SQL for begin and end of data rows - sql

I've got the following table:
and I was wondering if there is an SQL query, which would give me the begin and end Calender week (CW), where the value is greater than 0.
So in the case of the table above, a result like below:
Thanks in advance!

You can assign a group by counting the number of zeros and then aggregating:
select article_nr, min(year), max(year)
from (select t.*,
sum(case when amount = 0 then 1 else 0 end) over (partition by article_nr order by year) as grp
from t
) t
where amount > 0
group by article_nr, grp;

select Atricle_Nr, min(Year&CW) as 'Begin(Year&CW)',max(Year&CW) as 'End(Year&CW)'
from table where Amount>0 group by Atricle_Nr;

Related

CASE WHEN condition with MAX() function

There are a lot questions on CASE WHEN topic, but the closest my question is related to this How to use CASE WHEN condition with MAX() function query which has not been resolved.
Here is some of my sample data:
date
debet
2022-07-15
57190.33
2022-07-14
815616516.00
2022-07-15
40866.67
2022-07-14
1221510.00
So, I want to all records for the last two dates and three additional columns: sum(sales) for the previous day, sum for the current day and the difference between them:
SELECT
[debet],
[date] ,
SUM( CASE WHEN [date] = MAX(date) THEN [debet] ELSE 0 END ) AS sum_act,
SUM( CASE WHEN [date] = MAX(date) - 1 THEN [debet] ELSE 0 END ) AS sum_prev ,
(
SUM( CASE WHEN [date] = MAX(date) THEN [debet] ELSE 0 END )
-
SUM( CASE WHEN [date] = MAX(date) - 1 THEN [debet] ELSE 0 END )
) AS diff
FROM
Table
WHERE
[date] = ( SELECT MAX(date) FROM Table WHERE date < ( SELECT MAX(date) FROM Table) )
OR
[date] = ( SELECT MAX(date) FROM Table WHERE date = ( SELECT MAX(date) FROM Table ) )
GROUP BY
[date],
[debet]
Further, of course, it informs that I can't use the aggregate function inside CASE WHEN. Now I use this combination: sum(CASE WHEN [date] = dateadd(dd,-3,cast(getdate() as date)) THEN [debet] ELSE 0 END). But here every time I need to make an adjustment for weekends and holidays. The question is, is there any other way than using 'getdate' in 'case when' Statement to get max date?
Expected result:
date
sum_act
sum_prev
diff
2022-07-15
97190.33
0.00
97190.33
2022-07-14
0.00
508769.96
-508769.96
You can use dense_rank() to filter the last 2 dates in your table. After that you can use either conditional case expression with sum() to calculate the required value
select [date],
sum_act = sum(case when rn = 1 then [debet] else 0 end),
sum_prev = sum(case when rn = 2 then [debet] else 0 end),
diff = sum(case when rn = 1 then [debet] else 0 end)
- sum(case when rn = 2 then [debet] else 0 end)
from
(
select *, rn = dense_rank() over (order by [date] desc)
from tbl
) t
where rn <= 2
group by [date]
db<>fiddle demo
Two steps:
Get the sums for the last three dates
Show the results for the last two dates.
Well, we could also get all daily sums in step 1, but we just need the last three in order to calculate the sums for the last two days, so why aggregate more data than necessary?
Here is the query. You may have to put the date column name in brackets in SQL Server, as date is a keyword in SQL.
select top(2)
date,
sum_debit_current,
sum_debit_previous,
sum_debit_current - sum_debit_previous as diff
(
select
date,
sum(debet) as sum_debit_current,
lag(sum(debet)) over (order by date) as sum_debit_previous
from table
where date in (select distinct top(3) date from table order by date desc)
group by date
)
order by date desc;
(SQL Server uses TOP(n) instead of standard SQL FETCH FIRST 3 ROWS and while SELECT DISTINCT TOP(3) date looks like "get the top 3 rows, then apply distinct on their date", it is really "apply distinct on the dates, then get the top 3" like in standard SQL.)

SQL: create if condition for grouped variables

I have a table with 4 columns and need to create a newcolumn, which represents that if for the following year's quarter exists at least one data='colour', so for this quarter all values are changed to 'colour. How to do it?
You can use condition and get count of no for each quarter as follows:
select t.*,
case when count(case when data = 'no' then 1 end)
over (partition by year, quarter) > 0
then 'nocolour'
else data
end as new_column
from your_table t
You can use window functions:
select t.*,
min(data) over(partition by year, quarter) as new_column
from mytable t
If there is any 'no' for a given quarter, new_column takes value 'no' for all rows of the quarter. This works because string-wise, 'no' < 'yes'.
Assuming that you really mean "has data = 'yes' and the next quarter and you want to update the table, you can use:
update t
set newcolumn = (case when next_max_data = 'yes' then 'colour' else 'no colour')
from t join
(select year, quarter,
lead(max(data)) over (order by year, quarter) as next_max_data
from t
group by year, quarter
) tt
on t.year = tt.year and t.quater = tt.quarter;
If you want the the quarter a year later, you would use lead(max(data), 4) in the subquery.

Conditional CASE WHEN select snowflake SQL

