SQL - Total Row Values Meeting Criteria - sql

I have a table and I want to sum rows that meet a certain criteria.
Table looks like this:
| Product | Sales_Num | Week | Cost | Retail |
|:------- |:---------:|:----:|:----:| ------:|
| PLA | 45281 | 38 | 53 | 88 |
| PLA2 | 45281 | 38 | 3 | 4 |
| CR25 | 45281 | 38 | 99 | 250 |
| BA34 | 45281 | 38 | 74 | 99 |
| PLA | 40251 | 38 | 53 | 75 |
| PLA2 | 40251 | 38 | 2 | 5 |
| CR25 | 40251 | 38 | 99 | 200 |
| BA34 | 40251 | 38 | 74 | 88 |
I want to Calculate the RETAIL column WHERE Product IN ('PLA','PLA2') AND Week = 38 and Sales_Num = 45281
Essentially, I want to Add 88 + 4 (first 2 rows above meet criteria). I want to eventually turn this into a function where I pass in Product, Week, and Sales_Num and I write the Calculation, Sales_Num, and Week to another table.
I was able to sum the rows I want, but I want the output to be [Sales_Num],[Week],[Total_Retail]
SELECT (
(SUM(CASE WHEN [Product]='PLA' AND [Sales_Num]=45281 AND [WEEK]=38 THEN [Retail] END) +
SUM(CASE WHEN [Product]='PLA2' AND [Sales_Num]=45281 AND [WEEK]=38 THEN [Retail] END)
)
) AS Total_Retail

select Sales_Num
,week
,sum(Retail) as Total_Retail
from t
where Week = 38
and Sales_Num = 45281
and Product in('PLA', 'PLA2')
group by Sales_Num, week
Sales_Num
week
Total_Retail
45281
38
92
Fiddle

SELECT Sales_Num, [Week], SUM(Retail) AS Total_Retail
FROM #yourtable
WHERE [Week] = 38
AND Sales_Num = 45281
AND Product IN ('PLA', 'PLA2')
GROUP BY Sales_Num, [Week]

Related

Rolling Sum using two columns in Power BI

I've two columns containing sales from last year and this year and a data column with the number of weeks we are in. I want to calculate a yearly rolling sum in a new column from the week we are in back in the past till that same week.
In my example if i'm in week 2 this year my rolling sum will be sum all the values of sales last year from week 2 til week 52 plus sales from this year until week 2 including!!
Here's an example in excel of what my table and results would look like:
Assuming your data look like this
Table
+------+----------+-------+
| week | sales_ly | sales |
+------+----------+-------+
| 1 | 65 | 100 |
+------+----------+-------+
| 2 | 93 | 130 |
+------+----------+-------+
| 3 | 83 | 134 |
+------+----------+-------+
| 4 | 3083 | 59 |
+------+----------+-------+
| 5 | 30984 | 39 |
+------+----------+-------+
| 6 | 38 | 580 |
+------+----------+-------+
| 7 | 28 | 94 |
+------+----------+-------+
| 8 | 48 | 93 |
+------+----------+-------+
| 9 | 24 | 984 |
+------+----------+-------+
| 10 | 49 | 95 |
+------+----------+-------+
You need to create two cumulatives and sum them in the same measure.
Rolling Sum =
VAR CurrentYearCumulative =
CALCULATE(
SUM('Table'[sales]),
FILTER(ALLSELECTED('Table'),'Table'[week] <= MAX('Table'[week] ) )
)
VAR LastYearCumulative =
CALCULATE(
SUM('Table'[sales_ly]),
FILTER(ALLSELECTED('Table'),'Table'[week] >= MAX('Table'[week]) )
)
RETURN
CurrentYearCumulative + LastYearCumulative
The output

Replace a missing value SQL Server?

