How to combine two queries - sql

I have two queries
1)
select Year , Month, Sum(Stores) from ABC ;
2)
select Year, Month , Sum(SalesStores) from DEF ;
I want a result like :
**Year, Month , Sum(Stores), Sum(SalesStores)**
How can I do it ?
I tried union & Union all
select Year , Month, Sum(Stores) from ABC union
select Year, Month , Sum(SalesStores) from DEF ;
I see only 3 columns in the output
Year, Month Sum(Stores).
Here are the tables :
Year, Month Stores
Year Month SalesStores
Is there a way I can see the result in the format I would like to see ?

Since I don't know their relationship, I prefer to use UNION ALL.
SELECT Year,
Month,
MAX(TotalStores) TotalStores,
MAX(TotalSalesStores) TotalSalesStores
FROM
(
SELECT Year, Month,
SUM(Stores) TotalStores,
NULL TotalSalesStores
FROM ABC
UNION ALL
SELECT Year, Month,
NULL TotalStores,
SUM(SalesStores) TotalSalesStores
from DEF
) a
GROUP BY Year, Month

You can UNION them in the following fashion:
SELECT Year , Month, Sum(Stores) As Stores, NULL As SalesStores from ABC
UNION
SELECT Year , Month, NULL As Stores, Sum(Stores) As SalesStores from ABC
Or use UNION ALL if your logic allows it.

Try:
SELECT Year, Month, SUM(TotalStores) as TotalAllStores, SUM(TotalSalesStore) as TotalAllSalesStore
FROM
(
SELECT Year , Month, Sum(Stores) as TotalStores, 0 as TotalSalesStore from ABC union
UNION ALL
SELECT Year, Month , 0 as TotalStores, Sum(SalesStores) as TotalSalesStore from DEF
) SalesByYearMonth
GROUP BY Year, Month

I would use FULL OUTER JOIN thus:
SELECT ISNULL(x.[Year], y.[Year]) AS [Year],
ISNULL(x.[Month], y.[Month]) AS [Month],
x.Sum_Stores,
y.Sum_SalesStores
FROM (select Year , Month, Sum(Stores) AS Sum_Stores from ABC ...) AS x
FULL OUTER JOIN (select Year, Month , Sum(SalesStores) AS Sum_SalesStores from DEF ...) AS y
ON x.[Year] = y.[Year] AND x.[Month] = y.[Month]

Related

Calculate Revenue Recognition Per Month in Oracle SQL

I have a table with the order lines which show the Booking Amount and the booked date, but the revenue is recognised over 3 months (so 1/3 in the booked month and a further 1/3 in each of the next 2 months).
I need to create a query that would show the total revenue recognised in each month.
Is there an analytic function that could work this out? as at the moment I have cobbled together 3 joined queries that give the number but in 3 seperate columns, where I need it in one column:
select TRUNC(OM.BOOKING_DATE, 'MONTH') as Month
, SUM(OM.BOOKED_VALUE)/3 as Month_1
, M2.Month_2
, M3.Month_3
from ORDERS.OM,
(select TRUNC(ADD_MONTHS(OM.BOOKING_DATE,1), 'MONTH') as Month
, SUM(OM.BOOKED_VALUE)/3 as Month_2
from ORDERS.OM
GROUP By TRUNC(ADD_MONTHS(OM.BOOKING_DATE,1), 'MONTH')) M2,
(select TRUNC(ADD_MONTHS(OM.BOOKING_DATE,2), 'MONTH') as Month
, SUM(OM.BOOKED_VALUE)/3 as Month_3
from ORDERS.OM
GROUP By TRUNC(ADD_MONTHS(OM.BOOKING_DATE,2), 'MONTH')) M3
WHERE TRUNC(OM.BOOKING_DATE, 'MONTH') = M2.MONTH
AND TRUNC(OM.BOOKING_DATE, 'MONTH') = M3.MONTH
GROUP By TRUNC(OM.BOOKING_DATE, 'MONTH'), M2.Month_2, M3.Month_3
Order by 1 DESC
Triple every row and sum
select t.Month, SUM(t.Val) as Value
from ORDERS.OM
cross join lateral (select TRUNC(OM.BOOKING_DATE, 'MONTH') as Month, OM.BOOKED_VALUE/3.0 as Val from dual union all
select TRUNC(ADD_MONTHS(OM.BOOKING_DATE,1), 'MONTH'), OM.BOOKED_VALUE/3.0 from dual union all
select TRUNC(ADD_MONTHS(OM.BOOKING_DATE,2), 'MONTH'), OM.BOOKED_VALUE/3.0 from dual ) t
group by t.Month

