Summing Subquery - tsql

I'm trying to create a Query that sums up a sales amount from 52 weeks of data from the entities in this table.
I figured out how to get the past 52 weeks for the CYSales using the following query. The year and week will end up being parameters in the resultant report, so those values are arbitrary. I used the current year and week 40 just for this example.
SELECT [Group],[Owner],[SalesPersonNumber],SUM([tot_sls_amt]) AS CYSales
FROM TableA
WHERE ((Year = year(getdate()) AND Week <= 40) OR (Year = year(getdate()) - 1 AND Week > 40)) AND cmp_status = 'A'
Group BY [Group]
,[Owner]
,[SalesPersonNumber]
That gives me this
I'm now trying to get the PYSales amount in another calculated column, but when I add my subquery in I get an error
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
How do I fix the following query to give me the PYSales?
SELECT [Group]
,[Owner]
,[SalesPersonNumber]
,SUM([tot_sls_amt]) AS CYSales
,(SELECT SUM([tot_sls_amt])
FROM TableA
WHERE ((Year = year(getdate())-1 AND Week <= 40) OR (Year = year(getdate()) - 2 AND Week > 40)) AND cmp_status = 'A'
Group BY [Group] ,[Owner],[SalesPersonNumber]) AS PYSales
FROM TableA
WHERE ((Year = year(getdate()) AND Week <= 40) OR (Year = year(getdate()) - 1 AND Week > 40)) AND cmp_status = 'A'
Group BY [Group]
,[Owner]
,[SalesPersonNumber]

I would move your sub query and join it or use a cte.
i used a left join incase you have someone new that wont have data in py
didnt have data to test, let me know if something fails and i can revise.
SELECT
a.[Group]
,a.[Owner]
,a.[SalesPersonNumber]
,SUM(a.[tot_sls_amt]) AS CYSales
,(b.[tot_sls_amt]) AS PYSales
FROM
TableA a
Left Join
(SELECT sum([tot_sls_amt]) tot_sls_amt,[Group],[Owner] ,[SalesPersonNumber]
FROM TableA
WHERE ((Year = year(getdate())-1 AND Week <= 40) OR (Year = year(getdate()) - 2 AND Week > 40)) AND cmp_status = 'A'
group by [Group],[Owner] ,[SalesPersonNumber]) b on a.group = b.group and a.owner = b.owner and a.salespersonumber =b.salespersonnumber
WHERE
((Year = year(getdate()) AND Week <= 40) OR (Year = year(getdate()) - 1 AND Week > 40)) AND cmp_status = 'A'
Group BY
a.[Group]
,a.[Owner]
,a.[SalesPersonNumber]
,(b.[tot_sls_amt])

you are doing GROUP BY in the subquery, which will return sum for each pair of Group, Owner, SalesPersonNumber, which is same as your outer query.
in case you just need the Total accross the all values for given week and year, just do sum and use cross apply
SELECT [Group]
,[Owner]
,[SalesPersonNumber]
,SUM([tot_sls_amt]) AS CYSales,
T.total AS PYSales
FROM TableA
WHERE ((Year = year(getdate()) AND Week <= 40) OR (Year = year(getdate()) - 1 AND Week > 40)) AND cmp_status = 'A'
Group BY [Group]
,[Owner]
,[SalesPersonNumber]
CROSS APPLY (
SELECT SUM([tot_sls_amt]) as total
FROM TableA
WHERE ((Year = year(getdate())-1 AND Week <= 40) OR (Year = year(getdate()) - 2 AND Week > 40)) AND cmp_status = 'A'
) As T

Related

Postgresql how to get last year_month from previous year in where clause

I need to show how many active customers we had and the end of the year. Therefore I need to get always last year_month from the previous year. Working with PostgreSQL.
Here my SQL to get the customer base on monthly (year_month) view.
select *
from (
with data as (
select
a.brand,
a.d,
a.activations,
t.terminations,
a.activations-t.terminations count
from (select c.brand, dd.year_month d,
COALESCE(case when dd.year_month is not null then count(c.customer_number) else 0 end, 0) as activations
from generate_series(current_date - interval '8 years', current_date, '1 day') d
left join dim_date dd on dd."date" = d.d
left join r_contracts_report c on to_date(c.service_start_date, 'dd.mm.yyy') = d
where c.contract_status in ('aktiv', 'Kündigung vorgemerkt', 'gekündigt')
and c.contract in ('3048', '3049', '3050', '3055', '3056')
group by dd.year_month,
brand) a,
(select c.brand, dd.year_month d,
COALESCE(case when dd.year_month is not null then count(c.customer_number) else 0 end, 0) as terminations
from generate_series(current_date - interval '8 years', current_date, '1 day') d
left join dim_date dd on dd."date" = d.d
left join r_contracts_report c on to_date(c.termination_date, 'dd.mm.yyy') = d
where c.contract_status in ('aktiv', 'Kündigung vorgemerkt', 'gekündigt')
and c.contract in ('3048', '3049', '3050', '3055', '3056')
group by dd.year_month,
brand) t
where a.d = t.d
and a.brand = t.brand)
select
d.d year_month,
d.brand,
sum(count) over (order by d.d asc rows between unbounded preceding and current row) eop
from data d
where d.brand = '3'
) as foo
Using after "as foo" the following where clause I get the customer base for the last 12 months:
WHERE year_month >= to_char ((current_date - INTERVAL '12 months'), 'YYYY-MM')
And result looks like this:
But I always want to have only the December of the previous year. In this case it would be '2021-12'.
...
where year_month = '2021-12'
or automatically for the previous year:
...
where year_month = (extract(year from current_date) - 1)::text || '-12'
But this is a really inefficient way to get this data.

