How do I change the query to just show one row SQL? - sql

I am trying to compile a view of how many instances occur in each month. I have the below code, which gets me the answer, but also gives multiple rows. How do I limit the view to just one row, with each column being the amount of instances each month?
CREATE VIEW new_users_per_month AS
SELECT (
SELECT COUNT(id) AS January
FROM master_table
WHERE month(created_at)=1) AS January,
(
SELECT COUNT(id) AS February
FROM master_table
WHERE month(created_at)=2) AS February,
(
SELECT COUNT(id) AS March
FROM master_table
WHERE month(created_at)=3) AS March
FROM master_table;

Do conditional aggregation :
select count(case when month(created_at) = 1 then id end) as Jan,
count(case when month(created_at) = 2 then id end) as Feb,
count(case when month(created_at) = 3 then id end) as Mar
from master_table t;

Not properly tested, i will create dummy and test in a moment, but in support of my comment
select *
from
(
select
t.id,
month(t.created_at) as MTH_CRE
from master_table as t
) as q
pivot
(
count(id) for MTH_CRE in ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12])
) as pvt

Related

Transposing quarters as row to column using BigQuery

I have data that contains Quarters as rows.
Is it possible to convert 7 Quarters into columns using BigQuery?
My data :
Desired output :
Methods used by me :
Offset clause
Select Name,
SUM(CASE WHEN QuarterEnding ='Q1, 2020' THEN AT END) Q12020,
SUM(CASE WHEN QuarterEnding='Q2, 2020' THEN AT END) Q22020,
SUM(CASE WHEN QuarterEnding='Q3, 2020' THEN AT END) Q32020,
SUM(CASE WHEN QuarterEnding='Q4, 2020' THEN AT END) Q42020,
FROM `table1`
GROUP by 1;
As #Pi-R mentioned, example query in the documentation is very close to what you want but for your specific desired output, you might consider below.
SELECT * FROM (
SELECT * EXCEPT(City) FROM `table1`
) PIVOT (
SUM(`AT`) FOR TRANSLATE(QuarterEnding, ', ', '')
IN ('Q12020', 'Q22020', 'Q32020', 'Q42020',
'Q12021', 'Q22021', 'Q32021', 'Q42021')
);
You can look at pivot function of BigQuery https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#pivot_operator. There is the same use case as yours
First you have to rename quarter's name so they can be a field.
Q1, 2020 => Q12020
Then you can use
SELECT * FROM `table_name`
PIVOT(min(ID) FOR QuarterEnding IN ('Q12020', 'Q22020', 'Q32020', 'Q42020','Q12021', 'Q22021', 'Q32021', 'Q42021'))

How to add a condition for the query so that it can calculate the unique months and years in PostgreSQL

How can I write down the condition so that he counts the months for me from a certain client (redirect) and source (source)? I need to know how many invoices were issued, and this is counted by month, type January and February are 2 invoices, March April June 3 invoices, etc. I could write max instead of count, but this is not correct, since the client may appear in the middle of the year, for example in May, and he will have the values of the maximum month.
Here is my request:
select TA.redirect,
count(case when TA.source='zlat1' then extract(month from TA.date) else 0 end) number_of_accounts_zlat1,
count(case when TA.source='zlat2' then extract(month from TA.date) else 0 end) number_of_accounts_zlat2,
sum(TA.result_for_the_day) accrued
from total_accounts TA
group by TA.redirect
Here are tables and data + query and result ---->
https://dbfiddle.uk/?rdbms=postgres_14&fiddle=0bc8002e59b03afedeac8d1b8dfc98d1
insert into finace_base (redirect)
select distinct Ta.redirect /*this select will display those names that are not present
in FB if there is other info that u must add to insert then
just add , next to redirect and add whatever u like*/
from total_acounts TA
left join finace_base FB on TA.redirect=FB.redirect
where FB.redirect is null;
update finace_base FB
set zlat1=TA.zlat1,
zlat2=TA.zlat2,
accrued=TA.accrued
from (select TA.redirect,
count(*) filter ( where TA.source='zlat1' ) as zlat1,
count(*) filter ( where TA.source='zlat2' ) as zlat2,
sum(TA.accrued) as accrued
from(
select sum(TA.accrued) as accrued,
TA.date,
TA.redirect,
TA.source
from (select TA.result_for_the_day as accrued,
to_char(TA.date, 'yyyy-mm') as date,
TA.redirect,
TA.source
from total_accounts TA) TA
group by TA.redirect, TA.date, TA.source) TA
group by TA.redirect) TA
where FB.redirect=TA.redirect
i could not add it into comments cause it was too long essentialy you first run the insert into statement and then update it will only do inserts for redirects that are not added yet
select TA.redirect,
count(*) filter ( where TA.source='zlat1' ) as zlat1,
count(*) filter ( where TA.source='zlat2' ) as zlat2,
sum(TA.accrued)
from(
select sum(TA.accrued) as accrued,
TA.date,
TA.redirect,
TA.source
from (select TA.result_for_the_day as accrued,
to_char(TA.date, 'yyyy-mm') as date,
TA.redirect,
TA.source
from total_accounts TA) TA
group by TA.redirect, TA.date, TA.source) TA
group by TA.redirect
there you go thats the answer. giving back to comunity that i have taken :D