There is a table (SQL Server 2017) on sales of goods in stores, some records have no price.
+---------+-------------+---------+----------+-------+
| year_id | week_number | good_id | store_id | price |
+---------+-------------+---------+----------+-------+
| 2019 | 6 | 140629 | 2 | 199 |
+---------+-------------+---------+----------+-------+
| 2019 | 8 | 140629 | 2 | NULL |
+---------+-------------+---------+----------+-------+
| 2017 | 40 | 137233 | 9 | 278 |
+---------+-------------+---------+----------+-------+
| 2017 | 35 | 137233 | 9 | NULL |
+---------+-------------+---------+----------+-------+
| 2017 | 37 | 137233 | 9 | NULL |
+---------+-------------+---------+----------+-------+
We would like to replace the missing values according to the following scheme: set the price value to the same as the good with this number (good_id) from the same store (store_id), but sold as far as possible in the nearest to the missing value date, for example:
+---------+-------------+---------+----------+-------+
| year_id | week_number | good_id | store_id | price |
+---------+-------------+---------+----------+-------+
| 2019 | 6 | 140629 | 2 | 199 |
+---------+-------------+---------+----------+-------+
| 2019 | 8 | 140629 | 2 | 199 |
+---------+-------------+---------+----------+-------+
| 2017 | 40 | 137233 | 9 | 278 |
+---------+-------------+---------+----------+-------+
| 2017 | 35 | 137233 | 9 | 278 |
+---------+-------------+---------+----------+-------+
| 2017 | 37 | 137233 | 9 | 278 |
+---------+-------------+---------+----------+-------+
So far made something like this, but this query contains mutually exclusive conditions, so it does not affect the rows:
UPDATE dataset
SET price = p.price
FROM dataset AS p
WHERE good_id = p.good_id
AND store_id = p.store_id
AND price IS NULL
AND p.price IS NOT NULL;
GO
You can use apply. This works if all years have 52 weeks:
update d
set price = d2.price
from dataset d cross apply
(select top (1) d2.*
from dataset d2
where d2.good_id = d.good_id and
d2.store_id = d.store_id and
d2.price is not null
order by abs( (d2.year_id * 52 + d2.week_id) - (d.year_id * 52 + d.week_id) )
) d2
where d.price is null;
The only issue is when the comparisons pass the year boundary and the previous year has 53 weeks. Depending on how you define years, you can convert the year/week combos in to dates and use direct date comparisons for the difference.

get records where one colum has values within range across records with same column names

with a table like below
+------+-----+------+----------+-----------+
| city | day | hour | car_name | car_count |
+------+-----+------+----------+-----------+
| 1 | 12 | 00 | corolla | 8 |
| 1 | 12 | 00 | city | 9 |
| 1 | 12 | 00 | amaze | 3 |
| 1 | 13 | 00 | corolla | 17 |
| 1 | 13 | 00 | city | 2 |
| 1 | 13 | 00 | amaze | 8 |
| 1 | 14 | 00 | corolla | 3 |
| 1 | 14 | 00 | amaze | 1 |
+------+-----+------+----------+-----------+
need to find out the city, day, hour where the car_count for all car_names is >= 3 and <= 10
expected result
| city | day | hour |
+------+-----+------+
| 1 | 12 | 00 |
Use group by and having.
select city,day,hour
from tablename
group by city,day,hour
having sum(case when car_count>=3 and car_count<=10 then 1 else 0 end) = count(*)
select city, day, hour
from t
group by 1, 2, 3
having bool_and(car_count >= 3)
You can group by on city, day and hour with the having condition sum(your condition) = count(your condition)
So basically we are creating a flag for each row which satisfies the condition "10 >= car_count >= 3" . Now we are summing all the flags and counting them simultaneously, if both the count and sum are equal that means your condition "10 >= car_count >= 3" was true for all the cars against city,day and hour
create table want as
select city,day,hour from have
group by city,day,hour
having sum(car_count>=3 and car_count<=10)=count(car_count>=3 and car_count<=10);
Please let me know in case of any queries.

Checking for Consecutive 12 Weeks of 0 Sales

