grouping and aggregates with subqueries - sql

I have a query that is designed to find the number of people who went to a hospital more than once. What I have works, but is there a way to do it without the subquery?
SELECT count(*) as counts, hospitals.hospitalname
FROM Patient INNER JOIN
hospitals ON Patient.hospitalnpi = hospitals.npi
WHERE (hospitals.hospitalname = 'X')
group by patientid, hospitalname
having count(patient.patientid) >1
order by count(*) desc
This will always return the number of correct rows (30), but not the number 30. If I remove the group by patientid then I get the entire result set returned.
I solved this problem by doing
select COUNT(*),hospitalname
from
(
SELECT count(*) as counts,hospitals.hospitalname
FROM hospitals INNER JOIN
Patient ON hospitals.npi = Patient.hospitalnpi
group by patientid, hospitals.hospitalname
having count(patient.patientid) >1
) t
group by t.hospitalname
order by t.hospitalname desc
I feel that there has to be a more elegant solution than using subqueries all the time. How could this be improved?
sample data from first query
row # revisits
1 2
2 2
3 2
4 2
same data from second, working query
row# hosp. name revisitAggregate
1 x 30
2 y 15
3 z 5
Simple one-to-many relationship between patient and hospitals

It's super hacky, but here you are:
SELECT TOP 1
ROW_NUMBER() OVER (order by patient.patientid) as Count
FROM
Patient
INNER JOIN hospitals
ON Patient.hospitalnpi = hospitals.npi
WHERE
(hospitals.hospitalname = 'X')
GROUP BY
patientid,
hospitalname
HAVING
count(patient.patientid) >1
ORDER BY
Count desc

select distinct hospitalname, count(*) over (partition by hospitalname) from (
SELECT hospitalname, count(*) over (partition by patientid,
hospitals.hospitalname) as counter
FROM hospitals INNER JOIN
Patient ON hospitals.npi = Patient.hospitalnpi
WHERE (hospitals.hospitalname = 'X')
) Z
where counter > 1

Related

Count consecutive ocurrences SQL - PostgreSQL

I am trying to count the number of consecutive weeks an employee went to work. So I have this table that has whether jon or andy went to work on certain weeks (I have all week of the year).
I am trying on Postgresql
What I would like know the number of times each person went consecutively to work x number of weeks.
So the way the below is read is that Andy went twice two consecutive weeks.
I feel like I am close. On python I could use a for loop probably, but on Postgresql I am a bit lost.
Thanks!
We group each amount of consecutive weeks worked per person and then group by the result and the person.
select person
,consecutive_weeks
,count(*)/consecutive_weeks as times
from (
select person
,sum(case when "went to work?" = 1 then 1 end) over(partition by person, grp) as consecutive_weeks
from (
select *
,count(mrk) over(partition by person order by week) as grp
from (
select *
,case when "went to work?" <> lag("went to work?") over(partition by person order by week) then 1 end as mrk
from t
) t
) t
) t
where consecutive_weeks is not null
group by person, consecutive_weeks
order by person
person
consecutive_weeks
times
andy
2
2
john
3
1
john
2
1
Fiddle
You can find groups of weeks where a person was present, assigning a running id to each row of the group, and then apply a count on the results, performing a group by on the id:
with cte as (
select t3.person, t3.k, count(*) c from
(select t.*, (select sum((t1.person = t.person and t1.week <= t.week and t1.at_work = 0)::int) k from tbl t1)
from tbl t) t3
where t3.at_work != 0 group by t3.person, t3.k
)
select c.person, c.c, count(*) c1 from cte c group by c.person, c.c order by c1
See fiddle.

Find duplicate ID's with different fields