I am stuck on a conditional snowflake select sql. I am trying to count the IDs when they have the corresponding categorial value. I would appreciate some help.
Thanks
SELECT
YEAR(DATETIME) AS YEAR,
WEEKOVERYEAR(DATETIME) AS WEEK,
COUNT(CASE WHEN ID THEN CATEGORY = 'A')
from table
group by week, year;
Here is one method:
SELECT YEAR(DATETIME) AS YEAR,
WEEKOVERYEAR(DATETIME) AS WEEK,
SUM(CASE WHEN CATEGORY = 'A' THEN 1 ELSE 0 END) as num_a
FROM table
GROUP BY week, year;
Snowflake supports COUNT_IF:
Returns the number of records that satisfy a condition.
Aggregate function
COUNT_IF( <condition> )
SELECT YEAR(DATETIME) AS YEAR,
WEEKOVERYEAR(DATETIME) AS WEEK,
COUNT_IF(CATEGORY = 'A') AS num_a
FROM tab
GROUP BY week, year;
You should / can use IFF() since case when is more suitable when there are multiple conditions.
SELECT
YEAR(DATETIME) AS YEAR,
WEEKOVERYEAR(DATETIME) AS WEEK,
COUNT(IFF(CATEGORY = 'A',ID,NULL)) as count
from table
group by week, year;
COUNT() counts the number of rows that are not null.
If you are want when ID is not null AND CATEGORY = 'A' then
COUNT(CASE WHEN ID IS NOT NULL AND CATEGORY = 'A' THEN TRUE ELSE NULL END)
will give you that, or you can use a SUM like in Gordon's answer
SUM(CASE WHEN ID IS NOT NULL AND CATEGORY = 'A' THEN 1 ELSE 0 END)
or you can use the snowflake IFF as a shorter form for the same thing, which is how I do it
SUM( IFF( ID IS NOT NULL AND CATEGORY = 'A', 1, 0))

MSSQL Group by and Select rows from grouping

I'm trying to figure out if what I'm trying to do is possible. Instead of resorting to multiple queries on a table, I wanted to group the records by business date and id then group by the id and select one date for a field and another date for the other field.
SELECT
*
{AMOUNT FROM DATE}
{AMOUNT FROM OTHER DATE}
FROM (
SELECT
date,
id,
SUM(amount) AS amount
FROM
table
GROUP BY id, date
AS subquery
GROUP BY id
It seems that you're looking to do a pivot query. I usually use cross tabs for this. Based on the query you posted, it could look like:
SELECT
id,
SUM(CASE WHEN date = '20190901' THEN amount ELSE 0 END) AmountFromSept01,
SUM(CASE WHEN date = '20191001' THEN amount ELSE 0 END) AmountFromOct01
FROM (
SELECT
date,
id,
SUM(amount) AS amount
FROM
table
GROUP BY id, date
)AS subquery
GROUP BY id;
You could also use a CTE.
WITH CTE AS(
SELECT
date,
id,
SUM(amount) AS amount
FROM
table
GROUP BY id, date
)
SELECT
id,
SUM(CASE WHEN date = '20190901' THEN amount ELSE 0 END) AmountFromSept01,
SUM(CASE WHEN date = '20191001' THEN amount ELSE 0 END) AmountFromOct01
FROM CTE
GROUP BY id;
Or even be a rebel and do the operation directly.
SELECT
id,
SUM(CASE WHEN date = '20190901' THEN amount ELSE 0 END) AmountFromSept01,
SUM(CASE WHEN date = '20191001' THEN amount ELSE 0 END) AmountFromOct01
FROM CTE
GROUP BY id;
However, some people have tested for performance and found that pre-aggregating can improve performance.
If I understand you correctly, then you're just trying to pivot, but only with two particular dates:
select id,
date1 = sum(iif(date = '2000-01-01', amount, null)),
date2 = sum(iif(date = '2000-01-02', amount, null))
from [table]
group by id

SQL find consecutive days of specific threshold reached

I have two columns; the_day and amount_raised. I want to find the count of consecutive days that at least 1 million dollars was raised. Am I able to do this in SQL? Ideally, I'd like to create a column that counts the consecutive days and then starts over if the 1 million dollar threshold is not reached.
What I've done thus far is create a third column that puts a 1 in the row if 1 million was reached. Could I create a subquery and count the consecutive 1's listed, then reset when it hits 0?
and here is the desired output
select dt,amt,
case when amt>=1000000 then -1+row_number() over(partition by col order by dt)
else 0 end col1
from (select *, sum(case when amt >= 1000000 then 0 else 1 end) over(order by dt) col
from t) x
Sample Demo
SELECT the_day,
amount_raised,
million_threshold,
CASE WHEN million_threshold <> lag_million_threshold AND million_threshold = lead_million_threshold
THEN 1
WHEN million_threshold = lag_million_threshold
THEN SUM(million_threshold) OVER ( ORDER BY the_day ROWS UNBOUNDED PRECEDING )
ELSE 0
END AS consecutive_day_cnt
FROM
(
SELECT the_day,
amount_raised,
million_threshold,
LAG(million_threshold,1) OVER ( ORDER BY the_day ) AS lag_million_threshold,
LEAD(million_threshold,1) OVER ( ORDER BY the_day ) AS lead_million_threshold
FROM
(
SELECT the_day,
amount_raised,
CASE WHEN amount_raised >= 1000000
THEN 1
ELSE 0
END AS million_threshold
FROM Yourtable
)
);