How To Set Row As Null After Meeting A Certain Criteria - sql

I am trying to have "Cumulative Customers" be NULL after the first 5 "Cumulative Customers":
SUM(Customer) OVER (PARTITION BY Product ORDER BY date DESC) cumulative_customers
The final output will look like this:

Use a CASE expression:
SELECT CASE WHEN cumulative_customers < 5
OR cumulative_customers = 5 AND customer >= 1
THEN cumulative_customers END AS cumulative_customers
, ... -- more columns
FROM (
SELECT ... -- your current query here
) sub;
If the ELSE part is missing it defaults to NULL. You can spell that out, too, if you prefer.
I use customer >= 1 just in case there can be values greater than 1 (unlike your demo suggests).

If you don't want a subquery, you can do this using case:
select (case when SUM(Customer) OVER (PARTITION BY Product ORDER BY date DESC) <= 5
then SUM(Customer) OVER (PARTITION BY Product ORDER BY date DESC)
end) as cumulative_customers
Erwin's solution also works if you want a subquery or CTE.

Related

Finding first transaction after death of date

Could anyone please help to enhance the query below,
select
columns
from
(
select t.*,
sum (case when TRAN_DATE >= '20170701' then 1 end)
over (partition by acct_no order by TRAN_DATE, TRAN_TIME ) as sm_i
from (
Select
Columns
FROM
#BASEtable DTRAN
INNER JOIN sometable
where condition) t) t
where sm_i = 1
order by acc_no
here is the data example, (attached)
Company Acct_no Tran_Date Death_of_date
1 123 20170725 20170702
1 123 20170825 20170702
1 123 20170925 20170702
2 456 20191025 20200101
2 456 20191125 20200101
2 456 20191225 20200101
Result expected: Row no 1 , as that is the first transaction for that account after the death_of_date
I am sorting the data based on 20170701, that is it will pick the first transaction happened after this date should be picked up which is working with the above query.
Now, i want to set the value of '20170701' with the dynamic value , i.e. need the first transaction of every account after its death of date..
I replaced the partition code the below code,
sum(case when tran_Date > = (select death_of_date from #basetable a where a.acct_no = t.acct_no ) then 1 end)
over partition by acct_no order by tran_Date , tran_Time) as sm_i
but getting error saying, subquery retuned more than one result which is not application where using > , = and so on.
Please help to enhance this code in sql server. Appreciate your help in advance!
enter image description here
Assuming two things:
You have data with the four columns you have specified.
For each account, you want the first row meeting your date condition.
Then you can use window functions and filtering:
select t.*
from (select t.*,
row_number() over (partition by Company, Acct_no order by Tran_Date) as seqnum
from t
where tran_date > death_of_date
) t
where seqnum = 1;

Conditional Order by based on aggregate value of a column in Oracle Sql Developer

I have a table that has ID, CW_savings, PW_Savings and Savings_Diff(CW-PW). I want to order the table depending on the sum(Savings_Diff), if it is >=0 then Desc(greatest positive diff shown first) else asc(greatest -ve diff shown first). Currently i am using :
select ID, CW_savings, PW_Savings,Savings_Diff
from table
order by case
when sum(savings_diff) >=0 then Savings_diff end DESC
when sum(savings_diff) < 0 then SAvings_diff end ASC
;
This query is not working because i believe you can't use aggregate functions in Order by clause.
Looking for a workaround on this?
If the sum that you want to check is the total sum of the column Savings_Diff of all the rows of the table then you can do this:
select t.ID, t.CW_savings, t.PW_Savings, t.Savings_Diff
from tablename t
cross join (select sum(Savings_Diff) total from table) s
order by -sign(s.total) * t.Savings_diff
When the sum is positive then the sorting is equivalent to:
order by -Savings_diff
or
order by Savings_diff DESC
When the sum is negative then the sorting is equivalent to:
order by Savings_diff
or
order by Savings_diff ASC
I am going to speculate that id has multiple rows in the table and you want the sum for the id. You can use window functions:
select ID, CW_savings, PW_Savings,Savings_Diff
from table
order by (case when sum(savings_diff) over (partition by id) >= 0 then Savings_diff end) desc,
(case when sum(savings_diff) over (partition by id) < 0 then savings_diff end) ASC;

SQL - Window function to get values from previous row where value is not null

I am using Exasol, in other DBMS it was possible to use analytical functions such LAST_VALUE() and specify some condition for the ORDER BY clause withing the OVER() function, like:
select ...
LAST_VALUE(customer)
OVER (PARTITION BY ID ORDER BY date_x DESC ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING ) as the_last
Unfortunately I get the following error:
ERROR: [0A000] Feature not supported: windowing clause (Session:
1606983630649130920)
the same do not happen if instead of AND 1 PRECEDING I use: CURRENT ROW.
Basically what I wanted is to get the last value according the Order by that is NOT the current row. In this example it would be the $customer of the previous row.
I know that I could use the LAG(customer,1) OVER ( ...) but the problem is that I want the previous customer that is NOT null, so the offset is not always 1...
How can I do that?
Many thanks!
Does this work?
select lag(customer) over (partition by id
order by (case when customer is not null then 1 else 0 end),
date
)
You can do this with two steps:
select t.*,
max(customer) over (partition by id, max_date) as max_customer
from (select t.*,
max(case when customer is not null then date end) over (partition by id order by date) as max_date
from t
) t;

SQL retrieve recent record

I want to retrieve TOPIC 1 SCORES with the most recent score (excluding null) (sorted by date) for each detailsID, (there are only detailsID 2 and 3 here, therefore only two results should return)
What about getting rid of Topic 1 Scores in GROUP BYdetailsID,Topic 1 Scores ?
Use a subquery to get the max and then join to it.
SELECT a.detailsID,`Topic 1 Scores`, a.Date
FROM Information.scores AS a
JOIN (SELECT detailsID, MAX(Date) "MaxDate"
FROM Information.scores
WHERE `Topic 1 Scores` IS NOT NULL
GROUP BY detailsID) Maxes
ON a.detailsID = Maxes.detailsID
AND a.Date = Maxes.MaxDate
WHERE `Topic 1 Scores` IS NOT NULL
Assuming SQL Server:
SELECT
ROW_NUMBER() OVER (PARTITION BY detailsID ORDER BY Date DESC) AS RowNumber,
detailsID, Date, Topic 1 Scores
FROM
Information.scores
Try doing
SELECT detailsID,`Topic 1 Scores`, MAX(Date) as "Date" GROUP BY "Date"

How to get minimum value from the SQL table?

I have a table as below
ID Date
1 Null
1 Null
1 Null
1 02/02/2012
1 02/03/2012
1 02/04/2012
1 02/05/2012
I want to take a min date from the above table, that's result should be Null
I was trying to write
select min(date), Id from Table group by ID
then result is 02/02/2012, but I want Null.
Is there any otherway to pull Null value from the above table except the below method?
select top 1 date, ID from table order by date asc
Assuming that your dbms is SQL-Server.
If you want to group by id but select all fields anyway, you can use a cte with ROW_NUMBER function:
WITH cte AS(
SELECT x.*
, RN=ROW_NUMBER()OVER(Partition By id Order By date)
FROM Table x
)
SELECT * FROM cte
WHERE RN=1
http://sqlfiddle.com/#!3/cc2a4/7
By default the functions MAX and MIN do not count NULL in their evaluation of your data.
Try in this way, should do the trick :
SELECT
CASE WHEN MIN(COALESCE(Date, '19001231')) = '19001231' THEN NULL ELSE MIN(Date) END AS Date,
Id
FROM X
group by ID
I think some of them are given the answer. but the final result working with below query
SELECT CASE WHEN MIN(coalesce(date, '1900-01-01')) = '1900-01-01' THEN NULL ELSE MIN(date) END AS Date, ID
FROM table
GROUP BY ID
You can also do a simple check for 'NULL'. I didn't return an "ID" in the example since the "ID" seems meaningless in the example schema/query given.
IF (EXISTS(SELECT TOP 1 * FROM x WHERE date IS NULL)) SELECT NULL AS MinDate
ELSE SELECT MIN(date) AS MinDate FROM x;
http://sqlfiddle.com/#!3/d5fca/11