How do I select how many pantients every doctor has? - sql

I have a table of Visits on the Hospital, included DoctorID, PacientID, Date....
I did like this but I recieved an error.
SELECT
d.DoctorID, COUNT(v.DoctorID)
FROM Visits v
left join Doctors d on v.DoctorID=d.DoctorID

You care missing the group by:
SELECT d.DoctorID, COUNT(v.DoctorID)
FROM Doctors d LEFT JOIN
Visits v
ON v.DoctorID = d.DoctorID
GROUP BY d.DoctorID;
In addition, you presumably want the LEFT JOIN starting with Doctors so you keep all doctors.

Your query is missing a GROUP BY clause. Also I do not see the need for a JOIN. If you want the count of (distinct) patientsIDs per doctorID, you can get that information directly from the visit table, like so:
select doctorID, count(distinct patientID) from visits group by doctorID
Or, if you also want to see doctors that have no patients:
select d.doctorID, count(distinct v.patientID)
from doctors d
left join visits v on v.doctorID = d.doctorID
group by d.doctorID

Live demo on db<>fiddle
You are missing GroupBy clause.
So you can fix it in this way
SELECT d.Name, COUNT(v.DoctorID) AS PantientCount
FROM Doctors d
LEFT JOIN Visits v ON d.DoctorId = v.DoctorId
GROUP BY d.Name
You can also using Conditional aggregation query with a group by like below.
SELECT d.Name, SUM(CASE WHEN v.CustomerId IS NOT NULL THEN 1 ELSE 0 END) AS PantientCount
FROM Doctors d
LEFT JOIN Visits v ON d.DoctorId = v.DoctorId
GROUP BY d.Name
Output

Related

Count and group the number of times each town is listed in the table

SELECT PEOPLE.TOWNKEY, TOWN_LOOKUP.TOWN FROM PEOPLE
INNER JOIN TOWN_LOOKUP
ON PEOPLE.TOWNKEY = TOWN_LOOKUP.PK
ORDER BY TOWN
Current Table Output:
You are missing the group by clause entirely:
SELECT tl.town, COUNT(*)
FROM people p
INNER JOIN town_lookup ON p.townkey = tl.pk
GROUP BY tl.town
ORDER BY tl.town

SQL Server Circular Query

I have 4 tables, in that I want to fetch records from all 4 and aggregate the values
I have these tables
I am expecting this output
but getting this output as a Cartesian product
It is multiplying the expenses and allocation
Here is my query
select
a.NAME, b.P_NAME,
sum(a.DURATION) DURATION,
sum(b.[EXP]) EXPEN
from
(select
e.ID, a.P_ID, e.NAME, a.DURATION DURATION
from
EMPLOYEE e
inner join
ALLOCATION a ON e.ID = a.E_ID) a
inner join
(select
p.P_ID, e.E_ID, p.P_NAME, e.amt [EXP]
from
PROJECT p
inner join
EXPENSES e ON p.P_ID = e.P_ID) b ON a.ID = b.E_ID
and a.P_ID = b.P_ID
group by
a.NAME, b.P_NAME
Can anyone suggest something about this.
The following should work:
SELECT e.Name,p.Name,COALESCE(d.Duration,0),COALESCE(exp.Expen,0)
FROM
Employee e
CROSS JOIN
Project p
LEFT JOIN
(SELECT E_ID,P_ID,SUM(Duration) as Duration FROM Allocation
GROUP BY E_ID,P_ID) d
ON
e.E_ID = d.E_ID and
p.P_ID = d.P_ID
LEFT JOIN
(SELECT E_ID,P_ID,SUM(AMT) as Expen FROM Expenses
GROUP BY E_ID,P_ID) exp
ON
e.E_ID = exp.E_ID and
p.P_ID = exp.P_ID
WHERE
d.E_ID is not null or
exp.E_ID is not null
I've tried to write a query that will produce results where e.g. there are rows in Expenses but no rows in Allocations (or vice versa) for some particular E_ID,P_ID combination.
Use left join in select query by passing common id for all table
Hi I got the answer what I want from some modification in the query
The above query is also working like a charm and have done some modification to the original query and got the answer
Just have to group by the inner queries and then join the queries it will then not showing Cartesian product
Here is the updated one
select a.NAME,b.P_NAME,sum(a.DURATION) DURATION,sum(b.[EXP]) EXPEN from
(select e.ID,a.P_ID, e.NAME,sum(a.DURATION) DURATION from EMPLOYEE e inner join ALLOCATION a
ON e.ID=a.E_ID group by e.ID,e.NAME,a.P_ID) a
inner join
(select p.P_ID,e.E_ID, p.P_NAME,sum(e.amt) [EXP] from PROJECT p inner join EXPENSES e
ON p.P_ID=e.P_ID group by p.P_ID,p.P_NAME,e.E_ID) b
ON a.ID=b.e_ID and a.P_ID=b.P_ID group by a.NAME,b.P_NAME
Showing the correct output