Last 10 weeks in SQL Server

I'm using a Procedure that returns the turnover of the stores by weeks:
https://i.ibb.co/N3sP2Jp/1.png
I want just the last 10 weeks, from current week.
And the same for the previous year.
SELECT
DATENAME(WEEK, [GP_DATEPIECE]) AS [WEEK],
[et_libelle] AS [STORE NAME],
SUM(TOTALTTC) AS [TU],
SUM(TOTALTTC) AS [TU -1],
GROUP BY
[et_libelle],
DATENAME(WEEK, [GP_DATEPIECE])
THIS ANSWER THE ORIGINAL VERSION OF THE QUESTION.
To get the last 10 weeks in the data, you can do:
where datepiece >= dateadd(week, datediff(week, 0, getdate()) - 10, 0)
I have updated the script as per your requirement and I hope we are now so close to your requirement now. The output from the below query is a raw rows for your data comparison. You can now apply aggregation on your result set by applying GROUP by on YR (for whole years data comparison) and even you can add WK number in GROUP by so that you can compare data between Year and Week wise.
Note: As I applied ISO_Week, Week Starts at Monday and Ends at Sunday.
WITH CTE (COMMON,DayMinus)
AS
(
SELECT 1,0 UNION ALL
SELECT 1,1 UNION ALL
SELECT 1,2 UNION ALL
SELECT 1,3 UNION ALL
SELECT 1,4 UNION ALL
SELECT 1,5 UNION ALL
SELECT 1,6 UNION ALL
SELECT 1,7 UNION ALL
SELECT 1,8 UNION ALL
SELECT 1,9
)
SELECT YEAR(your_date_column) YR,
DATEPART(ISO_WEEK, your_date_column) WK,
*
FROM your_table
WHERE YEAR(your_date_column) IN (2019,2018)
AND DATEPART(ISO_WEEK, your_date_column) IN
(
SELECT A.WKNUM-CTE.DayMinus AS [WEEK NUMBER]
FROM CTE
INNER JOIN (
SELECT 1 AS COMMON,DATENAME(ISO_WEEK,GETDATE()) WKNUM
) A ON CTE.COMMON = A.COMMON
)

Fill missing months in a SELECT query