I have a table that contain UserID's and Departments. UserID's can belong to several departments so their combo makes it unique.
However I have been trying to query trying to find where the UserID belongs to either one of two departments (hr or customer).
SELECT UserId, Dept, COUNT(*) Total
FROM MyTable
GROUP BY UserID
HAVING COUNT(*) = 1
However this still brings back duplicates if a UserId has both departments I guess because the combo makes it a unique record.
What I get back is this
UserID | Department | Total
1 hr 1
2 customer 1
3 customer 1
1 customer 1
3 hr 1
But what I am trying to get back is this
UserID | Department | Total
2 customer 1
Where any instances of UserId belonging to both departments are not included only if they belong to one or the other.
This should do the job
select t1.UserId, Dept, t2.Total
FROM MyTable t1
INNER JOIN
(
SELECT UserId, COUNT(*) Total
FROM Table1
GROUP BY UserID
HAVING COUNT(*) = 1
) t2 on t1.UserId = t2.UserId
try
SELECT UserId, COUNT(distinct Dept) Total
FROM MyTable
GROUP BY UserID
HAVING COUNT(distinct Dept) = 1
You can try something like this
select UserId, Dept
FROM Mytable where UserId in
(
SELECT UserId, COUNT(*) Total
FROM MyTable
GROUP BY UserID
HAVING COUNT(*) = 1
)
If you add the Dept column in your Group by you will always retrieve all the combinations.
So you have to select all users with only one Dept and then retrieve the additional informations
There is maybe syntax errors because I am usually working with oracle but I think the concept is correct
This will select users in 'hr' that do not have id's in 'customer' and then users in 'customer' that do not have ids in 'hr'.
I didn't include count on purpose as it can always only be one.
SELECT * FROM [MyTable] T WHERE Department = 'hr' AND NOT EXISTS (SELECT 1 FROM [MyTable] WHERE [MyTable].UserID =T.UserID AND Department = 'customer') UNION
SELECT * FROM [MyTable] T WHERE Department = 'customer' AND NOT EXISTS (SELECT 1 FROM [MyTable] WHERE [MyTable].UserID =T.UserID AND Department = 'hr')
I do not think the above query will run as Dept is not in group by clause and also count comparsion cannot be in that way.
Coming to your issue:
Select userid, Dept
from #temp
where userid in (Select userid from (Select userid,count(*) 'C'
from #temp group by userid ) u where u.c=1)
I do not think you require count as it is always 1
It's a fake question because you can't use Dept in this query.
I'm don't understand why author doesn't explain us about any compiler warnings and tells us some results of this query.
but you can yse this way if you really want to get some result:
SELECT UserId, min(Dept) as Dept
FROM MyTable
GROUP BY UserID
HAVING COUNT(*) = 1
The problem is the COUNT (*) at the end.
Try this:
SELECT UserId, Dept, COUNT(*) Total
FROM MyTable
GROUP BY UserID
HAVING COUNT(UserId) = 1

I want to get 3 highest values in output when i execute query in vb 2010

I have a query thats displaying result, but i want 3 highest values only in Ascending order from this query
select (sum(l.quantity*l.rate-l.recieved)+first(c.openbal)) as total from customer c RIGHT
JOIN ledger l ON l.refno = c.refno group by l.refno
You can use the TOP key word for it with ORDER BY Cluase
like
Select TOP 1 * from TABLE //Will return top most row
Select TOP 2 * from TABLE //Will return top 2 rows
Select TOP 3 * from TABLE //Will return top 3 rows
Your query should be
select TOP 3 (sum(l.quantity*l.rate-l.recieved)+first(c.openbal)) as total from customer
c RIGHT JOIN ledger l ON l.refno = c.refno group by l.refno ORDER BY
(sum(l.quantity*l.rate-l.recieved)+first(c.openbal)) DESC
try something like this
SELECT *
FROM (
SELECT SUM(Amount) as total, RANK() OVER (ORDER BY SUM(Amount) Desc) rankME
FROM tmp_Agents
GROUP BY AgentName
) x
WHERE rankME <= 3
try this
select TOP 3 (sum(l.quantity*l.rate-l.recieved)+first(c.openbal)) as total from customer c
RIGHT JOIN ledger l ON l.refno = c.refno group by l.refno ORDER BY total DESC

Which row has the highest value?

I have a table of election results for multiple nominees and polls. I need to determine which nominee had the most votes for each poll.
Here's a sample of the data in the table:
PollID NomineeID Votes
1 1 108
1 2 145
1 3 4
2 1 10
2 2 41
2 3 0
I'd appreciate any suggestions or help anyone can offer me.
This will match the highest, and will also bring back ties.
select sd.*
from sampleData sd
inner join (
select PollID, max(votes) as MaxVotes
from sampleData
group by PollID
) x on
sd.PollID = x.PollID and
sd.Votes = x.MaxVotes
SELECT
t.NomineeID,
t.PollID
FROM
( SELECT
NomineeID,
PollID,
RANK() OVER (PARTITION BY i.PollID ORDER BY i.Votes DESC) AS Rank
FROM SampleData i) t
WHERE
t.Rank = 1
SELECT PollID, NomineeID, Votes
FROM
table AS ABB2
JOIN
(SELECT PollID, MAX(Votes) AS most_votes
FROM table) AS ABB1 ON ABB1.PollID = ABB2.PollID AND ABB1.most_votes = ABB2.Votes
Please note, if you have 2 nominees with the same number of most votes for the same poll, they'll both be pulled using this query
select Pollid, Nomineeid, Votes from Poll_table
where Votes in (
select max(Votes) from Poll_table
group by Pollid
);

SELECT a single field by ordered value

Consider the following two tables:
student_id score date
-------------------------
1 10 05-01-2013
2 100 05-15-2013
2 60 05-01-2012
2 95 05-14-2013
3 15 05-01-2011
3 40 05-01-2012
class_id student_id
----------------------------
1 1
1 2
2 3
I want to get unique class_ids where the score is above a certain threshold for at least one student, ordered by the latest score.
So for instance, if I wanted to get a list of classes where the score was > 80, i would get class_id 1 as a result, since student 2's latest score was above > 80.
How would I go about this in t-sql?
Are you asking for this?
SELECT DISTINCT
t2.[class_ID]
FROM
t1
JOIN t2
ON t2.[student_id] = t1.[student_id]
WHERE
t1.[score] > 80
Edit based on your date requirement, then you could use row_number() to get the result:
select c.class_id
from class_student c
inner join
(
select student_id,
score,
date,
row_number() over(partition by student_id order by date desc) rn
from student_score
) s
on c.student_id = s.student_id
where s.rn = 1
and s.score >80;
See SQL Fiddle with Demo
Or you can use a WHERE EXISTS:
select c.class_id
from class_student c
where exists (select 1
from student_score s
where c.student_id = s.student_id
and s.score > 80
and s.[date] = (select max(date)
from student_score s1
where s.student_id = s1.student_id));
See SQL Fiddle with Demo
select distinct(class_id) from table2 where student_id in
(select distinct(student_id) from table1 where score > thresholdScore)
This should do the trick:
SELECT DISTINCT
CS.Class_ID
FROM
dbo.ClassStudent CS
CROSS APPLY (
SELECT TOP 1 *
FROM dbo.StudentScore S
WHERE CS.Student_ID = S.Student_ID
ORDER BY S.Date DESC
) L
WHERE
L.Score > 80
;
And here's another way:
WITH LastScore AS (
SELECT TOP 1 WITH TIES
FROM dbo.StudentScore
ORDER BY Row_Number() OVER (PARTITION BY Student_ID ORDER BY Date DESC)
)
SELECT DISTINCT
CS.Class_ID
FROM
dbo.ClassStudent CS
WHERE
EXISTS (
SELECT *
FROM LastScore L
WHERE
CS.Student_ID = L.Student_ID
AND L.Score > 80
)
;
Depending on the data and the indexes, these two queries could have very different performance characteristics. It is worth trying several to see if one stands out as superior to the others.
It seems like there could be some version of the query where the engine would stop looking as soon as it finds just one student with the requisite score, but I am not sure at this moment how to accomplish that.