I have a table with customer_number, week, and sales. I need to check if there were 12 consecutive weeks of no sales for each customer and create a flag of 0/1.
I can check the last 12 weeks or a certain time frame, but what's the best way to check for consecutive runs? Here is the code I have so far:
select * from weekly_sales
where customer_nbr in (123, 234)
and week < '2015-11-01'
and week > '2014-11-01'
order by customer_nbr, week
;
Sql Fiddle Demo
Here is a simplify version only need a week_id and sales
SELECT S1.weekid start_week, MAX(S2.weekid) end_week, SUM (S2.sales)
FROM Sales S1
JOIN Sales S2
ON S2.weekid BETWEEN S1.weekid and S1.weekid + 11
WHERE S1.weekid BETWEEN 1 and 25 -- your search range
GROUP BY S1.weekid
Let me know if that work for you
OUTPUT
| start_week | end_week | |
|------------|----------|----|
| 1 | 12 | 12 |
| 2 | 13 | 8 |
| 3 | 14 | 3 |
| 4 | 15 | 2 |
| 5 | 16 | 0 | <-
| 6 | 17 | 0 | <- no sales for 12 week
| 7 | 18 | 0 | <-
| 8 | 19 | 4 |
| 9 | 20 | 9 |
| 10 | 21 | 11 |
| 11 | 22 | 15 |
| 12 | 23 | 71 |
| 13 | 24 | 78 |
| 14 | 25 | 86 |
| 15 | 25 | 86 | < - less than 12 week range
| 16 | 25 | 86 | < - below this line
| 17 | 25 | 86 |
| 18 | 25 | 86 |
| 19 | 25 | 86 |
| 20 | 25 | 82 |
| 21 | 25 | 77 |
| 22 | 25 | 75 |
| 23 | 25 | 71 |
| 24 | 25 | 15 |
| 25 | 25 | 8 |
Your final query should have
HAVING SUM (S2.sales) = 0
AND COUNT(*) = 12
Ummmmm...You could use between 'week' and 'week', and you can use too the "count(column)" in order to improve performance.
So you only have to compare if result is bigger than 0

SQL Query to display % Change

I have a database with sample data represented by Table 1 below. How do I write an SQL query to display them in either Table 2 or Table 3 format?
Table 1 Table 2
Date | Value Year | Week | Total Value | % Change
------------+------- ------+-----+--|---------------|----------
19/12/2011 | 60 2012 | 1 | 295 | 656.41%
20/12/2011 | 49 2012 | 0 | 39 | -80.98%
21/12/2011 | 42 2012 | 52 | 205 | -41.76%
22/12/2011 | 57 2011 | 51 | 352 |
23/12/2011 | 88
24/12/2011 | 18 Table 3
25/12/2011 | 38 Year | Week | SUM1 | Year | Week | SUM2 | % Change
26/12/2011 | 16 ------+--------+--------+--------+--------+--------+-----------
27/12/2011 | 66 2012 | 1 | 295 | 2012 | 0 | 39 | 656.41%
28/12/2011 | 21 2012 | 0 | 39 | 2011 | 52 | 205 | -80.98%
29/12/2011 | 79 2011 | 52 | 205 | 2011 | 51 | 352 | -41.76%
30/12/2011 | 7 2011 | 51 | 352 |
31/12/2011 | 16
01/01/2012 | 39
02/01/2012 | 17
03/01/2012 | 86
04/01/2012 | 55
05/01/2012 | 82
06/01/2012 | 0
07/01/2012 | 9
08/01/2012 | 46
My preference would be to run 1 query to aggregate Table 1 to the year/week level and then do the "% change" in another language, depending on your environment. However, if you truly needed a SQL-only solution, you could do something like this.
create table t1 as
select year(Date) as year, week(Date) as week, sum(Value) as totalvalue
from table1
group by year(Date) as year, week(Date) as week
order by Date desc
;
select a.year, a.month, a.totalvalue,
(a.totalvalue-b.totalvalue)/b.totalvalue as pct_change
from (
select year, month, totalvalue,
case when week>1 then week-1 else 52 end as prevweek,
case when week>1 then year else year-1 end as prevyear
from t1
) a
left outer join t1 b
on a.prevweek=b.week and a.prevyear =b.year
;