Count in SQL server - sql

select
hotel.hotel_name 'Hotel Name',
Address 'Address',
Description 'Description',
Contact_No 'Contact Number'
from hotel, customer_profile, booking_details where
customer_profile.email = booking_details.email
and hotel.hotel_name = booking_details.hotel_name
and booking_details.email = 'davidho#yahoo.com'
order by 1
I can't add images /:
So for example currently my result is
+-----------------------+
| Name | Address |
+-----------------------+
| Hotel1 | Beach Road1 |
| Hotel2 | Beach Road2 |
| Hotel2 | Beach Road2 |
+-----------------------+
I want it to remove the duplicates, and add a new column "Number of times" which indicate how many times it appeared.
I want it to be
+------------------------------------+
| Name | Address | No of Times |
+------------------------------------+
| Hotel1 | Beach Road1 | 1 |
| Hotel2 | Beach Road2 | 2 |
+------------------------------------+

You should use for your examples group by clause a below
select
hotel.hotel_name "Hotel Name",
Address, count(1) "No of Times"
from hotel, customer_profile, booking_details where
customer_profile.email = booking_details.email
and hotel.hotel_name = booking_details.hotel_name
and booking_details.email = 'davidho#yahoo.com'
group by hotel.hotel_name, Address
order by 1

First, learn proper join syntax, don't use single quote for column names, and use column aliases for all columns. Here is what I think your current query is doing.
select h.hotel_name as HotelName, h.Address. h.Description
cp.Contact_No
from booking_details bd join
hotel h
on h.hotel_name = bd.hotel_name join
customer_profile cp
on cp.email = bd.email
where bd.email = 'davidho#yahoo.com'
order by 1;
Next, to solve your question, just use group by. You can also eliminate the join to customer_profile, because I don't think that table gets used:
select h.hotel_name as HotelName, h.Address. count(*) as NumberOfTimes
from booking_details bd join
hotel h
on h.hotel_name = bd.hotel_name
where bd.email = 'davidho#yahoo.com'
order by 1;

Related

Join repeatedly until a string is present?

