SQL - joining two queries against same table for grid output - sql

I should probably be able to figure this out from other questions/answers I've read here, but I just can't get anything to work today. Any help is really appreciated.
I have two queries, counting the instances of "GOOD" feedback, and "BAD" feedback from a single table. I just want to join them so that I can see something like below
ID | GOOD | BAD
121 | 0 | 7
123 | 5 | 0
287 | 32 | 8
I'm running numerous queries from VBA, if that matters, and the 0's can just be null. I can clean that stuff up in VBA.
Query 1:
select ID, count(*)
from HLFULL
where DEPT= 'HLAK'
and feedback = 'GOOD'
group by ID
Query 2:
select ID, count(*)
from HLFULL
where DEPT= 'HLAK'
and feedback = 'BAD'
group by ID
I've tried UNION, UNION ALL, JOIN, INNER JOIN, OUTER JOIN, aggregations, etc.

You can do conditional aggregation like this:
select ID,
count(case when feedback = 'GOOD' then 1 end) as Good,
count(case when feedback = 'BAD' then 1 end) as Bad
from HLFULL
where DEPT = 'HLAK'
and feedback in ('GOOD', 'BAD')
group by ID

You should be able to get the result using conditional aggregation. This type of query uses a CASE expression along with your aggregate function to get multiple columns:
select ID,
count(case when feedback = 'GOOD' then Id end) as Good,
count(case when feedback = 'BAD' then Id end) as Bad
from HLFULL
where DEPT= 'HLAK'
group by ID

Related

SQL Conditional Aggregation not returning all expected rows

So I've been trying to get a conditional aggregation running on one of my tables in SQL Server Management Studio and I've run across a problem: only one row is being returned when there should be 2.
SELECT ListID,
MAX(CASE WHEN QuestionName = 'Probability Value' THEN Answer END) AS 'prob',
MAX(CASE WHEN QuestionName = 'Impact Value' THEN Answer END) As 'impa',
MAX(CASE WHEN QuestionName = 'What is the Risk Response Strategy' THEN Answer END) AS 'strat',
MAX(CASE WHEN QuestionName = 'Response Comment' THEN Answer END) AS 'rrap'
FROM table1
GROUP BY ListID
By the information stored on the table is should return two rows, something like:
ListID | Prob | Impa | Strat | rrap |
1 2 3 Admin text1
1 5 5 Elim text2
but only the first row appears. I don't have any good leads at the moment, but I wonder if you good people might have spotted something obviously wrong with the initial query.
Your only group by is ListID and your 2 rows both have 1 on ListID, that's why they group up
Why do you think it should return more than 1 row? You are grouping by ListID and getting the MAX answer for all these questions.
If you want more rows returned you will have to group by other columns/expressions as well. You can't expect ListID 1 to appear more than once if you grouped by ListID only.

Using Count distinct case in sql and group by multiple columns

I have a query that works great (listed below). The issue I am having is we have run into a patient that has had event on two different days and because I am grouping by the PATNUM, it is only showing it as one.
How can I get it to count 1 for each time if the PATNUM and SCHDT are different
Example:
PATNUM SCHDT
12345 30817
12345 30817
54321 30817
54321 30717
PATNUM 12345 should only count once while PATNUM 54321 should count twice.
My count statement is this:
SELECT ph.*, pi.*,
COUNT(DISTINCT CASE WHEN `SERVTYPE` IN ('INPT','INPFOP','INFOBS','IP') AND Complete ='7' THEN pi.PATNUM ELSE NULL END) AS count1,
COUNT(DISTINCT CASE WHEN `SERVTYPE` IN ('INPT','INPFOP','INFOBS','IP') AND Complete ='8' THEN pi.PATNUM ELSE NULL END) AS count2
FROM patientinfo as pi
INNER JOIN physicians as ph ON pi.SURGEON=ph.PName
WHERE PID NOT IN ('1355','988','767','1289','484','2784')
GROUP BY SURGEON
ORDER BY Dept,SURGEON ASC
Which columns do you want to see?
You can adjust your GROUP BY:
SELECT
ph.pname,
ph.specialty,
SUM(CASE WHEN complete = 7 THEN 1 ELSE 0 END) count1,
SUM(CASE WHEN complete = 8 THEN 1 ELSE 0 END) count2
FROM
(
SELECT
DISTINCT
surgeon,
patnum,
schdt,
complete,
servtype
FROM patientinfo
WHERE complete IN (7,8)
AND servtype IN ('INPT','INPFOP','INFOBS','IP')
AND pid NOT IN ('1355','988','767','1289','484','2784')
) pisub
INNER JOIN physicians ph ON pisub.surgeon = ph.pname
GROUP BY ph.pname, ph.specialty
ORDER BY ph.pname, ph.specialty;
Also, I would make a few suggestions:
If you're going to give your tables an alias, then use the alias when referring to any column in your query. I've made a guess here about some of your columns as to which table they come from (e.g. dept), so feel free to change it if it is not correct
You don't need to select all records from both tables if you don't need them
The query won't run if you don't GROUP BY all columns you're selecting. I've written about this for Oracle and SQL in general, but actually in MySQL I think it does run but show incorrect results.

