SQL query to Group By and Concatenate - sql

I have a table as so:
Date
Opponent
Score
Result
09/14/56
Shawen
0-18
L
09/21/56
Dixie
12-16
L
...
...
...
...
10/29/60
Carlisle
0-6
L
11/12/60
Shawen
22-0
W
I'm trying to create a query which will produce this result:
Year
W-L
1956
1-4
1957
4-3
1958
3-6
1959
3-5
1960
7-1
I am able to run these queries independently:
SELECT YEAR(Date), COUNT(Result) From GameSummaries WHERE Result = 'W' GROUP BY YEAR(Date)
SELECT YEAR(Date), COUNT(Result) From GameSummaries WHERE Result = 'L' GROUP BY YEAR(Date)
Which return:
Year
W
1956
1
1957
4
1958
3
1959
3
1960
7
And:
Year
L
1956
4
1957
3
1958
6
1959
5
1960
1
I am able to run this query:
SELECT CONCAT(w, '-', l) FROM (SELECT
(SELECT COUNT(Result) FROM GameSummaries WHERE Result = 'W') AS w,
(SELECT COUNT(Result) FROM GameSummaries WHERE Result = 'L') AS l) as c
Which returns:
18-19
But I haven't been able to figure out the syntax to put them together.
My best effort is:
SELECT YEAR(Date), CONCAT(w, '-', l) FROM (SELECT
(SELECT YEAR(Date), COUNT(Result) FROM GameSummaries WHERE Result = 'W' GROUP BY YEAR(Date)) AS w,
(SELECT YEAR(Date), COUNT(Result) FROM GameSummaries WHERE Result = 'L' GROUP BY YEAR(Date)) AS l) as c
Which returns:
Msg 116, Level 16, State 1, Line 14 Only one expression can be
specified in the select list when the subquery is not introduced with
EXISTS. Msg 116, Level 16, State 1, Line 15 Only one expression can be
specified in the select list when the subquery is not introduced with
EXISTS. Msg 207, Level 16, State 1, Line 13 Invalid column name
'Date'.
This seems like it should be fairly basic, can someone please point me in the right direction?

You can use SUM with a case statement as a trick
SELECT YEAR(date) as [year],
sum(CASE WHEN Result = 'W' THEN 1 ELSE 0 END) + '-'
sum(CASE WHEN Result = 'L' THEN 1 ELSE 0 END) as [W-L]
FROM GameSummaries
GROUP BY Year(Date)
Note you may need to cast to string if you get an error change to this
cast(sum(CASE WHEN Result = 'W' THEN 1 ELSE 0 END) as varchar(20)) + '-'
cast(sum(CASE WHEN Result = 'L' THEN 1 ELSE 0 END) as varchar(20)) as [W-L]

Related

sql sales data grouped by year in separate columns in postgresql

I have two input tables:
analysis (an_id, an_name, an_cost, an_price, an_group)
orders (ord_id, ord_datetime, ord_an) # orders of analysis (sales)
For every analysis_id I need to show the amount of orders for years 2020 and 2019.
Expected output:
an
year2019
year2020
1
32
41
2
29
28
3
42
37
4
26
35
5
32
34
logic in my query:
step1 - get orders table data only for years 2019,2020 - use CTE and extract()
step2 - aggregate by year
My query:
WITH helper AS (
SELECT an_id,
ord_id,
EXTRACT(year from ord_datetime) as year
FROM analysis a
INNER JOIN orders o ON o.ord_an = a.an_id
WHERE EXTRACT(year FROM ord_datetime) in (2019.0,2020.0)
)
SELECT an_id,
CASE WHEN year = 2019.0 THEN COUNT(ord_id) ELSE 0 END AS year2019,
CASE WHEN year = 2020.0 THEN COUNT(ord_id) ELSE 0 END AS year2020
FROM helper
GROUP BY year, an_id
ORDER BY an_id
The current output of my query:
an_id
year2019
year2020
1
32
0
1
0
41
2
29
0
2
0
28
3
42
0
The issue in your query may be inside your GROUP BY clause, because you're grouping on the year too. Instead consider the following approach, where you invert the position of the COUNT aggregate function and the CASE statement:
SELECT a.an_id,
COUNT(CASE WHEN EXTRACT(year FROM o.ord_datetime) = 2019 THEN o.ord_id END) AS year2019,
COUNT(CASE WHEN EXTRACT(year FROM o.ord_datetime) = 2020 THEN o.ord_id END) AS year2020
FROM analysis a
INNER JOIN orders o
ON o.ord_an = a.an_id
GROUP BY a.an_id
Note: the ELSE part of your CASE statement is not necessary, as long as values will be defaulted to NULL (and not counted in by the COUNT).