Subquery in 2 different time column

I tried this but it said that ERROR: subquery must return only one column
Select date_trunc('week', kyc.kyc_verify_date::timestamptz) as "week",
COUNT(*) filter (where kyc.status = 4) AS "A1",
COUNT(CASE WHEN kyc.status = 5
THEN
(Select date_trunc('week', kyc.last_update_time::timestamptz) AS "week",
count(*) filter (where kyc.status = 5)
From kyc
Group by 1)
END) AS "A2"
from KYC
Where kyc.kyc_verify_date >= date_trunc('week', CURRENT_TIMESTAMP - interval '4 week')
and kyc.kyc_verify_date < date_trunc('week', CURRENT_TIMESTAMP)
Group by 1
i do this query to get the result that if status = 4 will take the date is kyc_verify_date,
but if status = 5 will take the date is last_update_time
What should I have to change in this query? or is there any way better?
A case expression returns a single value. Since you need 2 values from it you will need to repeat the expression.

Moving grouped MEDIAN / Get the MEDIAN of specific months from the past IN T-SQL

Let's say I have a table:
DATE
ID
VALUE
01.2010
1
100
02.2010
1
200
...
...
...
12.2010
1
300
01.2011
1
150
02.2011
1
250
...
...
...
12.2011
1
350
01.2012
1
200
02.2012
1
300
...
...
...
12.2012
1
400
I want to get a median of VALUE grouped by months i.e. get something like
DATE
ID
VALUE
MEDIAN
01.2010
1
100
100
02.2010
1
200
200
...
...
...
...
12.2010
1
300
300
01.2011
1
150
125 = (100+150)/2
02.2011
1
250
225 = (200+250)/2
...
...
...
...
12.2011
1
350
325 = (300+350)/2
01.2012
1
200
150
02.2012
1
300
250
...
...
...
...
12.2012
1
400
350
I have more ID in table so I would like to get this result for every ID.
I have tried doing
SELECT PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY VALUE) OVER (PARTITION BY Id, MONTH(Date) ORDER BY Date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
but I get "The function 'PERCENTILE_CONT' may not have a window frame.
I've also tried the following (but also without any results):
SELECT PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY VALUE)
OVER (PARTITION BY Id, MONTH(Date))
FROM tab1 LEFT JOIN tab2
ON tab1.key = tab2.key
WHERE tab1.Date BETWEEN Min(Date) AND tab2.Date
EDIT
So far I have resolved it with
SELECT (CASE WHEN Date =2010 THEN PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY CASE WHEN Date = 2010 THEN VALUE ELSE NULL) OVER (PARTITION BY Id, MONTH(Date)) ELSE 0 END) +
(CASE WHEN Date =2011 THEN PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY CASE WHEN Date <= 2011 THEN VALUE ELSE NULL) OVER (PARTITION BY Id, MONTH(Date)) ELSE 0 END) +
(CASE WHEN Date =2012 THEN PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY CASE WHEN Date <= 2012 THEN VALUE ELSE NULL) OVER (PARTITION BY Id, MONTH(Date)) ELSE 0 END)
FROM tab1
But to be honest, I would like to have an resolution without assumption of a priori knowledge of dates. I've thought about WHILE LOOP and updating column while #MinYear <= #MaxYear where in every iteration #MinYear = #MinYear+1 but in this case I would have to create temporary tables which I'm trying to avoid.
My idea is to use (Value1+value2)/2 as median as your requirement is little complicated.
CREATE TABLE MedianData
(
[Date] VARCHAR(100)
,ID INT
,[Value] INT
)
INSERT INTO MedianData VALUES ('01.2010', 1, 100)
,('02.2010', 1, 200)
,('12.2010', 1, 300)
,('01.2011', 1, 150)
,('02.2011', 1, 250)
,('12.2011', 1, 350)
,('01.2012', 1, 200)
,('02.2012', 1, 300)
,('12.2012', 1, 400)
SELECT *
,ROW_NUMBER() OVER ( PARTITION BY Substring([Date],1,2 ) ORDER BY [Date] ) AS [row]
,Substring([Date],1,2 ) as [MONTH]
INTO #Temp_tbl2
FROM MedianData
SELECT
A.Date
,A.ID
,A.[Value]
--Logic is applied here. I used (Value1+value2)/2 as median
,CASE WHEN A.[row] = 3 THEN ( A.[Value] + ( SELECT T.[Value] FROM #Temp_tbl2
T where T.[MONTH] = Substring(A.[Date],1,2 ) AND T.[row] = 1 ) )/2
WHEN A.[row] != 1 THEN (A.total/2)
ELSE A.total END as [Median]
INTO #Temp_table
FROM
(
SELECT *
,ROW_NUMBER() OVER ( PARTITION BY Substring([Date],1,2 ) ORDER BY [Date] ) AS [row]
,SUM ([Value] ) OVER ( PARTITION BY Substring([Date],1,2 ) ORDER BY [Date] ) AS [total]
FROM MedianData
) AS A
--to make the table data order
SELECT MedianData.*, #Temp_table.Median
FROM MedianData
INNER JOIN #Temp_table
ON MedianData.[Date] = #Temp_table.[Date]
drop table #Temp_table
drop table #Temp_tbl2