While querying a subset of our employees, I'm trying to add a field for the SVP they "roll up" to.
Employees may have anywhere from 1 to 5 or 6 degrees of separation from their SVP. The trouble is, we don't have any specific hierarchical indicator to reference. I have to do this by walking up through the employee's manager repeatedly, until some manager's manager has "SVP" in their title.
How could I write a query to do this?
From the opposite direction, I've found the employees of a specific SVP (named BM for the example) by saying, 'Employee's manager is BM, OR Employee's manager's manager is BM, OR Employee's manager's manager's manager is BM' and so on...
For my instance, I suspect I'd only use the same sys_user table over and over again, following the manager field each time until I reach a user with SVP in the title.
+--------+-------------------+-----------+--------+
| sys_id | name | title | manager|
+--------+-------------------+-----------+--------+
| 555789 | Tina Belcher | Contractor| 123456 |
| 123456 | Bob Belcher | Manager | 654321 |
| 654321 | Calvin Fischoeder | SVP | 997755 |
+--------+-------------------+-----------+--------+
SELECT su.Name
, su.Title
, dp.name
, mg.name
FROM sys_user su
LEFT JOIN cmn_department dp
ON dp.sys_id = su.department
LEFT JOIN sys_user mg
ON mg.sys_id = su.manager
WHERE su.Title like ('%contractor%')
I appreciate any helps or tip that can be offered. Thanks for looking and have a great day.
Your Sys_User table is an adjacency list that only provides information about employees and who they directly report to. Adjacency Lists are one way to to encode hierarchical data. They're nice because they're relatively fast and compact, however they aren't the only way to encode hierarchical relationships.
To answer the questions you are asking you will benefit from re-encoding the data into a Closure table which maps each employee to all of its direct and indirect managers/reportees along with their degree of separation, and any other additional pertinent info. However, since it represents a Many-to-Many relationship you don't want to over load it with too much additional data. Fortunately thanks to the utility of recursive queries you can create one fairly easily on the fly.
To create a closure table you start by populating it with the degree 0 relationships, where every employee is considered their own manager/reportee. The reasoning for it is a bit beyond my ken, but it has something to do with the mathematics behind the concept of transitive closure (hence the name closure table). After that you iteratively (recursively) add each additional reporting degree. You can either do that from the Top Down, or from the Bottom Up
Here's the Top Down version:
with closure(manager_id, report_id, degree, is_managing_SVP, is_reporting_svp) as (
select sys_id
, sys_id
, 0
, case when title like '%SVP%' then 1 else 0 end
, case when title like '%SVP%' then 1 else 0 end
from sys_user
union all
select cur.manager_id
, nxt.sys_id
, cur.degree+1
, cur.is_managing_SVP
, case when nxt.title like '%SVP%' then 1 else 0 end
from closure cur
join sys_user nxt
on nxt.manager = cur.report_id
and nxt.sys_id <> nxt.manager
)
select * from closure
And here's the Bottom Up version:
with closure(manager_id, report_id, degree, is_managing_SVP, is_reporting_svp) as (
select sys_id
, sys_id
, 0
, case when title like '%SVP%' then 1 else 0 end
, case when title like '%SVP%' then 1 else 0 end
from sys_user
union all
select nxt.manager
, cur.report_id
, cur.degree+1
, case when mgr.title like '%SVP%' then 1 else 0 end
, cur.is_reporting_SVP
from closure cur
join sys_user nxt
on nxt.sys_id = cur.manager_id
and nxt.sys_id <> nxt.manager
join sys_user mgr
on mgr.sys_id = nxt.manager
)
select * from closure
It doesn't matter too much which version you use if you are going to generate the entire closure table, however, if you want to optimize your query and only generate a partial closure table then it depends on if you want to walk up or down the tree.
Once generated you can use the closure table to answer your questions about SVPs such as who each contractor's SVP is:
select r.sys_id, r.name, r.title, c.degree
, c.manager_id SVP_ID
, m.name SVP_name
, m.title SVP_title
from sys_user r
join closure c
on c.report_id = r.sys_id
join sys_user m
on m.sys_id = c.manager_id
where r.title like '%contractor%'
and c.is_managing_svp = 1
sys_id | name | title | degree | SVP_ID | SVP_name | SVP_title
-----: | :----------- | :--------- | -----: | -----: | :---------------- | :--------
555789 | Tina Belcher | Contractor | 2 | 654321 | Calvin Fischoeder | SVP
Or every direct and indirect report to the SVP named Calvin Fischoeder:
select m.sys_id manager_id
, m.name
, m.title
, c.degree
, r.sys_id report_id
, r.name report_name
, r.title report_title
from sys_user m
join closure c
on c.manager_id = m.sys_id
join sys_user r
on r.sys_id = c.report_id
where m.name = 'Calvin Fischoeder'
order by degree, report_name
manager_id | name | title | degree | report_id | report_name | report_title
---------: | :---------------- | :---- | -----: | --------: | :---------------- | :-----------
654321 | Calvin Fischoeder | SVP | 0 | 654321 | Calvin Fischoeder | SVP
654321 | Calvin Fischoeder | SVP | 1 | 123456 | Bob Belcher | Manager
654321 | Calvin Fischoeder | SVP | 2 | 555789 | Tina Belcher | Contractor
To see all queries in action, check out this db<>fiddle
You are looking for a recursive CTE:
with cte as (
select su.sys_id, su.name, su.title, su.manager, 1 as lev, 0 as hit_svp
from sys_user su
where su.Title like '%contractor%'
union all
select su.sys_id, su.name, su.title, su.manager, lev + 1,
(case when su.title like '%SVP%' then 1 else 0 end) as hit_svp
from sys_user su join
cte
on cte.manager = su.sys_id
where cte.hit_svp = 0
)
select . . . -- whatever columns you want
from cte; -- you may want additional joins here for other columns