I'm trying to fill missing months in a SELECT query.
It looks like this :
SELECT sl.loonperiode_dt, (sum(slr.uren)) code_220
FROM HR.soc_loonbrief_regels slr,
HR.soc_loonbrieven sl,
HR.werknemers w,
HR.v_kontrakten vk
WHERE sl.loonperiode_dt BETWEEN '01012018' AND '01122018'
AND slr.loon_code_id IN (394)
AND slr.loonbrief_id = sl.loonbrief_id
AND w.werknemer_id = sl.werknemer_id
AND w.werknemer_id = vk.werknemer_id
AND vk.functie_id IN (121, 122, 128)
AND sl.loonperiode_dt BETWEEN hist_start_dt AND last_day(nvl(hist_eind_dt, sl.loonperiode_dt))
AND w.afdeling_id like '961'
GROUP BY sl.loonperiode_dt
ORDER BY sl.loonperiode_dt
It outputs this table :
31/01/18 234
30/04/18 245,8
31/05/18 714,6
31/07/18 288,04
31/08/18 281
30/11/18 515,12
I obviously would like it to be like that :
31/01/18 234
28/02/18 0
31/03/18 0
30/04/18 245,8
31/05/18 714,6
30/06/18 0
31/07/18 288,04
31/08/18 281
30/09/18 0
31/10/18 0
30/11/18 515,12
31/12/18 0
I have a calendar table 'CONV_HC.calendar' with dates in a column named 'DAT'.
I have seen many questions and answers about this, but I can't figure out how to apply the LEFT JOIN method or any other one to my current problem.
Thanks a lot in advance,
You could have a already done table with months and "join" with it, group by the date, or you can create one with subquery or using a with statement, something like
WITH Months (month) AS (
SELECT 1 AS Month FROM DUAL
UNION ALL
SELECT MONTH + 1
FROM Months
WHERE MONTH < 12
)
SELECT *
FROM Months
LEFT JOIN SomeTable
ON SomeTable.month = Months.MONTH
--ON Extract(MONTH FROM SomeTable.date) = Months.MONTH
edit
A better example:
--Just to simulate some table data
WITH SomeData AS (
SELECT TO_DATE('01/01/2019', 'MM/DD/YYYY') AS Dat, 5 AS Value FROM dual
UNION ALL
SELECT TO_DATE('01/05/2019', 'MM/DD/YYYY') AS Dat, 7 AS Value FROM dual
UNION ALL
SELECT TO_DATE('03/03/2019', 'MM/DD/YYYY') AS Dat, 2 AS Value FROM dual
UNION ALL
SELECT TO_DATE('11/05/2019', 'MM/DD/YYYY') AS Dat, 9 AS Value FROM dual
)
, Months (StartDate, MaxYear) AS (
SELECT CAST(TO_DATE('01/01/2019', 'MM/DD/YYYY') AS DATE) AS StartDate, 2019 AS MaxYear FROM DUAL
UNION ALL
SELECT CAST(ADD_MONTHS(StartDate, 1) AS DATE), MaxYear
FROM Months
WHERE EXTRACT(YEAR FROM ADD_MONTHS(StartDate, 1)) <= MaxYear
)
SELECT
Months.StartDate AS Dat
, SUM(SomeData.Value) AS SumValue
FROM Months
LEFT JOIN SomeData
ON Extract(MONTH FROM SomeData.Dat) = Extract(MONTH FROM Months.StartDate)
GROUP BY
Months.StartDate
edit
You won't find a just copy past solution, you need to get the idea from it and change to your context.
let's try this. You can "add" the missing months in an APP, or you can JOIN it with a already done table, doesn't need to be a real table, you can make one. The with statement is an example of it. So lets get all month, at the last day for 2019:
--Geting the last day of every month for 2019
WITH Months (CurrentMonth, MaxYear) AS (
SELECT CAST(TO_DATE('01/01/2019', 'MM/DD/YYYY') AS DATE) AS CurrentMonth, 2019 AS MaxYear FROM DUAL
UNION ALL
SELECT CAST(ADD_MONTHS(CurrentMonth, 1) AS DATE), MaxYear
FROM Months
WHERE EXTRACT(YEAR FROM ADD_MONTHS(CurrentMonth, 1)) <= MaxYear
)
SELECT LAST_DAY(Months.CurrentMonth) AS LastDay
FROM Months
Ok, now we have all months avaliable for the join. In your query, you already have the sum done so lets skip the sum and just use your data. Just add another with query.
--Geting the last day of every month for 2018
WITH Months (CurrentMonth, MaxYear) AS (
SELECT CAST(TO_DATE('01/01/2018', 'MM/DD/YYYY') AS DATE) AS CurrentMonth, 2018 AS MaxYear FROM DUAL
UNION ALL
SELECT CAST(ADD_MONTHS(CurrentMonth, 1) AS DATE), MaxYear
FROM Months
WHERE EXTRACT(YEAR FROM ADD_MONTHS(CurrentMonth, 1)) <= MaxYear
)
, YourData as (
SELECT sl.loonperiode_dt, (sum(slr.uren)) code_220
FROM HR.soc_loonbrief_regels slr,
HR.soc_loonbrieven sl,
HR.werknemers w,
HR.v_kontrakten vk
WHERE sl.loonperiode_dt BETWEEN '01012018' AND '01122018'
AND slr.loon_code_id IN (394)
AND slr.loonbrief_id = sl.loonbrief_id
AND w.werknemer_id = sl.werknemer_id
AND w.werknemer_id = vk.werknemer_id
AND vk.functie_id IN (121, 122, 128)
AND sl.loonperiode_dt BETWEEN hist_start_dt AND last_day(nvl(hist_eind_dt, sl.loonperiode_dt))
AND w.afdeling_id like '961'
GROUP BY sl.loonperiode_dt
--ORDER BY sl.loonperiode_dt
)
SELECT
LAST_DAY(Months.CurrentMonth) AS LastDay
, COALESCE(YourData.code_220, 0) AS code_220
FROM Months
Left Join YourData
on Extract(MONTH FROM Months.CurrentMonth) = Extract(MONTH FROM YourData.loonperiode_dt)
--If you have more years: AND Extract(YEAR FROM Months.CurrentMonth) = Extract(YEAR FROM YourData.loonperiode_dt)
ORDER BY LastDay ASC

