Query doesn't work when adding another condition with PARTITION BY - sql

Originally I had the following query:
SELECT T.* FROM
(SELECT *, row_number() OVER
(PARTITION BY manager_id ORDER BY id) AS sn FROM my_table) T
WHERE (sn = 1)
AND ((checkbox IS NULL OR (checkbox = 0)
)
but then I added another boolean column to the db called "not_relevant" and I want to show results where its value is not 1, so I added the following:
SELECT T.* FROM
(SELECT *, row_number() OVER
(PARTITION BY manager_id ORDER BY id) AS sn FROM my_table) T
WHERE (sn = 1)
AND ((checkbox IS NULL) OR (checkbox = 0)
AND (not_relevant != 1)
)
But I get the same results even if not_relevant is 1
Why?

Related

How can I generate row_number by condition

I am trying to put conditional numbering depending on a result from row_num column.
When the flg_start_trx is 1, I would like to have new column with brand new increment by 1 and it will stop when found the end of flg_session_match != 1
How can I fix this query if I want the result should be like row_num column?
case when (title is not null and title_program is null)
then (row_number() over (partition by flg_session_match,(case when (title is not null and title_program is null) then 1 else 0 end)
)
)
end as start_session
You may try this:
(As #Ahmed mentioned above, you need a column to define an order of each row, so I've added ts for that purpose.)
SELECT * EXCEPT(par0, par1),
IF (FIRST_VALUE(flg_start_trx) OVER w1 IS NOT NULL, ROW_NUMBER() OVER w1, NULL) AS row_num
FROM (
SELECT *,
COUNT(*) OVER w0 - COUNTIF(flg_start_trx IS NULL) OVER w0 AS par0,
COUNT(*) OVER w0 - COUNTIF(flg_session_match = 1) OVER w0 AS par1
FROM sample_data
WINDOW w0 AS (ORDER BY ts)
) WINDOW w1 AS (PARTITION BY par0, par1 ORDER BY ts);

get first occurrence of last changed value of a column for each unique id

How to get first occurrence of last changed value of "sval" column?
for id = 22, 71 is the last changed value so wants to fetch first occurence of 71.
same way for id = 25, 74 is the last changed value so wants to fetch first occurence of 74.
https://dbfiddle.uk/?rdbms=mariadb_10.6&fiddle=c980809154d41f2accc9f14d569b48f1
data:
in above picture i wanted to fetch highlighted row.
try:
with LastValue as (
select t.sval
from test t
order by t.date desc
limit 1
)
select t.*
from test t
where t.sval = (select sval from LastValue)
and t.date > (select max(tt.date) from test tt where tt.sval <> (select sval from LastValue))
order by t.date asc
limit 1;
actually the problem statement is i dont want the group by sval first occurence, instead i want the whatever last changed sval so our example after highlighted rows should be returns for ids (22,25).
WITH
cte1 AS ( SELECT *,
ROW_NUMBER() OVER (PARTITION BY id ORDER BY `date` DESC) rn1,
ROW_NUMBER() OVER (PARTITION BY id, sval ORDER BY `date` DESC) rn2
FROM test ),
cte2 AS ( SELECT *,
ROW_NUMBER() OVER (PARTITION BY id ORDER BY `date` ASC) rn3
FROM cte1
WHERE rn1 = rn2 )
SELECT id, date, sval
FROM cte2
WHERE rn3 = 1;
https://dbfiddle.uk/?rdbms=mariadb_10.6&fiddle=a25569690e4b35a55b0bee13856eb724
One method for doing this uses lag() to check for a difference and then chooses the last point where there is a difference:
select t.*
from (select t.*,
row_number() over (partition by id order by date desc) as seqnum
from (select t.*,
lag(sval) over (partition by id order by date) as prev_sval
from test t
) t
where prev_sval is null or prev_sval <> sval
) t
where seqnum = 1;
Very importantly: This returns the last time there was a change even when the value returns to an already seen value for the id. That is how I interpret your question.

Identify the pattern to get desired output

We have below table contains multiple code against the ID and CounterID. Need an output based on code and id.
Condition: Against the ID and CounterID
case 1 : if there is code CI and CO then no record
case 2 : if there is code CI and CO and CI then last record with code CI
case 3 : if there is code CI then last CI
Thanks
Rahul
You can use the analytical function as follows:
select t.* from
(select t.*, row_number() over (partition by sno order by date desc) as rn,
count(case when code = 'CI' then 1 end) over (partition by sno) as cicount,
count(case when code = 'CO' then 1 end) over (partition by sno) as cocount
from your_table t) t
where ( (cocount = 0)
or not (cicount = 1 and cocount = 1)
or (cocount > cicount ))
and rn = 1
Your logic simplifies to: The last row when it has 'CI'. One method with window functions is:
select t.*
from (select t.*,
row_number() over (partition by id order by date desc) as seqnum
from t
) t
where seqnum = 1 and code = 'CI';
You can also do this without window functions:
select t.*
from t
where code = 'CI' and
date = (select max(t2.date) from t t2 where t2.id = t.id);

SQL - delete record where sum = 0

I have a table which has below values:
If Sum of values = 0 with same ID I want to delete them from the table. So result should look like this:
The code I have:
DELETE FROM tmp_table
WHERE ID in
(SELECT ID
FROM tmp_table WITH(NOLOCK)
GROUP BY ID
HAVING SUM(value) = 0)
Only deletes rows with ID = 2.
UPD: Including additional example:
Rows in yellow needs to be deleted
Your query is working correctly because the only group to total zero is id 2, the others have sub-groups which total zero (such as the first two with id 1) but the total for all those records is -3.
What you're wanting is a much more complex algorithm to do "bin packing" in order to remove the sub groups which sum to zero.
You can do what you want using window functions -- by enumerating the values for each id. Taking your approach using a subquery:
with t as (
select t.*,
row_number() over (partition by id, value order by id) as seqnum
from tmp_table t
)
delete from t
where exists (select 1
from t t2
where t2.id = t.id and t2.value = - t.value and t2.seqnum = t.seqnum
);
You can also do this with a second layer of window functions:
with t as (
select t.*,
row_number() over (partition by id, value order by id) as seqnum
from tmp_table t
),
tt as (
select t.*, count(*) over (partition by id, abs(value), seqnum) as cnt
from t
)
delete from tt
where cnt = 2;

SQL query to display latest value first and then others ASC

I have a table with news which I then echo into a slider using foreach loop.
I would need to adjust the sort order of the query, so the last one added (max id) is always displayed first, with others sorted by id ASC.
So example: News 1, 2, 3,4. I need them echoed like 4,1,2,3.
SELECT * FROM news ORDER BY sort ASC
How add another condition in the form of max(id) first then sort ASC?
Thanks.
You can try this query:
SELECT *
FROM (
SELECT *,
(SELECT MAX(Id) FROM news) AS max_id
FROM news) AS t
ORDER BY CASE WHEN id = max_id THEN 0 ELSE 1 END asc,
id ASC
or, using CROSS JOIN:
SELECT n.*
FROM news AS n
CROSS JOIN (SELECT MAX(Id) AS max_id FROM news) AS m
ORDER BY CASE WHEN n.id = m.max_id THEN 0 ELSE 1 END asc,
n.id ASC
or use window function
SELECT *
FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY id DESC) AS RN
FROM news) AS T
ORDER BY CASE WHEN RN = 1 THEN 0 ELSE 1 END, id
SELECT *
FROM (
SELECT *, MAX(id) OVER () AS MaxID
FROM news) AS T
ORDER BY CASE WHEN MaxID = id THEN 0 ELSE 1 END, id