Count in a VIEW - sql

I have a Deaths table where each personID display that died. There is also a column for reason of death and a date for when he/she died.
I need to count all the people that died by Illness, Accident, Suicide, etc.
I want my output to be like this:
| Illness | Accident | Suicide |
| 32 | 55 | 3 |
I can easily create a view like this:
CREATE VIEW viewDeaths AS
SELECT COUNT(personID) AS Illness
WHERE Reason = 'Illness';
And it will display it correct, but how do I do it with multiple conditions?
The main purpose is to display the different values for each reason on a graph in a C# application

Simply use multiple subqueries:
CREATE VIEW viewDeaths AS
SELECT Illness = (SELECT COUNT(*) FROM dbo.Deaths d
WHERE d.Reason = 'Illness'),
Accident = (SELECT COUNT(*) FROM dbo.Deaths d
WHERE d.Reason = 'Accident'),
Suicide = (SELECT COUNT(*) FROM dbo.Deaths d
WHERE d.Reason = 'Suicide')

In this way:
CREATE VIEW viewDeaths AS
SELECT Reason, COUNT(personID) AS Illness
-- WHERE Reason IN (.....)
GROUP BY Reason

Since it's a view, you can't use dynamic SQL, so either a static PIVOT or a CASE expression would be the best way to do it:
CREATE VIEW viewDeaths
AS
SELECT SUM(CASE WHEN Reason = 'Illness' THEN 1 ELSE 0 END) Illness,
SUM(CASE WHEN Reason = 'Accident' THEN 1 ELSE 0 END) Accident,
SUM(CASE WHEN Reason = 'Suicide' THEN 1 ELSE 0 END) Suicide
FROM dbo.Deaths;

Related

Create function that returns table in SQL

I wanted to create view with some logic like using (for loop , if .. else) but since that's not supported in SQL
I thought of creating table function that takes no parameter and returns a table.
I have a table for orders as below
OrderId Destination Category Customer
----------------------------------------
6001 UK 5 Adam
6002 GER 3 Jack
And table for tracking orders as below
ID OrderID TrackingID
-----------------------
1 6001 1
2 6001 2
3 6002 2
And here are the types of tracking
ID Name
--------------
1 Processing
2 Shipped
3 Delivered
As you can see in tracking order, The order number may have more than one record depending on how many tracking events occurred.
We have more than 25 tracking types that I didn't include here. which means one order can exist 25 times in tracking order table.
Now with that being said , My requirements is to create view as below with condition that an order must belong to 5 or 3 category ( we have more than 15 categories).
And whenever I run the function it must return the updated information.
So for example, when new tracking occurs and it's inserted in tracking order , I want to run my function and see the update in the corresponding flag column (e.g isDelivered).
I'm really confused on what is the best way to achieve this. I don't need the exact script i just need to understand the way to achieve it as i'm not very familiar with SQL
It could be done with a crosstab query using conditional aggregation. Something like this
select o.OrderID,
max(case when tt.[Name]='Processing' then 1 else 0 end) isPrepared,
max(case when tt.[Name]='Shipped' then 1 else 0 end) isShipped,
max(case when tt.[Name]='Delivered' then 1 else 0 end) isDelivered
from orders o
join tracking_orders tro on o.OrderID=tro.OrderID
join tracking_types tt on tro.TrackingID=tt.TrackingID
where o.category in(3, 5)
group by o.OrderID;
[EDIT] To break out Category 3 orders, 3 additional columns were added to the cross tab.
select o.OrderID,
max(case when tt.[Name]='Processing' then 1 else 0 end) isPrepared,
max(case when tt.[Name]='Shipped' then 1 else 0 end) isShipped,
max(case when tt.[Name]='Delivered' then 1 else 0 end) isDelivered,
max(case when tt.[Name]='Processing' and o.category=3 then 1 else 0 end) isC3Prepared,
max(case when tt.[Name]='Shipped' and o.category=3 then 1 else 0 end) isC3Shipped,
max(case when tt.[Name]='Delivered' and o.category=3 then 1 else 0 end) isC3Delivered
from orders o
join tracking_orders tro on o.OrderID=tro.OrderID
join tracking_types tt on tro.TrackingID=tt.TrackingID
where o.category in(3, 5)
group by o.OrderID;

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.