How can I count users in a month that were not present in the month before?

I am trying to count unique users on a monthly basis that were not present in the previous month. So if a user has a record for January and then another one for February, then I would only count January for that user.
user_id time
a1 1/2/17
a1 2/10/17
a2 2/18/17
a4 2/5/17
a5 3/25/17
My results should look like this
Month User Count
January 1
February 2
March 1
I'm not really familiar with BigQuery, but here's how I would solve the problem using TSQL. I imagine that you'd be able to use similar logic in BigQuery.
1). Order the data by user_id first, and then time. In TSQL, you can accomplish this with the following and store it in a common table expression, which you will query in the step after this.
;WITH cte AS
(
select ROW_NUMBER() OVER (PARTITION BY [user_id] ORDER BY [time]) AS rn,*
from dbo.employees
)
2). Next query for only the rows with rn = 1 (the first occurrence for a particular user) and group by the month.
select DATENAME(month, [time]) AS [Month], count(*) AS user_count
from cte
where rn = 1
group by DATENAME(month, [time])
This is assuming that 2017 is the only year you're dealing with. If you're dealing with more than one year, you probably want step #2 to look something like this:
select year([time]) as [year], DATENAME(month, [time]) AS [month],
count(*) AS user_count
from cte
where rn = 1
group by year([time]), DATENAME(month, [time])
First aggregate by the user id and the month. Then use lag() to see if the user was present in the previous month:
with du as (
select date_trunc(time, month) as yyyymm, user_id
from t
group by date_trunc(time, month)
)
select yyyymm, count(*)
from (select du.*,
lag(yyyymm) over (partition by user_id order by yyyymm) as prev_yyyymm
from du
) du
where prev_yyyymm is not null or
prev_yyyymm < date_add(yyyymm, interval 1 month)
group by yyyymm;
Note: This uses the date functions, but similar functions exist for timestamp.
The way I understood question is - to exclude user to be counted in given month only if same user presented in previous month. But if same user present in few months before given, but not in previous - user should be counted.
If this is correct - Try below for BigQuery Standard SQL
#standardSQL
SELECT Year, Month, COUNT(DISTINCT user_id) AS User_Count
FROM (
SELECT *,
DATE_DIFF(time, LAG(time) OVER(PARTITION BY user_id ORDER BY time), MONTH) AS flag
FROM (
SELECT
user_id,
DATE_TRUNC(PARSE_DATE('%x', time), MONTH) AS time,
EXTRACT(YEAR FROM PARSE_DATE('%x', time)) AS Year,
FORMAT_DATE('%B', PARSE_DATE('%x', time)) AS Month
FROM yourTable
GROUP BY 1, 2, 3, 4
)
)
WHERE IFNULL(flag, 0) <> 1
GROUP BY Year, Month, time
ORDER BY time
you can test / play with above using below example with dummy data from your question
#standardSQL
WITH yourTable AS (
SELECT 'a1' AS user_id, '1/2/17' AS time UNION ALL
SELECT 'a1', '2/10/17' UNION ALL
SELECT 'a2', '2/18/17' UNION ALL
SELECT 'a4', '2/5/17' UNION ALL
SELECT 'a5', '3/25/17'
)
SELECT Year, Month, COUNT(DISTINCT user_id) AS User_Count
FROM (
SELECT *,
DATE_DIFF(time, LAG(time) OVER(PARTITION BY user_id ORDER BY time), MONTH) AS flag
FROM (
SELECT
user_id,
DATE_TRUNC(PARSE_DATE('%x', time), MONTH) AS time,
EXTRACT(YEAR FROM PARSE_DATE('%x', time)) AS Year,
FORMAT_DATE('%B', PARSE_DATE('%x', time)) AS Month
FROM yourTable
GROUP BY 1, 2, 3, 4
)
)
WHERE IFNULL(flag, 0) <> 1
GROUP BY Year, Month, time
ORDER BY time
The output is
Year Month User_Count
2017 January 1
2017 February 2
2017 March 1
Try this query:
SELECT
t1.d,
count(DISTINCT t1.user_id)
FROM
(
SELECT
EXTRACT(MONTH FROM time) AS d,
--EXTRACT(MONTH FROM time)-1 AS d2,
user_id
FROM nbitra.tmp
) t1
LEFT JOIN
(
SELECT
EXTRACT(MONTH FROM time) AS d,
user_id
FROM nbitra.tmp
) t2
ON t1.d = t2.d+1
WHERE
(
t1.user_id <> t2.user_id --User is in previous month
OR t2.user_id IS NULL --To handle january, since there is no previous month to compare to
)
GROUP BY t1.d;

