One SQL statement for multiple column totals based on year - sql

I'm trying to return the total number of unique countries listed for each year, and the total number of unique countries in the entire table. The table is formatted like this:
Country | Year | State | V1 | V2 |
US 2020 NY 9 2
US 2020 MA 3 6
CA 2020 MAN 2 8
CA 2020 ONT 5 1
AU 2020 TAS 7 2
AU 2020 VIC 3 3
US 2021 NY 2 0
US 2021 MA 8 2
AU 2021 TAS 4 1
AU 2021 VIC 5 2
I want my query to return this:
2020 | 2021 | Total_Unique_Countries
3 2 3
I tried:
SELECT
SUM(CASE WHEN YEAR=2020 THEN 1 ELSE 0 END) AS "2020",
SUM(CASE WHEN YEAR=2021 THEN 1 ELSE 0 END) AS "2021",
COUNT(DISTINCT COUNTRY) AS Total_Unique_Countries
FROM MYTABLE GROUP BY YEAR
The result:
2020 | 2021 | Total_Unique_Countries
6 0 3
0 4 2

SELECT
COUNT(DISTINCT CASE WHEN YEAR=2020 THEN COUNTRY END) AS "2020",
COUNT(DISTINCT CASE WHEN YEAR=2021 THEN COUNTRY END) AS "2021",
COUNT(DISTINCT COUNTRY) AS Total_Unique_Countries
FROM MYTABLE
This should give you the result you are looking for.

You can first elimnate the duplicates in a CTE and then count
WITH CTE as (SELECT
DISTINCT "Country", "Year" FROM MYTABLE)
SELECT
SUM(CASE WHEN "Year"=2020 THEN 1 ELSE 0 END) AS "2020",
SUM(CASE WHEN "Year"=2021 THEN 1 ELSE 0 END) AS "2021",
COUNT(DISTINCT "Country") AS Total_Unique_Countries
FROM CTE
2020
2021
total_unique_countries
3
2
3
SELECT 1
fiddle

Related

Grouping problems using two CTEs

Code is providing correct numbers- Grouping is giving me a problem and this maybe a fundamental code chose issue. Query is as:
With
P as ( Select sum(r.qty) as proposed, rm.entity, id,
quarter (case When status = open then quarter = 1 ELSE 3 END) AS QUARTER,
year (case When status = open then year = 2017 ELSE 2016 END) AS YEAR,
FROM Db1
Group By proposed, quarter, id, entity, quarter, year)
A as ( Select sum(r.qty) as awarded, rm.entity, id,
quarter (case When status = open then quarter = 2 ELSE 4 END),
year(case When status = open then year = 2018 ELSE 2016 END)
From DB1
Group By proposed, quarter, id, entity, quarter, year
)
SELECT * FROM P right join a on p.id = a.id
Group By proposed, quarter, id, entity, quarter, year
My returns are something like:
ID p.Quarter p.Year a.Quarter a.Year Proposed Awarded
1 null null 1 2017 null 1
2 2 2018 3 2017 1 1
2 1 2018 4 2016 1 1
3 null null 2 2018 null 2
I want:
ID p.Quarter p.Year a.Quarter a.Year Proposed Awarded
1 null null 1 2017 null 1
2 2 2018 null null 1 null
2 1 2018 null null 1 null
2 null null 3 2017 null 1
2 null null 4 2017 null null
3 null null 2 2018 null 2
The problem is - If an ID has a proposed date, quantity, awarded date and quantity I want all of the years and quarters to be shown outside of the id grouping. So each awarded or proposed count will have it's own row. Otherwise the counts are coming in wrong.
I am pulling from two different databases and my Case statements are much more complex but adding that large amount of code seed irrelevant for this.

SQL Aggregate on Two tables

Table A has millions of records from 2014, Using Oracle
ID Sales_Amount Sales_Date
1 10 20/11/2014
1 10 22/11/2014
1 10 22/12/2014
1 10 22/01/2015
1 10 22/02/2015
1 10 22/03/2015
1 10 22/04/2015
1 10 22/05/2015
1 10 22/06/2015
1 10 22/07/2015
1 10 22/08/2015
1 10 22/09/2015
1 10 22/10/2015
1 10 22/11/2015
Table B
ID ID_Date
1 22/11/2014
2 01/12/2014
I want sum of totals for 6 months as well as 1 year for ID 1 taking starting
date from Table B as 22/11/2014
Output Sales_Amount_6Months Sales_Amount_6Months
1 70 130
Shall I use add_months in this case?
Yes, you can use ADD_MONTHS() and conditional aggregation :
SELECT b.id,
SUM(CASE WHEN a.sales_date between b.id_date AND ADD_MONTHS(b.id_date,6) THEN a.sales_amount ELSE 0 END) as sales_6_month,
SUM(CASE WHEN a.sales_date between b.id_date AND ADD_MONTHS(b.id_date,12) THEN a.sales_amount ELSE 0 END) as sales_12_month
FROM TableB b
JOIN TableA a
ON(b.id = a.id)
GROUP BY b.id