how to count the buyer with special condition

so i have a table which contain data buyer who doing transaction per day in a month, so how do i get the buyer where the total transaction in a month >= 600k, this is my syntax
SELECT
b.buyer_id
FROM order_buyer b
WHERE
EXISTS (SELECT 1 FROM order_buyer d
WHERE d.buyer_id = b.buyer_id AND
d.createdAt >= '2017-10-01' AND d.createdAt < '2018-01-01') AND
EXISTS (SELECT 1 FROM order_buyer d
WHERE d.buyer_id = b.buyer_id AND
d.createdAt >= '2017-10-01' AND d.createdAt < '2018-01-01' ) AND
NOT EXISTS (SELECT 1 FROM order_buyer d
WHERE d.buyer_id = b.buyer_id AND d.createdAt < '2017-01-01') group by buyer_id;
A simple query using HAVING clause should work for you.
SELECT buyer_id, amount
FROM order_buyer
WHERE createdAt >= '2018-10-01'
AND createdAt < '2018-11-01'
GROUP BY buyer_id
HAVING SUM(amount) >= 600000;

Yearly total for items over multiple years

I am trying to find the total per year
For example
Start date End Date Total Value
1 07/01/14 01/01/15 $10,000
2 08/01/13 12/01/14 $10,000
3 03/01/13 05/01/15 $10,000
As you can see, Some items are over multiple years. Is there a way to find out what the total value is per year.
Solution should be:
item 3
2013- $3600
2014-$4800
2015-1600
Then a summation would be down for all three items to give a yearly total.
What I have so far:
I have a rolling summation code which is shown below.
case when
(
[begin date] >= dateadd(mm,0,DATEADD(mm,DATEDIFF(mm,0,getdate()),0))
and [end date] >= dateadd(mm,0,DATEADD(mm,DATEDIFF(mm,0,getdate()),0))
)
OR
(
[Begin Date] < dateadd(mm,0,DATEADD(mm,DATEDIFF(mm,0,getdate()),0))
and [End Date] >= dateadd(mm,0,DATEADD(mm,DATEDIFF(mm,0,getdate()),0))
)
then [Totalvalue]/nullif(DATEDIFF(mm,[begin date],[end date]),0)
else 0
end [Current Month]
I dono how you got that total values for item 3
but for item 3 i hope it should be
2013 = 3704
2014 = 4444
2015 = 1852
Dono how efficient this code is just have a try
CREATE TABLE #tblName
(
itemid INT,
startdate DATETIME,
endate DATETIME,
value int
)
INSERT INTO #tblName
VALUES (1,'2014/07/01','2015/01/01',10000),
(2,'2013/08/01','2014/12/01',10000),
(3,'2013/03/01','2015/05/01',10000)
DECLARE #mindate DATETIME,
#maxdate DATETIME
SELECT #mindate = Min(startdate),
#maxdate = Max(endate)
FROM #tblName
SELECT *
FROM #tblName;
WITH cte
AS (SELECT #mindate startdate
UNION ALL
SELECT Dateadd(mm, 1, startdate) startdate
FROM cte
WHERE startdate <= Dateadd(mm, -1, #maxdate))
SELECT a.value * ( ( convert(numeric(22,6),a.cnt) / convert(numeric(22,6),c.total) ) * 100 ) / 100,a.itemid,a.startdate
FROM (SELECT Avg(value) value,
Count(1) cnt,
itemid,
Year(a.startdate) startdate
FROM cte a
JOIN #tblName b
ON a.startdate BETWEEN b.startdate AND b.endate
GROUP BY itemid,
Year(a.startdate)) a
JOIN(SELECT Sum(cnt) total,
itemid
FROM (SELECT Avg(value) value,
Count(1) cnt,
itemid,
Year(a.startdate) startdate
FROM cte a
JOIN #tblName b
ON a.startdate BETWEEN b.startdate AND b.endate
GROUP BY itemid,
Year(a.startdate)) B
GROUP BY itemid) C
ON a.itemid = c.itemid
WHERE a.itemid = 3