Got a error message when I try to find out which patient account have duplicated record. - sql

When I run the script below, I got a error message "Cannot perform an aggregate function on an expression containing an aggregate or a subquery" Please provide some advice. Thanks
SELECT
CONVERT(DECIMAL(18,5),SUM(CASE WHEN PATIENT_ACCOUNT_NO IN (
SELECT PATIENT_ACCOUNT_NO
FROM STND_ENCOUNTER
GROUP BY PATIENT_ACCOUNT_NO
HAVING ( COUNT(PATIENT_ACCOUNT_NO) > 1)) THEN 0 ELSE 1 END)) dupPatNo
FROM [DBO].[STND_ENCOUNTER]

I think the error message is pretty clear. You have a sum() function with a subquery in it (albeit within a case, but that doesn't matter).
It seems that you want to choose patients that have more than one encounter, then add 0 if the patients is in the list and 1 if the patient is not. Hmmm. . . sounds like you want to count the number of patients with only one encounter.
Try using this logic instead:
select count(*)
from (select se.*, count(*) over (partition by PATIENT_ACCOUNT_NO) as NumEncounters
from dbo.stnd_encounter se
) se
where NumEncounters = 1;
As a note, the variable you are assigning is called DupPatientNo. This sounds like the number of patients that have duplicates. In that case, the query is:
select count(distinct PATIENT_ACCOUNT_NO)
from (select se.*, count(*) over (partition by PATIENT_ACCOUNT_NO) as NumEncounters
from dbo.stnd_encounter se
) se
where NumEncounters > 1;
(Or use count(*) if you want the number of encounters on duplicate patients.)

If you want to find number of PATIENT_ACCOUNT_NO that does not have any duplicates then use the following
SELECT COUNT(DISTINCT dupPatNo.PATIENT_ACCOUNT_NO)
FROM (
SELECT PATIENT_ACCOUNT_NO
FROM STND_ENCOUNTER
GROUP BY PATIENT_ACCOUNT_NO
HAVING COUNT(PATIENT_ACCOUNT_NO) = 1
) dupPatNo
If you want to find number of PATIENT_ACCOUNT_NO that have atleast one duplicate then use the following
SELECT COUNT(DISTINCT dupPatNo.PATIENT_ACCOUNT_NO)
FROM (
SELECT PATIENT_ACCOUNT_NO
FROM STND_ENCOUNTER
GROUP BY PATIENT_ACCOUNT_NO
HAVING COUNT(PATIENT_ACCOUNT_NO) > 1
) dupPatNo
Use of DISTINCT will make the query not count same item again and again
Though your query looks for first result, its not clear what you want. Hence giving query for both

Related

1407. Top Travellers ending in runtime error

I attempted the 1407. Top Travellers. But am struggling with my Oracle query below, 'Runtime error'. A little too tired to understand why. Any idea where I am going wrong? Have been rusty with SQL of late. :(
select name as name,
case when rides.distance is null then 0 else sum(rides.distance) end as travelled_distance
from users
left join rides
on users.id = rides.user_id
group by rides.users_id
order by travelled_distance desc, name;
As commented, is another way round:
select
name,
sum(case when rides.distance is null then 0 else rides.distance end) as travelled_distance
from users left join rides on users.id = rides.user_id
group by name
order by travelled_distance desc, name;
Or, simpler, use the nvl function:
select
name,
sum(nvl(rides.distance, 0)) as travelled_distance
from ...
Though, a few more objections:
you should use table aliases (as they simplify query and improve readability)
moreover, you should precede all column names with table aliases; in your case, you failed to do so for the name column. It probably belongs to the users table, but we can't tell for sure as we don't have your data model nor access to your database
group by clause should contain column(s) that aren't aggregated. In your query, that's the name column. You can put rides.users_id into that clause, but you must put name in there
The below solution works. Thanks to one of the Discussion posts at leetcode I could figure out the issue:
select r.name,
case when x.td is null
then 0
else x.td
end travelled_distance
from Users r
left join
(
select user_id, sum(distance) td
from Rides
group by user_id
) x
on r.id = x.user_id
order by travelled_distance desc, r.name;

AnalysisException: subqueries are not supported in the select list

I get this error code shown in title when using this following query. I'm trying query two tables to find total patients with hearing issues and the total of those patients with hearing issues who have undergone some sort of scan (MR,SC,CT).
SELECT (
SELECT COUNT(*)
FROM hearing_evaluation
where severity_of_hearing_loss <> 'Normal'
AND severity_of_hearing_loss <> 'insufficient data'
) AS patients_with_hearing_loss
, AVG(number_of_scans) AS avg_number_of_scans
FROM (
SELECT patient_id, COUNT(*) AS number_of_scans
from imaging
where patient_id IN (
SELECT patient_id
from hearing_evaluation
where severity_of_hearing_loss <> 'Normal'
and severity_of_hearing_loss <> 'insufficient data'
)
AND modality IN ('CT','MR','SC')
GROUP BY patient_id
) AS scans
Any help would be appreciated.
I tried, pls refer to below SQL - this will work in impala. Only issue i can see is, if hearing_evaluation has multiple patient ids for a given patient id, you need to de-duplicate the data.
There can be case when patient id doesnt exist in image table - in such case you need to apply RIGHT JOIN.
SELECT
COUNT(patient_id) AS patients_with_hearing_loss
, AVG(rs.number_of_scans) AS avg_number_of_scans
FROM (
SELECT i.patient_id patient_id, COUNT(*) AS number_of_scans
from imaging i ,hearing_evaluation h
where i. patient_id = h.patient_id
and h.severity_of_hearing_loss <> 'Normal'
and h.severity_of_hearing_loss <> 'insufficient data'
AND modality IN ('CT','MR','SC')
GROUP BY i.patient_id ) rs

Sql query using count(*) , groupby and fetching a column value simultaneously

I am been developing application in java and not much insight into sql.
Meanwhile , I have got to fetch count and username in the same query. My query goes like this :
SELECT count(*),c_user_name
FROM tra_shipment_status
WHERE i_tra_shipment_status_id IN
(SELECT MAX(i_tra_shipment_status_id)
FROM tra_shipment_status
WHERE i_status_code = '4072'
AND c_reference IN ('FILEIO0023','MIASTOFIL003')
Group By C_Reference
);
This throws me an exception "not a single-group group function"
I want the count and C_user_name of the top most row (latest one).
Can somebody please help.
If you use count(*) in the main query you also need a group by there:
SELECT count(*),c_user_name
FROM tra_shipment_status
WHERE i_tra_shipment_status_id IN
(SELECT MAX(i_tra_shipment_status_id)
FROM tra_shipment_status
WHERE i_status_code = '4072'
AND c_reference IN ('FILEIO0023','MIASTOFIL003')
Group By C_Reference
)
Group by c_user_name
When you try to include an aggregate function like count, sum, max,.. you should use group by with other unaggregated columns like c_user_name in your case. There is another thing; you say that you need the top most row but your sub query will return the top most row for each C_Reference, and to get the top most row regardless of C_Reference you should do something like the following:
SELECT count(*),c_user_name
FROM tra_shipment_status
WHERE i_tra_shipment_status_id IN
(SELECT MAX(i_tra_shipment_status_id)
FROM tra_shipment_status
WHERE i_status_code = '4072'
AND c_reference IN ('FILEIO0023','MIASTOFIL003')
);
Group By c_user_name

SQL query count divided by a distinct count of same query

Having some trouble with some SQL.
Take the following result for instance:
LOC_CODE CHANNEL
------------ --------------------
3ATEST-01 CHAN2
3ATEST-01 CHAN3
3ATEST-02 CHAN4
What I need to do is get a count of the above query, grouped by channel, but i want that count to be divided by the count that the "LOC_CODE" appears.
Example of the result I am after is:
CHANNEL COUNT
---------------- ----------
CHAN2 0.5
CHAN3 0.5
CHAN4 1
Above explaination is that the CHAN2 appears next to "3ATEST-01", but that LOC_CODE of "3ATEST-01" appears twice, so the count should be divided by 2.
I know I can do this by basically duplicating the query with a distinct count, but the underlying query is quite complex and don't really want to harm performance.
Please let me know if you would like more information!
Try:
select channel,
count(*) over (partition by channel, loc_code)
/ count(*) over (partition by loc_code) as count_ratio
from my_table
SELECT t.CHANNEL, COUNT(*) / gr.TotalCount
FROM my_table t JOIN (
SELECT LOC_CODE, COUNT(*) TotalCount
FROM my_table
GROUP BY LOC_CODE
) gr USING(LOC_CODE)
GROUP BY t.LOC_CODE, t.CHANNEL
Create a index on (LOC_CODE, CHANNEL)
If are no duplicate channels, replace COUNT(*) / gr.TotalCount with 1 / gr.TotalCount and remove the GROUP BY clause
First, find a query that gets you the correct results. Then, see if it can be optimised. My guess is that it's hard to optimise as you require two different groupings, one per Channel and one pre Loc_Code.
I'm not even sure that this fits your description:
SELECT t.CHANNEL
, COUNT(*) / SUM(grp.TotalCount)
FROM my_table t
JOIN
( SELECT LOC_CODE
, COUNT(*) TotalCount --- or is it perhaps?:
--- COUNT(DISTINCT CHANNEL)
FROM my_table
GROUP BY LOC_CODE
) grp
ON grp.LOC_CODE = t.LOC_CODE
GROUP BY t.CHANNEL
Your requirements are still a bit unclear to me when it comes to duplicate CHANNELs, but this should work if you want grouping on both CHANNEL and LOC_CODE to sum up later;
SELECT L1.CHANNEL, 1/COUNT(L2.LOC_CODE)
FROM Locations L1
LEFT JOIN Locations L2 ON L1.LOC_CODE = L2.LOC_CODE
GROUP BY L1.CHANNEL, L1.LOC_CODE
Demo here.

Switch case in aggregate query

I want to have a switch case in my SQL query such that when the group by does not group any element i dont want to aggregate otherwise I want to. Is that possible.
my query is something like this:
select count(1),AVG(student_mark) ,case when Count(1)=1 then student_subjectid else null end from Students
group by student_id
i get this error Column 'student_subjectid' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Thanks in advance..
SELECT
student_id,
COUNT(*) AS MarkCount,
AVG(student_mark) AS student_mark,
CASE COUNT(*) WHEN 1 THEN MIN(student_subjectid) END AS student_subjectid
FROM Students
GROUP BY student_id
Why in the world would you complicate it?
select count(1), AVG(Student_mark) Student_mark
from Students
group by student_id
If there is only one student_mark, it is also the SUM, AVG, MIN and MAX - so just continue to use the aggregate!
EDIT
The dataset that would eventuate with your requirement will not normally make sense. The way to achieve that would be to merge (union) two different results
select
numRecords,
Student_mark,
case when numRecords = 1 then student_subjectid end # else is implicitly NULL
from
(
select
count(1) AS numRecords,
AVG(Student_mark) Student_mark,
min(student_subjectid) as student_subjectid
from Students
group by student_id
) x