How to turn repeated ranking(1-5) row data to column data in TSQL

I have a table data:
ID Sale Weekday
1 12 1
2 15 2
3 16 3
4 17 4
5 18 5
6 11 1
7 13 2
8 14 3
9 15 4
10 20 5
11 25 1
12 14 2
13 18 3
14 21 4
15 11 5
.. ..
I'd like to turn it into:
Mo Tu We Th Fr
12 15 16 17 18
11 13 14 15 20
25 14 18 21 11
..
Thank you!
Try this
SELECT SUM(case when Weekday = 1 then Sale else 0 end) as mn,
SUM(case when Weekday = 2 then Sale else 0 end) as Tu,
SUM(case when Weekday = 3 then Sale else 0 end) as We,
SUM(case when Weekday = 4 then Sale else 0 end) as Th,
SUM(case when Weekday = 5 then Sale else 0 end) as Fr
FROM
(
SELECT *,
Row_number()OVER(partition by weekday ORDER BY ID ) as seq_no
FROM tablename
) A
Group by seq_no
As mentioned in sample data if your table has all 5 days for all the week
SELECT SUM(case when Weekday = 1 then Sale else 0 end) as mn,
SUM(case when Weekday = 2 then Sale else 0 end) as Tu,
SUM(case when Weekday = 3 then Sale else 0 end) as We,
SUM(case when Weekday = 4 then Sale else 0 end) as Th,
SUM(case when Weekday = 5 then Sale else 0 end) as Fr
FROM
(
SELECT *,
( ( Row_number()OVER(ORDER BY ID ) - 1 ) / 5 ) + 1 seq_no
FROM tablename
) A
Group by seq_no
SQL FIDDLE DEMO
You could use the pivot operator together with a partitioned row_number like this:
select
max([1]) as 'Mo',
max([2]) as 'Tu',
max([3]) as 'We',
max([4]) as 'Th',
max([5]) as 'Fr'
from
(
select *, row_number() over (partition by weekday order by id) rn
from your_table
) a
pivot (max(sale) for weekday in ([1],[2],[3],[4],[5])) p
group by rn;

Counting values from a column and grouping and sorting by a second value

Let's say I have this table:
NAME YEAR SCORE
_____________________
User1 2010 1
User2 2011 3
User3 2012 2
User4 2013 1
User5 2012 1
User6 2011 3
User7 2010 4
User8 2011 1
I would like to create a query whose output looks like this from this data:
YEAR 1 2 3 4
________________________
2010 1 0 0 1
2011 1 0 2 0
2012 1 1 0 0
2013 1 0 0 0
Where the values in the numbered columns is the count of how many times that score appears in the given year. This seems as if it should be easy but I am having trouble figuring out how to wrap my head around writing this query in a way that is static. Ideas?
select YEAR,
count(CASE WHEN SCORE = 1 THEN 1 END) AS `1`,
count(CASE WHEN SCORE = 2 THEN 1 END) AS `2`,
count(CASE WHEN SCORE = 3 THEN 1 END) AS `3`,
count(CASE WHEN SCORE = 4 THEN 1 END) AS `4`
from TABLE
group by year
For a set of Four values
SELECT YEAR, SUM(CASE WHEN SCORE = 1 THEN 1 ELSE 0 END) AS `1`,
SUM(CASE WHEN SCORE = 2 THEN 1 ELSE 0 END) AS `2`,
SUM(CASE WHEN SCORE = 3 THEN 1 ELSE 0 END) AS `3`,
SUM(CASE WHEN SCORE = 4 THEN 1 ELSE 0 END) AS `4`
FROM TABLE
GROUP BY YEAR

How to group sums by weekday in MySQL?

I have a table like this:
id | timestamp | type
-----------------------
1 2010-11-20 A
2 2010-11-20 A
3 2010-11-20 B
4 2010-11-21 A
5 2010-11-21 C
6 2010-11-27 B
and I need to count the rows for each type, grouped by weekday; like this:
weekday | A | B | C
--------------------------
5 2 2 0 -- the B column equals 2 because nov 20 and nov 27 are saturday
6 1 0 1
What would be the simplest solution for this?
I don't mind using views, variables, subqueries, etc.
Use:
SELECT WEEKDAY(t.timestamp) AS weekday,
SUM(CASE WHEN t.type = 'A' THEN 1 ELSE 0 END) AS a,
SUM(CASE WHEN t.type = 'B' THEN 1 ELSE 0 END) AS b,
SUM(CASE WHEN t.type = 'C' THEN 1 ELSE 0 END) AS c
FROM YOUR_TABLE t
GROUP BY WEEKDAY(t.timestamp)