Multiple SELECT in oracle

I want to get a particular value from 3 different tables. Each table has the same structure but contains data for a different period of a year.
Temp_Table_Jun (Contains data for June month)
---------------
CustNo CustName Revenue
1000 John 5.55
Similary I have two more tables
Temp_table_Apr
Temp_table_May
Now I run a query
select sum(Revenue)Rev_June from Temp_Table_Jun where CustNo='1000'
to get the results for June. Now my problem is I want to get the revenue details for all the month in a single query.
I need something like,(THIS IS WRONG AND DOESN'T WORK)
select Rev_June,Rev_Apr,Rev_May,((Rev_June+Rev_Apr+Rev_May)/3)Avg_3_Mon from
(
select sum(Revenue)Rev_June from Temp_Table_Jun where CustNo='1000',
select sum(Revenue)Rev_Apr from Temp_Table_Apr where CustNo='1000',
select sum(Revenue)Rev_May from Temp_Table_May where CustNo='1000'
)
How can this be achieved? I am using Oracle 10g.
To get the data you can do it the following way. Oracle 10g does not have a PIVOT but you can use CASE statements to replicate the functionality:
SELECT sum(case when month = 'June' then Rev END) June
, sum(case when month = 'May' then Rev END) May
, sum(case when month = 'April' then Rev END) April
, avg(Rev) as Average
FROM
(
SELECT sum(revenue) Rev, 'June' as Month from rev_june where cust_no = '1000'
union all
SELECT sum(revenue) Rev, 'April' from rev_apr where cust_no = '1000'
union all
SELECT sum(revenue) Rev, 'May' from rev_may where cust_no = '1000'
) x
See SQL Fiddle with Demo
Or you can do the following:
SELECT June, April, May, (June + April + May)/3 as Average
FROM
(
select
(SELECT sum(revenue) from rev_june where cust_no = '1000') as June
, (SELECT sum(revenue) from rev_apr where cust_no = '1000') as April
, (SELECT sum(revenue) from rev_may where cust_no = '1000') as May
from dual
) x
See SQL Fiddle with Demo
The following might work:
select Rev_June, Rev_Apr, Rev_May,
(Rev_June + Rev_Apr + Rev_May) / 3 Avg_3_Mon
from (
(select sum(Revenue) from Temp_Table_Jun where CustNo='1000') as Rev_June,
(select sum(Revenue) from Temp_Table_Apr where CustNo='1000') as Rev_Apr,
(select sum(Revenue) from Temp_Table_May where CustNo='1000') as Rev_May
from dual
)
I don't know if it works in Oracle 10g, but a UNION query roughly like the following would normally work in databases I've worked with:
select sum(Revenue) Rev_June from Temp_Table_Jun where CustNo='1000'
UNION
select sum(Revenue) Rev_Apr from Temp_Table_Apr where CustNo='1000'
UNION
select sum(Revenue) Rev_May from Temp_Table_May where CustNo='1000'
I'm not crysal clear about punctuation - do you need a semi-colon at the end etc? - but that might get you started.
I think I would do it slightly differently because each query must have the same structure for a UNION query to work:
select sum(Revenue) Revenue_Sum, 'Jun' Month from Temp_Table_Jun where CustNo='1000'
UNION
select sum(Revenue) Revenue_Sum, 'Apr' Month from Temp_Table_Apr where CustNo='1000'
UNION
select sum(Revenue) Revenue_Sum, 'May' Month from Temp_Table_May where CustNo='1000'
Now, that doesn't quite get the average sum and the 3 columns you're looking for, but perhaps you could create a VIEW with something like this UNION query and then use a GROUP BY query on that VIEW to aggregate the data.