Select and count in the same query on two tables

I've got these two tables:
___Subscriptions
|--------|--------------------|--------------|
| SUB_Id | SUB_HotelId | SUB_PlanName |
|--------|--------------------|--------------|
| 1 | cus_AjGG401e9a840D | Free |
|--------|--------------------|--------------|
___Rooms
|--------|-------------------|
| ROO_Id | ROO_HotelId |
|--------|-------------------|
| 1 |cus_AjGG401e9a840D |
| 2 |cus_AjGG401e9a840D |
| 3 |cus_AjGG401e9a840D |
| 4 |cus_AjGG401e9a840D |
|--------|-------------------|
I'd like to select the SUB_PlanName and count the rooms with the same HotelId.
So I tried:
SELECT COUNT(*) as 'ROO_Count', SUB_PlanName
FROM ___Rooms
JOIN ___Subscriptions
ON ___Subscriptions.SUB_HotelId = ___Rooms.ROO_HotelId
WHERE ROO_HotelId = 'cus_AjGG401e9a840D'
and
SELECT
SUB_PlanName,
(
SELECT Count(ROO_Id)
FROM ___Rooms
Where ___Rooms.ROO_HotelId = ___Subscriptions.SUB_HotelId
) as ROO_Count
FROM ___Subscriptions
WHERE SUB_HotelId = 'cus_AjGG401e9a840D'
But I get empty datas.
Could you please help ?
Thanks.
You need to use GROUP BY whenever you do some aggregation(here COUNT()). Below query will give you the number of ROO_ID only for the SUB_HotelId = 'cus_AjGG401e9a840D' because you have this condition in WHERE. If you want the COUNTs for all Hotel_IDs then you can simply remove the WHERE filter from this query.
SELECT s.SUB_PlanName, COUNT(*) as 'ROO_Count'
FROM ___Rooms r
JOIN ___Subscriptions s
ON s.SUB_HotelId = r.ROO_HotelId
WHERE r.ROO_HotelId = 'cus_AjGG401e9a840D'
GROUP BY s.SUB_PlanName;
To be safe, you can also use COUNT(DISTINCT r.ROO_Id) if you don't want to double count a repeating ROO_Id. But your table structures seem to have unique(non-repeating) ROO_Ids so using a COUNT(*) should work as well.

SQL Retrieve data with more than 1 record