Selecting count by row combinations

I'm strugling with what on the first sight appeared to be simple SQL query :)
So I have following table which has three columns: PlayerId, Gender, Result (all of type integer).
What I'm trying to do, is to select distinct players of gender 2 (male) with number of each results.
There are about 50 possible results, so new table should have 51 columns:
|PlayerId | 1 | 2 | 3 | ... | 50 |
So I would like to see how many times each individual male (gender 2) player got specific result.
*** In case question is still not entirely clear to you: After each game I insert a row with a player ID, gender and result (from 1 - 50) player achieved in that game. Now I'd like to see how many times each player achieved specfic results.
If there are 50 results and you want them in columns, then you are talking about a pivot. I tend to do these with conditional aggregation:
select player,
sum(case when result = 0 then 1 else 0 end) as result_00,
sum(case when result = 1 then 1 else 0 end) as result_01,
. . .
sum(case when result = 50 then 1 else 0 end) as result_50
from t
group by player;
You can choose a particular gender if you like, with where gender = 2. But why not calculate all at the same time?
try
select player, result, count(*)
from your_table
where Gender = 2
group by player, result;
select PleyerId from tablename where result = 'specific result you want' and gender = 2 group by PleyerId
The easiest way is to use pivoting:
;with cte as(Select * from t
Where gender = 2)
Select * from cte
Pivot(count(gender) for result in([1],[2],[3],....,[50]))p
Fiddle http://sqlfiddle.com/#!3/8dad5/3
One note: keeping gender in scores table is a bad idea. Better make a separate table for players and keep gender there.

Do subqueries ignore an outer WHERE condition if it has it's own WHERE condition?

I want a SQL query to follow the conditions of a WHERE statement, except those that are subqueries. In the example below, I'd like to get all entries from the past week, but I want the subqueries to ignore that outer WHERE clause, but I'm not sure of how it will behave.
For example:
SELECT
ProductID,
SUM(CASE WHEN from_source = 'button' THEN 1 ELSE 0 END) 'Used Button',
(SELECT COUNT(*) FROM tracking WHERE from_source = 'button') 'Used Button to date'
FROM tracking
WHERE date_entered > (GETDATE() - 7)
GROUP BY ProductID
Expected output, where the second column is calculating based on outer WHERE, and subquery is not looking at the outer WHERE:
ProductID | Used Button | Used Button to date
123 | 5 | 102
456 | 8 | 175
You could write the query just using conditional aggregation:
select sum(case when date_entered > (GETDATE() - 7) then 1 else 0
end) as UsedButton,
count(*) as UsedButtonToDate
from tracking
where from_source = 'button';
This seems like a simpler approach.
By the way, you shouldn't use single quotes for column aliases. Either name the columns with something that doesn't have to be escaped (as above) or use square braces.

SQL Nested Select Statement

I have the following SQL Code which is not giving me my desired results.
SELECT
POLICIES.CLIENTS_ID,
POLICIES.CLIENTCODE,
COUNT(POLICIES.POLICIES_ID) as [Total Policies],
(
SELECT
COUNT(POLICIES.POLICIES_ID)
FROM
POLICIES
WHERE
POLICIES.COVCODE = 'AUT'
) as [Auto Policies]
FROM
POLICIES
LEFT JOIN CLIENTS
ON CLIENTS.CLIENTS_ID = POLICIES.CLIENTS_ID
WHERE
POLICIES.CNR IS NULL
GROUP BY
POLICIES.CLIENTS_ID,
POLICIES.CLIENTCODE
ORDER BY
POLICIES.CLIENTS_ID
I get a result like this:
ID CODE Total Auto
3 ABCDE1 1 999999
4 ABCDE2 1 999999
5 ABCDE3 2 999999
6 ABCDE4 2 999999
I would like for the last column to COUNT the total auto policies that exists for that clientid rather than all of the auto policies that exist. I believe I need a nested select statement that somehow groups all like results on the clientid, but it ends up returning more than 1 row and throws the error.
If I add:
GROUP BY
POLICIES.CLIENTS_ID
I get:
Subquery returned more than 1 value. This is not permitted when the....
Any help would be appreciated greatly!
Thank you
You can use a CASE statement to do this. Instead of your subquery in the SELECT clause use:
SUM(CASE WHEN POLICIES.COVCODE = 'AUT' THEN 1 ELSE 0 END) as [AUTO POLICIES]
As Martin Smith pointed out. If client_id has multiple client_codes then this will give you the count of records for each combination of client_id/client_code. If client_id is 1:1 with client_code then this will give you a count of records for each distinct client_id, which I suspect is the case from your example and question.
Unrelated: You have a LEFT JOIN to your Clients table, but you don't use your Clients table anywhere int he query. Consider removing it if you don't need to select or filter by any its fields, since it's just unused overhead.
What if you modify the inner query for getting count to something like
SUM(CASE WHEN POLICIES.COVCODE = 'AUT' THEN 1 ELSE 0 END) as [Auto Policies]