SQL Conditional Aggregation not returning all expected rows - sql

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.

Related

SQL - joining two queries against same table for grid output

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

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.

Group and Separate into Different Columns

I'm trying to group some data and separate one column into several. The following is the kind of table I'm working with although each of these columns are from individual tables connected through an ID on each:
ParticipantId QuestionText QuestionAnswer
1 What is your gender? 2
2 What is your gender? 1
3 What is your gender? 1
4 What is your gender? 2
5 What is your gender? 1
1 What is your age? 28
2 What is your age? NULL
3 What is your age? 55
4 What is your age? 63
And this is what I want to achieve:
ParticipantId Question1Answer Question2Answer Question3Answer
1 2 28 3
2 1 NULL 4
I imagine this is quite a difficult thing to do? As the questionnaire contains around 100 questions. I don't think using case would be suitable without typing each questionID out. I'm using SQL Server 2008. The following is some of the table structures I'm working with. I'm sure there's an clearer way than typing it out.
The QuestionnaireQuestion table contains QuestionNumber for the sequence and joins to the Question table to via questionID which is the Question tables PID. The question table contains QuestionText and links to the Answer table using QuestionID which contains the answer field. Then the answer table goes through a link table called QuestionnaireInstance which finally links to the PaperQuestionnaire table which contains the ParticipantID.
That probably hasn't made it any clearer, just let me know anything else that might clear it up a bit.
In case you don't want to have to type out all of the question text each time, you could always use this:
;with sample_data as
(
SELECT
ParticipantId
,QuestionText
,QuestionAnswer
,row_number() OVER (PARTITION BY PARTICIPANTID ORDER BY (SELECT NULL)) AS rn
FROM yourdatatable
)
SELECT
PARTICIPANTID
,MAX(CASE WHEN rn = 1 THEN questionanswer END) AS Q1
,MAX(CASE WHEN rn = 2 THEN questionanswer END) AS Q2
,MAX(CASE WHEN rn = 3 THEN questionanswer END) AS Q3
,MAX(CASE WHEN rn = 4 THEN questionanswer END) AS Q4
FROM sample_data
GROUP BY ParticipantId
Although it might be better in your case to consider dynamic pivoting instead, depending on how many columns you want to ultimately end up with
If you have uniquness in you table for column combination ParticipantId and QuestionText then you can use below query also to acive the desired output -
SELECT Participantid,
MAX(CASE
WHEN Questiontext = 'What is your gender?' THEN
Questionanswer
ELSE
NULL
END) AS Question1answer,
MAX(CASE
WHEN Questiontext = 'What is your age?' THEN
Questionanswer
ELSE
NULL
END) AS Question2answer,
MAX(CASE
WHEN Questiontext = '...your third question...' THEN
Questionanswer
ELSE
NULL
END) AS Question3answer,
..
..
FROM Your_Table_Name
GROUP BY Participantid

SQL query ordered alphabetically

I have a table as below,
ID Description
--------------------
1 Bacteria
2 Cell Lines
3 Compounds
4 Virus
5 Others
6 AntiBody
What I want is a single SQL query, ordered alphabetically but have 'Other' (ID 5) as the last record.
Is that even possible?
Any help would greatly appreciated.
Thanks.
SELECT ID, Description
FROM YourTable
ORDER BY CASE WHEN ID = 5 THEN 1 ELSE 0 END,
Description
SELECT ID, Description
FROM yourtable
ORDER BY CASE WHEN Description = 'Others' THEN 1 ELSE 0 END, Description

Counting values in columns

What I am looking for is to group by and count the total of different data in the same table and have them show in two different columns. Like below.
Data in table A
Fields:
Name Type
Bob 1
John 2
Bob 1
Steve 1
John 1
Bob 2
Desired result from query:
Name Type 1 Type 2
Bob 2 1
John 1 1
Steve 1 0
This will do the trick in SQL Server:
SELECT
name,
SUM( CASE type WHEN 1 THEN 1 ELSE 0 END) AS type1,
SUM( CASE type WHEN 2 THEN 1 ELSE 0 END) AS type2
FROM
myTable
GROUP BY
name
No time to write the code, but the Case statement is what you want here. SImply havea value of 1 if it meets the case and zero if it deosn't. Then you can sum the columns.
Use two separate GROUP BY subqueries.
SELECT Name, a.Count1, b.Count2
from myTable
JOIN
(SELECT Name, SUM(Type) AS Count1 FROM myTable GROUP BY Name WHERE Type=1) AS a ON a.Name = myTable.Name
(SELECT Name, SUM(Type) FROM myTable GROUP BY Name WHERE Type=2) AS b ON b.Name = myTable.Name
You're looking for a CrossTab solution. The above solutions will work, but you'll come unstuck if you want a general solution and have N types.
A CrossTab solution will solve this for you. If this is for quickly crunching some numbers then dump your data into Excel and use the native Pivot Table feature.
If it's for a RDBMS in an app, then it depends upon the RDBMS. MS SQL 2005 and above has a crosstab syntax. See:
http://www.databasejournal.com/features/mssql/article.php/3521101/Cross-Tab-reports-in-SQL-Server-2005.htm
#Seb has a good solution, but it's server-dependent. Here's an alternate using subselects that should be portable:
select
name,
(select count(type) from myTable where type=1 and name=a.name) as type1,
(select count(type) from myTable where type=2 and name=a.name) as type2
from
myTable as a
group by
name