Normalising a table in Oracle SQL

Was wondering if someone could assist in providing some guidance as to how I could most efficiently normalize the following table so that I can create a refreshable view / table.
Table1:
SYSTEM_KEY | ID | ORDER | ORDER_STATUS | SYSTEM_Actions
A 1 Pencil Open Shipped
B 1 Pencil Open Tested
C 1 Pencil Open Shipped
A 1 Paper Closed Delivered
I'am looking to normalize this table in a repeatable way to something like this:
RESULT:
ID | ORDER | Order Status | A_actions | B_Actions | C_Actions
1 Pencil OPEN Shipped Tested Delivered
1 Paper Closed Delivered null null
I was able to achieve this by doing something similar to this
Select full.ID, full.order, full.orderstatus, case when system_ID = 'A' then sysa.system_actions as A_actions, ....{for B, C}
from table1 full
left join table1 sysa on full.id = sysa.id and full.order = sysa.order
left join table1 sysb on full.id = sysb.id and full.order = sysb.order
Whilst this appeared to work, it was quite clunky in terms of being repeatable having to use several staging tables.
Does anyone know if a good way I can achieve this?
try using group by clause
select id,order,order_status,
case when system_ID = 'A' then system_actions as A_actions,
case when system_ID = 'B' then system_actions as B_actions,
case when system_ID = 'C' then system_actions as C_actions
from table1
group by id,order,order_status

sql query that will get a distinct type, brand, and model, but get a count of how many duplicates were found

I have a table "Competitor" and here are some of its columns:
Type | Brand | Model | Date | Resolution | etc.
The table will have duplicate Model entries (with obviously same Brand as well, but possibly a different Type (two possible types: 'ProAV' and 'Disti')). I need to build a query that will output a table like this:
Top (ProAV) | Top (Disti) | Last Occurrence | Brand | Model | Resolution | etc.
Basically I need a query that will get a distinct type, brand, and model, but get a count of how many duplicates were found and put that number in either Top (ProAV) or Top (Disti), whichever Type it has. I would need to pull the most recent (given Date) out of the duplicates, so that I can put its Date as the Last Occurrence field. I hope this makes sense, let me know if it doesn't.
SELECT SUM(CASE WHEN Type = 'ProAV' THEN 1 ELSE 0 END) AS TopProAV,
SUM(CASE WHEN Type = 'Disti' THEN 1 ELSE 0 END) AS TopDisti,
MAX(Date) AS LastOccurence,
Brand, Model, Resolution
FROM Competitor
GROUP BY Brand, Model, Resolution
EDIT: Based on the comment, you could use a subquery or CTE to accomplish what you want. Something like:
WITH cteMaxDate AS (
SELECT SUM(CASE WHEN Type = 'ProAV' THEN 1 ELSE 0 END) AS TopProAV,
SUM(CASE WHEN Type = 'Disti' THEN 1 ELSE 0 END) AS TopDisti,
MAX(Date) AS LastOccurence,
Brand, Model, Resolution
FROM Competitor
GROUP BY Brand, Model, Resolution
)
SELECT md.TopProAV, md.TopDisti,
md.LastOccurentce,
md.Brand, md.Model, md.Resolution,
c.AdditionalColumn1, c.AdditionalColumn2
FROM cteMaxDate md
INNER JOIN Competitor c
ON md.Brand = c.Brand
AND md.Model = c.Model
AND md.Resolution = c.Resolution
AND md.LastOccurence = c.Date
Do you have a limited number of Types? In this case you can solve your problem using pivot
More specifically, for the table
Type Model
---- -----
A X
B X
C Y
A Z
NULL NULL
you run this query
Select Model, [A], [B], [C]
From
(select Model, Type
from dbo.Competitor) as SourceTable
PIVOT
(Count([Type]) for [Type] in ([A], [B], [C])) as PivotTable
to get
Model A B C
------ - - -
X 1 1 0
Y 0 0 1
Z 1 0 0