Combine different results of "group by" queries in the same table

I need to make some comparation between 2 years: sales by product, sales by category, etc.
How can I have this in one table having 3 columns:
first column = product, category, etc
second column = sales in 2021
third column = sales in 2022
Sample of queries that must be combined in one single table as the one below
select product_code, sum(amount)
from product
where year = '2021'
group by product_code
select product_code, sum(amount)
from product
where year = '2022'
group by product_code
select category_code, sum(amount)
from category
where year = '2021'
group by category_code
select category_code, sum(amount)
from category
where year = '2022'
group by category_code
Please, see the final table
[1]: https://i.stack.imgur.com/smF7h.png
NOTE!
If for instance in 2021 there was no "product D", it will be 0 for "Sales_2021" or the "product A" is no longer present in 2022, it will be 0 for "Sales_2022".
Thank you
You need two things here:
Conditional aggregation (a CASE expression inside the aggregation function) in order to get 2021 and 2022 in one go.
A union of two intermediate result sets (product figures UNION ALL category figures).
And as any table - and a query result is again a table - is unordered, we need an ORDER BY at last to get products first and categories second and also the products ordered alphabetically and the categories, too.
The complete query:
select category_or_product, sales_2021, sales_2022
from
(
select
product_code as category_or_product,
sum(case when year = 2021 then amount else 0 end) as sales_2021,
sum(case when year = 2021 then amount else 0 end) as sales_2022,
1 as product_first
from product
group by product_code
union all
select
category_code as category_or_product,
sum(case when year = 2021 then amount else 0 end) as sales_2021,
sum(case when year = 2021 then amount else 0 end) as sales_2022,
2 as product_first
from category
group by category_code
) unioned
order by product_first, category_or_product;

Group by in columns and rows, counts and percentages per day