How to group Ages with case

Someone knows how i can group ages witch the CASE statement?
I got the ages 14,15,16,17,18,19,20,21,22,23,24,25. I want groups like <18,19,20,>21
I started like:
Case age when BETWEEN 14 AND 18 THEN sum(age)
when >=21 THEN sum(age)
ELSE age END as age_groups
But i think aggregate functions don't work in CASE statements, at least it brings up an error.
CASE statement would work, you have a syntax error, your query would be:
SELECT Case when age BETWEEN 14 AND 18 THEN '14 - 18'
when age >=21 THEN '>=21'
ELSE age END as age_groups, SUM(age)
FROM YOUR_TABLE
GROUP BY Case when age BETWEEN 14 AND 18 THEN '14 - 18'
when age >=21 THEN '>=21'
ELSE age END
Use a CTE to calculate the age_groups, and then you can normally sum the ages for each group.
WITH age_groups AS (
SELECT Age,
Case when age BETWEEN 14 AND 18 THEN '14 - 18'
when age >=21 THEN '>=21'
ELSE age END as age_group
FROM YOUR_TABLE
)
SELECT age_group, sum(Age)
FROM age_groups
GROUP BY age_group
Another neat alternative is to place the CASE inside a CROSS APPLY (VALUES so you can then refer to it in other parts of the query without repetition:
SELECT
v.age_group,
SUM(Age)
FROM age_groups ag
CROSS APPLY (VALUES (
CASE WHEN ag.age BETWEEN 14 AND 18 THEN '14 - 18'
WHEN ag.age >= 21 THEN '>=21'
ELSE CAST(ag.age AS varchar(10)) END
) ) v(age_group)
GROUP BY v.age_group
You can use Case inside Sum():
select
Sum(Case when age < 18 then 1 end) '<18',
Sum(Case when age = 19 then 1 end) '19',
Sum(Case when age = 20 then 1 end) '20',
Sum(Case when age > 20 then 1 end) '>20'
from myTable;
DBFiddle demo is here
EDIT: If you meant to get the results vertically, still keep it simple:
select '<18' as ageGroup, Sum(Case when age < 18 then 1 end) total from myTable
union
select '19', Sum(Case when age = 19 then 1 end) from myTable
union
select '20', Sum(Case when age = 20 then 1 end) from myTable
union
select '20>', Sum(Case when age > 20 then 1 end) from myTable;

Multiple SUM in one query with multiple where

I'm trying to write a SQL query that produces a table with summarized values for each year and month.
I have a table that looks something like this:
TABLENAME: TIME
id cID cDate cTime
1 254 2019-10-11 5
2 259 2019-10-13 4
3 268 2020-01-17 6
4 268 2020-01-18 9
5 271 2020-01-21 4
6 267 2020-02-19 8
And another table that looks like this:
TABLENAME: CASE
id name invoice status
254 Acme Yes finish
259 Tex NoFakt finish
268 Rex C Yes *Null*
267 Hydro *Null* open
271 Corp Yes finish
I want to have a query that returns the sum for each month like this:
Year Month RegTime Invoiced ToBeInvoiced
2019 10 5 5 0
2019 11 0 0 0
2019 12 0 0 0
2020 1 19 4 15
2020 2 8 0 8
Explanation of the output:
Year and Month are obvious
RegTime should be the sum of all TIME.cTime WHERE CASE.invoice <> 'NoFakt'
Invoiced should be the sum of all TIME.cTIME WHERE CASE.invoice = 'Yes' AND CASE.status = 'finish'
ToBeInvoiced should be the sum of all TIME.cTIME WHERE CASE.invoice = 'Yes' AND CASE.status <> 'finish'
I have tried this query, but with this i need to loop a predefined year and month value in my programming code instead of simply having a sql statement that are doing all the work. ThereĀ“s got to be a simpler way than this...
select (select sum(cTIME) from TIME inner join CASE on TIME.cID = CASE.id WHERE CASE.invoice <> 'NoFakt' AND DATEPART(yy, cDate) = '2019' AND DATEPART(mm, cDate) = '10') AS RegTime,
(select sum(cTIME) from TIME inner join CASE on TIME.cID = CASE.id WHERE CASE.invoice = 'Yes' AND CASE.status = 'finish' AND DATEPART(yy, cDate) = '2019' AND DATEPART(mm, cDate) = '10') AS Invoiced,
(select sum(cTIME) from TIME inner join CASE on TIME.cID = CASE.id WHERE CASE.invoice = 'Yes' AND CASE.status <> 'finish' AND DATEPART(yy, cDate) = '2019' AND DATEPART(mm, cDate) = '10') AS ToBeInvoiced
Use conditional aggregation :
SELECT YEAR(T.cDate) AS YR, MONTH(T.cDate) AS Mnth,
SUM(CASE WHEN C.invoice <> 'NoFakt' THEN C.cTIME ELSE 0 END) AS RegTime,
SUM(CASE WHEN C.invoice = 'Yes' AND C.status = 'finish' THEN C.cTIME ELSE 0 END) AS Invoiced,
SUM(CASE WHEN C.invoice = 'Yes' AND C.status <> 'finish' THEN C.cTIME ELSE 0 END) AS ToBeInvoiced
FROM TIME T INNER JOIN
CASE C
ON T.cID = C.id
GROUP BY YEAR(T.cDate), MONTH(T.cDate);
Note: Do not use reserved keyword as Object Name.

how to sum two column within single case statement

The query below returns 2 rows, but actually I need only one;
select Datename(month, m.CreatedDate) as [Ay], sum(case when h.Cinsiyet=1 then 1 else 0 end) as [Group1], sum(case when h.Cinsiyet=2 then 1 else 0 end) as [Group2] from Muayene.Muayene m with(nolock)
join Ortak.Hasta h with(nolock) on m.HastaTc = h.HastaTc
group by h.Cinsiyet, Datename(month, m.CreatedDate)
result:
MonthName Group1 Group2
April 4500 0
April 0 9000
Expected Result:
MonthName Group1 Group2
April 4500 9000
I know I can do it wrapping the query with another select statement and Group by month and Sum these results.. But its not efficient and looks dirty code.
How can I make a trick to get expected result without make another sum statement?
FIx the GROUP BY:
select Datename(month, m.CreatedDate) as [Ay],
sum(case when h.Cinsiyet = 1 then 1 else 0 end) as [Group1],
sum(case when h.Cinsiyet = 2 then 1 else 0 end) as [Group2]
from Muayene.Muayene m join
Ortak.Hasta h
on m.HastaTc = h.HastaTc
group by Datename(month, m.CreatedDate);

Group by datepart and find total count of individual values of each record

This is table structure;
ID Score Valid CreatedDate
1 A 1 2018-02-19 23:33:10.297
2 C 0 2018-02-19 23:32:40.700
3 B 1 2018-02-19 23:32:30.247
4 A 1 2018-02-19 23:31:37.153
5 B 0 2018-02-19 23:25:08.667
...
I need to find total number of each score and valid in each month
I mean final result should be like
Month A B C D E Valid(1) NotValid(0)
January 123 343 1021 98 12 1287 480
February 516 421 321 441 421 987 672
...
This is what I tried;
SELECT DATEPART(year, CreatedDate) as Ay,
(select count(*) from TableResults where Score='A') as 'A',
(select count(*) from TableResults where Score='B') as 'B',
...
FROM TableResults
group by DATEPART(MONTH, CreatedDate)
but couldn't figure how to calculate all occurrence of scores on each month.
Use conditional aggregation.
SELECT DATEPART(year, CreatedDate) as YR
, DATEPART(month, CreatedDate) MO
, sum(Case when score = 'A' then 1 else 0 end) as A
, sum(Case when score = 'B' then 1 else 0 end) as B
, sum(Case when score = 'C' then 1 else 0 end) as C
, sum(Case when score = 'D' then 1 else 0 end) as D
, sum(Case when score = 'E' then 1 else 0 end) as E
, sum(case when valid = 1 then 1 else 0 end) as Valid
, sum(case when valid = 0 then 1 else 0 end) as NotValid
FROM TableResults
GROUP BY DATEPART(MONTH, CreatedDate), DATEPART(year, CreatedDate)
I'm not a big fan of queries in the select; I find they tend to cause performance problems in the long run. Since we're aggregating here I just applied the conditional logic to all the columns.