SQL Joins Clarification

I wish to display the hospitalid,hosp name and hosp type for the hospital which have/has the highest no of doctors associated with them.
I have two tables:
Doctor: doctorid, hospitalid
Hospital: hospitalid, hname, htype
SELECT d.hospitalid,h.hname,h.htype
FROM doctor d
INNER JOIN hospital h ON d.hospitalid = h.hospitalid
GROUP BY d.hospitalid,h.hname,h.htype
HAVING MAX(count(d.doctorid));
I tried the above code, but i get an error "group func is nested too deeply". How should i modify d code?
This is a common error when learning SQL, thinking that having Max(col) says "keep only the row with the max". It simply means having <some function on the column> without any condition. For instance, you could say having count(d.doctorid) = 1 to get hospitals with only one doctor.
The way to do this is to order the columns and then take the first row. However, the syntax for "take the first row" varies by database. The following works in many SQL dialects:
SELECT d.hospitalid,h.hname,h.htype
FROM doctor d INNER JOIN
hospital h
ON d.hospitalid = h.hospitalid
GROUP BY d.hospitalid,h.hname,h.htype
order by count(d.doctorid) desc
limit 1;
In SQL Server and Sybase, the syntax is:
SELECT top 1 d.hospitalid,h.hname,h.htype
FROM doctor d INNER JOIN
hospital h
ON d.hospitalid = h.hospitalid
GROUP BY d.hospitalid,h.hname,h.htype
order by count(d.doctorid) desc;
In Oracle:
select t.*
from (SELECT d.hospitalid,h.hname,h.htype
FROM doctor d INNER JOIN
hospital h
ON d.hospitalid = h.hospitalid
GROUP BY d.hospitalid,h.hname,h.htype
order by count(d.doctorid) desc
) t
where rownum = 1;
EDIT (based on comment):
To get all rows with the maximum, then you can do something similar to your original query. It is just more complicated. You can calculate the maximum number using a subquery and do the comparison in the having clause:
SELECT d.hospitalid, h.hname, h.htype
FROM doctor d INNER JOIN
hospital h
ON d.hospitalid = h.hospitalid join
GROUP BY d.hospitalid,h.hname,h.htype
having count(d.doctorid) = (select max(NumDoctors)
from (select hospitalid, count(*) as NumDoctors
from hospitalId
group by hospitalid
) hd
)
As a note, there are easier mechanisms in other databases.
This is how I would write it for SQL Server. THe specific details might vary depending teh database backend you are using.
SELECT TOP 1 a.hospitalid,a.hname,a.htype
FROM
(SELECT d.hospitalid,h.hname,h.htype, count(d.doctorid) as doctorcount FROM doctor d INNER JOIN hospital h ON d.hospitalid = h.hospitalid
GROUP BY d.hospitalid,h.hname,h.htype) a
ORDER BY doctorcount DESC;

Query extensibility with WHERE EXISTS with a large table