I have a table that has data like following.
attr |time
----------------|--------------------------
abc |2018-08-06 10:17:25.282546
def |2018-08-06 10:17:25.325676
pqr |2018-08-05 10:17:25.366823
abc |2018-08-06 10:17:25.407941
def |2018-08-05 10:17:25.449249
I want to group them and count by attr column row wise and also create additional columns in to show their counts per day and percentages as shown below.
attr |day1_count| day1_%| day2_count| day2_%
----------------|----------|-------|-----------|-------
abc |2 |66.6% | 0 | 0.0%
def |1 |33.3% | 1 | 50.0%
pqr |0 |0.0% | 1 | 50.0%
I'm able to display one count by using group by but unable to find out how to even seperate them to multiple columns. I tried to generate day1 percentage with
SELECT attr, count(attr), count(attr) / sum(sub.day1_count) * 100 as percentage from (
SELECT attr, count(*) as day1_count FROM my_table WHERE DATEPART(week, time) = DATEPART(day, GETDate()) GROUP BY attr) as sub
GROUP BY attr;
But this also is not giving me correct answer, I'm getting all zeroes for percentage and count as 1. Any help is appreciated. I'm trying to do this in Redshift which follows postgresql syntax.
Let's nail the logic before presenting:
with CTE1 as
(
select attr, DATEPART(day, time) as theday, count(*) as thecount
from MyTable
)
, CTE2 as
(
select theday, sum(thecount) as daytotal
from CTE1
group by theday
)
select t1.attr, t1.theday, t1.thecount, t1.thecount/t2.daytotal as percentofday
from CTE1 t1
inner join CTE2 t2
on t1.theday = t2.theday
From here you can pivot to create a day by day if you feel the need
I am trying to enhance the query #johnHC btw if you needs for 7days then you have to those days in case when
with CTE1 as
(
select attr, time::date as theday, count(*) as thecount
from t group by attr,time::date
)
, CTE2 as
(
select theday, sum(thecount) as daytotal
from CTE1
group by theday
)
,
CTE3 as
(
select t1.attr, EXTRACT(DOW FROM t1.theday) as day_nmbr,t1.theday, t1.thecount, t1.thecount/t2.daytotal as percentofday
from CTE1 t1
inner join CTE2 t2
on t1.theday = t2.theday
)
select CTE3.attr,
max(case when day_nmbr=0 then CTE3.thecount end) as day1Cnt,
max(case when day_nmbr=0 then percentofday end) as day1,
max(case when day_nmbr=1 then CTE3.thecount end) as day2Cnt,
max( case when day_nmbr=1 then percentofday end) day2
from CTE3 group by CTE3.attr
http://sqlfiddle.com/#!17/54ace/20
In case that you have only 2 days:
http://sqlfiddle.com/#!17/3bdad/3 (days descending as in your example from left to right)
http://sqlfiddle.com/#!17/3bdad/5 (days ascending)
The main idea is already mentioned in the other answers. Instead of joining the CTEs for calculating the values I am using window functions which is a bit shorter and more readable I think. The pivot is done the same way.
SELECT
attr,
COALESCE(max(count) FILTER (WHERE day_number = 0), 0) as day1_count, -- D
COALESCE(max(percent) FILTER (WHERE day_number = 0), 0) as day1_percent,
COALESCE(max(count) FILTER (WHERE day_number = 1), 0) as day2_count,
COALESCE(max(percent) FILTER (WHERE day_number = 1), 0) as day2_percent
/*
Add more days here
*/
FROM(
SELECT *, (count::float/count_per_day)::decimal(5, 2) as percent -- C
FROM (
SELECT DISTINCT
attr,
MAX(time::date) OVER () - time::date as day_number, -- B
count(*) OVER (partition by time::date, attr) as count, -- A
count(*) OVER (partition by time::date) as count_per_day
FROM test_table
)s
)s
GROUP BY attr
ORDER BY attr
A counting the rows per day and counting the rows per day AND attr
B for more readability I convert the date into numbers. Here I take the difference between current date of the row and the maximum date available in the table. So I get a counter from 0 (first day) up to n - 1 (last day)
C calculating the percentage and rounding
D pivot by filter the day numbers. The COALESCE avoids the NULL values and switched them into 0. To add more days you can multiply these columns.
Edit: Made the day counter more flexible for more days; new SQL Fiddle
Basically, I see this as conditional aggregation. But you need to get an enumerator for the date for the pivoting. So:
SELECT attr,
COUNT(*) FILTER (WHERE day_number = 1) as day1_count,
COUNT(*) FILTER (WHERE day_number = 1) / cnt as day1_percent,
COUNT(*) FILTER (WHERE day_number = 2) as day2_count,
COUNT(*) FILTER (WHERE day_number = 2) / cnt as day2_percent
FROM (SELECT attr,
DENSE_RANK() OVER (ORDER BY time::date DESC) as day_number,
1.0 * COUNT(*) OVER (PARTITION BY attr) as cnt
FROM test_table
) s
GROUP BY attr, cnt
ORDER BY attr;
Here is a SQL Fiddle.

Bring through a newly created calculated column in another query

I have 2 separate queries below which run correctly.Now I've created a calculated column to provide a count of working days by YMs and would like to bring this through to query1(the join would be query1.Period = query2.Yms)
please see the query and outputs below.
SELECT Client, ClientGroup, Type, Value, Period, PeriodName, PeriodNumber, ClientName
FROM metrics.dbo.vw_KPI_001_Invoice
select YMs,sum(case when IsWorkDay = 'X' then 1 else 0 end) from IESAONLINE.Dbo.DS_Dates
where Year > '2013'
group by YMs
Query 1
Client ClientGroup Type Value Period PeriodName PeriodNumber ClientName
0LG0 KarroFoods Stock 5691.68 201506 Week 06 2015 35 Karro Foods Scunthorpe
Query 2
YMs (No column name)
201401 23
Would the following work:
SELECT Client, ClientGroup, Type, Value, Period, PeriodName, PeriodNumber, ClientName, cnt
FROM metrics.dbo.vw_KPI_001_Invoice q1
INNER JOIN (select YMs,sum(case when IsWorkDay = 'X' then 1 else 0 end) as cnt from IESAONLINE.Dbo.DS_Dates
where Year > '2013'
group by YMs ) q2 ON q1.Period = q2.YMs
If a value isn't always available then you might consider changing the INNER JOIN to an OUTER JOIN.