I was encountered with a "not a GROUP BY expression"error.
I would need to search for similar title, medium and description.
Artist table consist of artistid, artist last name and artist first name.
work table consist of workid, title, medium, description, artistid
artistid are unique key.
List the details of any works of art that have more than one copy recorded in the database.
SELECT W.workid, W.title, W.medium, W.description, W.artistid, A.FirstName, A.LastName
FROM dtoohey.work W, dtoohey.artist A
GROUP BY W.artistid, A.FirstName, A.LastName
having count(*) > 1;
Seems you don't have a proper join between the tables (i have suggest one .. you should do the correct one)
If you want the group by on W.artistIid (alias the count of the workid for each artist) you cannot have W.workid, W.title, W.medium in select
SELECT W.artistid, A.FirstName, A.LastName
FROM dtoohey.work W
INNER JOIN dtoohey.artist A ON A.artistid = W.artistid
GROUP BY W.artistid, A.FirstName, A.LastName
having count(*) > 1;
otherwise if you want check if the select return more that one rows for the column select you must add all column to the group by clause
SELECT W.workid, W.title, W.medium, W.description, W.artistid, A.FirstName, A.LastName
FROM dtoohey.work W
INNER JOIN dtoohey.artist A ON A.artistid = W.artistid
GROUP BY W.workid, W.title, W.medium, W.description, W.artistid, A.FirstName, A.LastName
having count(*) > 1;
Maybe writing an answer (that focuses on #mathguy's observation of the missing join specifity and the one, that the mix of SELECT columns versus GROUP BY/HAVING does not fit) is better in finding out what your problem is and giving ideas how to enhance the question ;-) ... next time I suggest to be more heavy on the question, so the world does not have to work so heavy on the answers.
I do not think this is a MySQL, Oracle, or what not database specific problem, but more a SQL beginners learning journey ... you may want to also look for join explanations here: "Difference between Inner Join & Full join"
Starting from the minimal subset of info given in question: 2 tables artist and work related presumable over a shared id (say artist_id).
One thing directly asking for trouble in databases like PostgreSQL or ParStream is selecting columns in group by queries neither being grouped by nor aggregated / filtered. But here we go:
Create tables:
$psql> CREATE TABLE artist(artist_id INT, given_name VARCHAR(42), family_name VARCHAR(99));
CREATE TABLE
$psql> CREATE TABLE work(work_id INT, artist_id INT, title VARCHAR(42));
CREATE TABLE
Insert some data:
$psql> INSERT INTO artist VALUES(1, 'John', 'Doe');
INSERT 0 1
$psql> INSERT INTO artist VALUES(2, 'Natalie', 'Noir');
INSERT 0 1
$psql> INSERT INTO work VALUES(43, 1, 'The game is on');
INSERT 0 1
$psql> INSERT INTO work VALUES(44, 1, 'The game is over');
INSERT 0 1
$psql> INSERT INTO work VALUES(98, 2, 'La nuit commonce');
INSERT 0 1
$psql> INSERT INTO work VALUES(97, 2, 'Un jour se lve');
INSERT 0 1
Check what is in it:
$psql> SELECT * FROM work;
work_id | artist_id | title
---------+-----------+------------------
43 | 1 | The game is on
44 | 1 | The game is over
98 | 2 | La nuit commonce
97 | 2 | Un jour se lve
(4 rows)
$psql> SELECT * FROM artist;
artist_id | given_name | family_name
-----------+------------+-------------
1 | John | Doe
2 | Natalie | Noir
(2 rows)
Show the implicit INNER JOIN:
$psql> SELECT * FROM work W, artist A;
work_id | artist_id | title | artist_id | given_name | family_name
---------+-----------+------------------+-----------+------------+-------------
43 | 1 | The game is on | 1 | John | Doe
43 | 1 | The game is on | 2 | Natalie | Noir
44 | 1 | The game is over | 1 | John | Doe
44 | 1 | The game is over | 2 | Natalie | Noir
98 | 2 | La nuit commonce | 1 | John | Doe
98 | 2 | La nuit commonce | 2 | Natalie | Noir
97 | 2 | Un jour se lve | 1 | John | Doe
97 | 2 | Un jour se lve | 2 | Natalie | Noir
(8 rows)
Show the explicit INNER JOIN with a dummy condition to let the parser pass our query (Update: Don't use this at home, only to show the mish-mash.):
$psql> SELECT * FROM work W INNER JOIN artist A ON 1 = 1;
work_id | artist_id | title | artist_id | given_name | family_name
---------+-----------+------------------+-----------+------------+-------------
43 | 1 | The game is on | 1 | John | Doe
43 | 1 | The game is on | 2 | Natalie | Noir
44 | 1 | The game is over | 1 | John | Doe
44 | 1 | The game is over | 2 | Natalie | Noir
98 | 2 | La nuit commonce | 1 | John | Doe
98 | 2 | La nuit commonce | 2 | Natalie | Noir
97 | 2 | Un jour se lve | 1 | John | Doe
97 | 2 | Un jour se lve | 2 | Natalie | Noir
(8 rows)
Now a more useful INNER JOIN matching only these entries from the two tables, that are related through "creator" relationship:
$psql> SELECT * FROM work W INNER JOIN artist A ON W.artist_id = A.artist_id;
work_id | artist_id | title | artist_id | given_name | family_name
---------+-----------+------------------+-----------+------------+-------------
43 | 1 | The game is on | 1 | John | Doe
44 | 1 | The game is over | 1 | John | Doe
98 | 2 | La nuit commonce | 2 | Natalie | Noir
97 | 2 | Un jour se lve | 2 | Natalie | Noir
(4 rows)
So above we blindly trust the data managing part to magically enter artist_id values always correctly and matching our expectations (in real life a REFERENCES foreign key constraint would surely placed on the column in the work table (no work without an artist/creator would dictate the artist table to be the "first" causally).
Above you also see that selecting from a list of tables is identical to an INNER JOIN without any constraint i.e. the cartesian product of all entries from table work with all all entries from table artist.
Now your query (edited a tad for the minimal table model) besides not clear to me in its request idea, errors out as explained on top of this answer text:
$psql> SELECT W.work_id, W.title, W.artist_id, A.given_name, A.family_name FROM work W, artist A GROUP BY W.artist_id, A.given_name, A.family_name HAVING COUNT(*) > 1;
ERROR: column "w.work_id" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT W.work_id, W.title, W.artist_id, A.given_name, A.fam...
This is of course not cured by using a more meaningful joined input set (claro, as the error points to the mismatch in select and group by lists:
$psql> SELECT W.work_id, W.title, W.artist_id, A.given_name, A.family_name FROM work W INNER JOIN artist A ON W.artist_id = A.artist_id GROUP BY W.artist_id, A.given_name, A.family_name HAVING COUNT(*) > 1;
ERROR: column "w.work_id" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT W.work_id, W.title, W.artist_id, A.given_name, A.fam...
You need suggest input on what you want to achieve to obtain a single answer (working). Until you do so, here are some offerings:
Given that you join on only existing pairs of artis and work ids, you do not need that having clause, as neither non-existing artist nor missing works nor missing combinations of artists and works will ever enter the rowset your query works on, so:
$psql> SELECT title, R.* FROM ( SELECT W.work_id AS work_id_filtered, W.artist_id, A.given_name, A.family_name FROM work W INNER JOIN artist A ON W.artist_id = A.artist_id GROUP BY W.work_id, W.artist_id, A.given_name, A.family_name) R INNER JOIN work WW ON WW.work_id = R.work_id_filtered;
title | work_id_filtered | artist_id | given_name | family_name
------------------+------------------+-----------+------------+-------------
The game is on | 43 | 1 | John | Doe
The game is over | 44 | 1 | John | Doe
La nuit commonce | 98 | 2 | Natalie | Noir
Un jour se lve | 97 | 2 | Natalie | Noir
(4 rows)
This should give you a bit clumsy but good enough for my sunday morning the nice list of all titles (non-grouped files) combined with the grouped fields from the inner query. Formatted query might be written as:
SELECT title,
R.*
FROM
(SELECT W.work_id AS work_id_filtered,
W.artist_id,
A.given_name,
A.family_name
FROM
work W
INNER JOIN artist A ON W.artist_id = A.artist_id
GROUP BY W.work_id,
W.artist_id,
A.given_name,
A.family_name) R
INNER JOIN
work WW ON WW.work_id = R.work_id_filtered;
Removing any GROUP BY (until the question offers detail on why it would be needed for the task):
$psql> SELECT W.work_id, W.title, W.artist_id, A.given_name, A.family_name FROM work W INNER JOIN artist A ON W.artist_id = A.artist_id;
work_id | title | artist_id | given_name | family_name
---------+------------------+-----------+------------+-------------
43 | The game is on | 1 | John | Doe
44 | The game is over | 1 | John | Doe
98 | La nuit commonce | 2 | Natalie | Noir
97 | Un jour se lve | 2 | Natalie | Noir
(4 rows)
Query formatted to not have to scroll horizontally:
SELECT W.work_id, W.title, W.artist_id, A.given_name, A.family_name
FROM work W INNER JOIN artist A ON W.artist_id = A.artist_id;
Note: Yes, as #ThorstenKettner pointed rightfully out, I made up the term "FULL INNER JOIN", I smoetimes do, sorry. Maybe my brain needs cartesian filling to balance the LEFT|RIGHT|FULL OUTER JOINs - who knows ;-)
I used scaisEdge answer and edited. What I realize was if I select workid(unique key), I won't be able to display anything but without it, all my field is up.
As has been mentioned, the problem is mainly that you don't yet fully understand what you are doing.
First point is your join. By merely separating the tables with commas, you are using a syntax that was made redundant more than twenty years ago. It seems rare that you, as a beginner, use this. You must have found this in a very old book or tutorial. In short: Don't join tables like this. Use explicit joins. A comma means CROSS JOIN. So what you have is:
FROM dtoohey.work W CROSS JOIN dtoohey.artist A
That means that you combine every artist with every work. This is most likely not what you want. You want to join related artists and works. Your query shows there is an artistid in your work table, so one work is made by one artist in your model. The appropriate join would hence be:
FROM dtoohey.work w
INNER JOIN dtoohey.artist a ON a.artistid = w.artistid
The second point is that you are aggregating rows. GROUP BY W.artistid, A.FirstName, A.LastName tells the DBMS to aggregate the rows such that you get one result row per artist. With having count(*) > 1 you say you only want artists with more than one work. But in your select clause you are showing a work (W.workid, W.title, W.medium, W.description). Which one? If you only show one row per artist and each artist has more than one work, which work of an artist do you show? The DBMS notices that you forgot to tell it what to select and raises an error. And you will probably agree now that the query with the given GROUP BY and HAVING clauses makes no sense.

SQL advanced compare of strings

I am working on getting some very specific information out of a MSSQL database. All the information I need is available via this SQL command:
SELECT
receivedate,
swp.firmwarelevel AS 'Firmwarelevel',
pa.description AS 'Description'
FROM tbl_swapgroup_parts swp, tbl_parts pa, tbl_part_type pt, tbl_swapgroups sw, tbl_workorders wo
WHERE custom7 = 'somemodel'
AND swp.swapgroup_id IN (18,25)
AND sw.id = swp.swapgroup_id
AND pa.id = swp.part_id
AND pt.id = pa.parttype_id
AND wo.part_id = pa.id'
Now this returns a list which looks something like this, trimmed to just 4 entries for sanity...
+---------------------+---------------+--------------------------------------------------+
| receivedate | Firmwarelevel | Description |
+---------------------+---------------+--------------------------------------------------+
| 2013-08-29 12:10:28 | YN07 | Description 1... |
| 2013-08-29 12:10:28 | YN07 | Description 2... |
| 2014-01-13 13:12:55 | YN07 | Description 1... |
| 2014-01-13 13:12:55 | YN07 | Description 2... |
+---------------------+---------------+--------------------------------------------------+
So what I want is really only 1 entry for each Unique description string, and the unique entry has to be the one with the newest recievedate.
Is such an 'advanced' thing possible only in SQL or do I have to post-process with some other language like python?
If at all possible I`d like to do it in pure SQL...
Yes, you can do this in SQL. For example, with row_number():
SELECT * FROM (
SELECT
receivedate,
swp.firmwarelevel AS 'Firmwarelevel',
pa.description AS 'Description',
row_number() over (partition by Description order by receivedate desc) rn
FROM tbl_swapgroup_parts swp,
tbl_parts pa,
tbl_part_type pt,
tbl_swapgroups sw,
tbl_workorders wo
WHERE custom7 = 'somemodel'
AND swp.swapgroup_id IN (18,25)
AND sw.id = swp.swapgroup_id
AND pa.id = swp.part_id
AND pt.id = pa.parttype_id
AND wo.part_id = pa.id
) x
where x.rn=1
Also, ANSI JOIN syntax came out in 1992 - please use it :)

Multiple select or distinct

I am new to sql so looking for a little help - got the first part down however I am having issues with the second part.
I got the three tables tied together. First I needed to tie tblPatient.ID = tblPatientVisit.PatientID together to eliminate dups which works
Now I need to take those results and eliminate dups in the MRN but my query is only returning one result which is WRONG - LOL
Query
select
tblPatient.id,
tblPatient.firstname,
tblPatient.lastname,
tblPatient.dob,
tblPatient.mrn,
tblPatientSmokingScreenOrder.SmokeStatus,
tblPatientVisit.VisitNo
from
tblPatient,
tblPatientSmokingScreenOrder,
tblPatientVisit
Where
tblPatient.ID = tblPatientVisit.PatientID
and tblPatientVisit.ID = tblPatientSmokingScreenOrder.VisitID
and tblPatient.ID in(
Select Distinct
tblPatient.mrn
From
tblPatient
where
isdate(DOB) = 1
and Convert(date,DOB) <'12/10/2000'
and tblPatientVisit.PatientType = 'I')
Actual Results:
ID | firstName | LastName | DOB | MRN | SmokeStatus | VisitNO
12 | Test Guy | Today | 12/12/1023 | 0015396 | Never Smoker | 0013957431
Desired Results:
90 | BOB | BUILDER | 02/24/1974 | 0015476 | Former Smoker | 0015476001
77 | DORA | EXPLORER | 06/04/1929 | 0015463 | Never Smoker | 0015463001
76 | MELODY | VALENTINE | 09/17/1954 | 0015461 | Current | 0015461001
32 | STRAWBERRY | SHORTCAKE | 07/06/1945 | 0015415 | Current | 0015415001
32 | STRAWBERRY | SHORTCAKE | 07/06/1945 | 0015415 | Never Smoker | 0015415001
32 | STRAWBERRY | SHORTCAKE | 07/06/1945 | 0015415 | Former Smoker | 0015415001
12 | Test Guy | Today | 12/12/1023 | 0015345 | Never Smoker | 0013957431
Anyone have any suggestions on how I go down to the next level and get all the rows with one unique MRN. From the data above I should have 5 in my list. Any help would be appreciated.
Thanks
If I had to guess -- The only thing that looks odd (but maybe it's OK) is that you're comparing patient.ID from your parent query to patient.mrn in the subquery.
Beyond that -- things to check:
(1)
Do you get all your patients with the inner query?
Select Distinct
tblPatient.mrn
From
tblPatient
where
isdate(DOB) = 1
and Convert(date,DOB) <'12/10/2000'
and tblPatientVisit.PatientType = 'I'
(2)
What is your patient type for the missing records? (Your filtering it to tblPatientVisit.PatientType = 'I' -- do the missing records have that patient type as well?)
Perhaps you need to invert the logic here. As in,
Select Distinct
patients.mrn1
From (select
tblPatient.id as id1,
tblPatient.firstname as firstname1,
tblPatient.lastname as lastname1,
tblPatient.dob as DOB1,
tblPatient.mrn as mrn1,
tblPatientSmokingScreenOrder.SmokeStatus as SmokeStatus1,
tblPatientVisit.VisitNo as VisitNo1,
tblPatientVisit.PatientType as PatientType1,
from
tblPatient,
tblPatientSmokingScreenOrder,
tblPatientVisit
Where
tblPatient.ID = tblPatientVisit.PatientID
and tblPatientVisit.ID = tblPatientSmokingScreenOrder.VisitID
) as patients
where
isdate(patients.DOB1) = 1
and Convert(date,patients.DOB1) <'12/10/2000'
and patients.PatientType1 = 'I');
Cleaned it up a bit and I think they were right. MRN wont match patient id, at least not from your example data. You should not need an inner query. This query should give you what you want.
SELECT DISTINCT
p.id,
p.firstname,
p.lastname,
p.dob,
p.mrn,
s.SmokeStatus,
v.VisitNo
FROM
tblPatient p
JOIN tblPatientVisit v ON p.id = v.patientId
JOIN tblPatientSmokingScreenOrder s ON v.id = s.visitId
WHERE
isdate(p.DOB) = 1
AND CONVERT(date,p.DOB) <'12/10/2000'
AND v.PatientType = 'I'