The following query is designed to find the number of people who went to a hospital, the total number of people who went to a hospital and the divide those two to find a percentage. The table Claims is two million plus rows and does have the correct non-clustered index of patientid, admissiondate, and dischargdate. The query runs quickly enough but I'm interested in how I could make it more usable. I would like to be able to add another code in the line where (hcpcs.hcpcs ='97001') and have the change in percentRehabNotHomeHealth be relfected in another column. Is there possible without writing a big, fat join statement where I join the results of the two queries together? I know that by adding the extra column the math won't look right, but I'm not worried about that at the moment. desired sample output: http://imgur.com/BCLrd
database schema
select h.hospitalname
,count(*) as visitCounts
,hospitalcounts
,round(count(*)/cast(hospitalcounts as float) *100,2) as percentRehabNotHomeHealth
from Patient p
inner join statecounties as sc on sc.countycode = p.countycode
and sc.statecode = p.statecode
inner join hospitals as h on h.npi=p.hospitalnpi
inner join
--this join adds the hospitalCounts column
(
select h.hospitalname, count(*) as hospitalCounts
from hospitals as h
inner join patient as p on p.hospitalnpi=h.npi
where p.statecode='21' and h.statecode='21'
group by h.hospitalname
) as t on t.hospitalname=h.hospitalname
--this where exists clause gives the visitCounts column
where h.stateCode='21' and p.statecode='21'
and exists
(
select distinct p2.patientid
from Patient as p2
inner join Claims as c on c.patientid = p2.patientid
and c.admissiondate = p2.admissiondate
and c.dischargedate = p2.dischargedate
inner join hcpcs on hcpcs.hcpcs=c.hcpcs
inner join hospitals as h on h.npi=p2.hospitalnpi
where (hcpcs.hcpcs ='97001' or hcpcs.hcpcs='9339' or hcpcs.hcpcs='97002')
and p2.patientid=p.patientid
)
and hospitalcounts > 10
group by h.hospitalname, t.hospitalcounts
having count(*)>10
You might look into CTE (Common Table Expressions) to get what you need. It would allow you to get summarized data and join that back to the detail on a common key. As an example I modified your join on the subquery to be a CTE.
;with hospitalCounts as (
select h.hospitalname, count(*) as hospitalCounts
from hospitals as h
inner join patient as p on p.hospitalnpi=h.npi
where p.statecode='21' and h.statecode='21'
group by h.hospitalname
)
select h.hospitalname
,count(*) as visitCounts
,hospitalcounts
,round(count(*)/cast(hospitalcounts as float) *100,2) as percentRehabNotHomeHealth
from Patient p
inner join statecounties as sc on sc.countycode = p.countycode
and sc.statecode = p.statecode
inner join hospitals as h on h.npi=p.hospitalnpi
inner join hospitalCounts on t.hospitalname=h.hospitalname
--this where exists clause gives the visitCounts column
where h.stateCode='21' and p.statecode='21'
and exists
(
select p2.patientid
from Patient as p2
inner join Claims as c on c.patientid = p2.patientid
and c.admissiondate = p2.admissiondate
and c.dischargedate = p2.dischargedate
inner join hcpcs on hcpcs.hcpcs=c.hcpcs
inner join hospitals as h on h.npi=p2.hospitalnpi
where (hcpcs.hcpcs ='97001' or hcpcs.hcpcs='9339' or hcpcs.hcpcs='97002')
and p2.patientid=p.patientid
)
and hospitalcounts > 10
group by h.hospitalname, t.hospitalcounts
having count(*)>10

SQL Return only where more than one join

Not sure how to ask this as I'm a bit of a database noob,
What I want to do is the following.
table tb_Company
table tb_Division
I want to return companies that have more than one division and I don't know how to do the where clause.
SELECT dbo.tb_Company.CompanyID, dbo.tb_Company.CompanyName,
dbo.tb_Division.DivisionName FROM dbo.tb_Company INNER JOIN dbo.tb_Division ON
dbo.tb_Company.CompanyID = dbo.tb_Division.DivisionCompanyID
Any help or links much appreciated.
You'll need another JOIN where you only return companies having more than one division by using a GROUP BYand a HAVINGclause.
You can read up on grouping here
Groups a selected set of rows into a
set of summary rows by the values of
one or morecolumns or expressions. One
row is returned for each group.
Aggregate functions in the SELECT
clause list provide
information about each group instead
of individual rows.
SELECT dbo.tb_Company.CompanyID
, dbo.tb_Company.CompanyName
, dbo.tb_Division.DivisionName
FROM dbo.tb_Company
INNER JOIN dbo.tb_Division ON dbo.tb_Company.CompanyID = dbo.tb_Division.DivisionCompanyID
INNER JOIN (
SELECT DivisionCompanyID
FROM dbo.tb_Division
GROUP BY
DivisionCompanyID
HAVING COUNT(*) > 1
) d ON d.DivisionCompanyID = dbo.tb_Company.CompanyID
another alternative...
SELECT c.CompanyId, c.CompanyName, d.DivisionName
FROM tbl_Company c
INNER JOIN tbl_Division d ON c.CompanyId=d.DivisionCompanyId
GROUP BY c.CompanyId, c.CompanyName, d.DivisionName
HAVING COUNT(*) > 1
How about?
WITH COUNTED AS
(
SELECT C.CompanyID, C.CompanyName, D.DivisionName,
COUNT() OVER(PARTITION BY C.CompanyID) AS Cnt
FROM dbo.tb_Company C
INNER JOIN dbo.tb_Division D ON C.CompanyID = D.DivisionCompanyID
)
SELECT *
FROM COUNTED
WHERE Cnt > 1
With the other solutions (that join onto Division table twice), a single company/division can be returned under a heavy insert load.
If a row is inserted into the Division table between the time the first join occurs and the time the second join (with the group by/having) is evaluated, the first Division join will return a single row. However, the second one will return a count of 2.
How about...
SELECT dbo.tb_Company.CompanyID,
dbo.tb_Company.CompanyName,
FROM dbo.tb_Company
WHERE (SELECT COUNT(*)
FROM dbo.tb_Division
WHERE dbo.tb_Company.CompanyID =
dbo.tb_Division.DivisionCompanyID) > 1;