SQL to find records with last 3 same status - sql

I have the following tasks table:
id type submit_time status
I need to run a query that returns only the types which their last 3 tasks finished with status "FAILED".
How can I do this?
Should I use a window function?
Thanks

You can use aggregation and filtering after using row_number() to get the last three rows:
select type
from (select t.*,
row_number() over (partition by type order by submit_time desc) as seqnum
from t
) t
where seqnum <= 3
group by type
having min(status) = max(status) and min(status) = 'FAILED' and
count(*) = 3;
Actually, a slightly simpler method is:
select type
from (select t.*,
row_number() over (partition by type order by submit_time desc) as seqnum
from t
) t
where seqnum <= 3 and status = 'FAILED'
group by type
having count(*) = 3;

Related

Max date and order by status exist at first occurrence if not found next value

I have a table as below
ID,DATE,Status
359,2021-05-01,M
359,2021-05-01,R
359,2021-04-01,M
759,2021-05-01,R
759,2021-04-01,O
123,2021-05-01,M
123,2021-04-01,O
123,2021-03-31,U
and I want the result as below
359,2021-05-01,R
759,2021-05-01,R
123,2021-05-01,M
Date - Max/Latest date
Status:
First preference should be R(Exit if R found)
If R doesn't exist then M
If M doesn't exist then O
If O doesn't exist then U etc.,
Could someone please help me with this?
Thanks in advance
One method is row_number():
select t.*
from (select t.*,
row_number() over (partition by id order by case status when 'R' then 1 when 'M' then 2 when 'O' then 3 when 'U' then 4 else 5 end
) as seqnum
from t
) t
where seqnum = 1;
If you know all the statuses, a shortcut is:
select t.*
from (select t.*,
row_number() over (partition by id order by charindex('RMOU', status)) as seqnum
from t
) t
where seqnum = 1;

Displaying a multiple columns in single row in SQL

SELECT * FROM
(select ID,POLICY_ID,CONTACT_ID,POLICY_CONTACT_ROLE,ROW_NUMBER () OVER (PARTITION BY POLICY_ID,POLICY_CONTACT_ROLE ORDER BY ID ) AS ORDERNO
FROM P_POL_HEADER_CONTACT ) SUB
WHERE SUB.ORDERNO=1 AND POLICY_ID =20001
I want to arrange the above query to take result like this
Thanks
You need to pivot on a row-number.
You can use PIVOT, but I often find a simple GROUP BY/MAX is simpler, especially when you need to rename the columns.
SELECT
SUB.POLICY_ID
,MAX(CASE WHEN POLICY_CONTACT_ROLE_NO = 1 THEN POLICY_CONTACT_ROLE END) AS POLICY_CONTACT_ROLE
,MAX(CASE WHEN POLICY_CONTACT_ROLE_NO = 2 THEN POLICY_CONTACT_ROLE END) AS POLICY_CONTACT_ROLE2
,MAX(CASE WHEN POLICY_CONTACT_ROLE_NO = 3 THEN POLICY_CONTACT_ROLE END) AS POLICY_CONTACT_ROLE3
-- etc etc
FROM (
SELECT *,
ROW_NUMBER () OVER (PARTITION BY POLICY_ID ORDER BY POLICY_CONTACT_ROLE) AS POLICY_CONTACT_ROLE_NO
FROM (
SELECT *
ROW_NUMBER () OVER (PARTITION BY POLICY_ID, POLICY_CONTACT_ROLE ORDER BY ID ) AS ORDERNO
FROM P_POL_HEADER_CONTACT
WHERE POLICY_ID = 20001
) SUB
WHERE SUB.ORDERNO = 1
) SUB
GROUP BY SUB.POLICY_ID
You want conditional aggregation. I think the logic you want is:
SELECT PCH.POLICY_ID,
MAX(CASE WHEN SEQNUM = 1 THEN POLICY_CONTACT_ROLE END) as POLICY_CONTACT_ROLE_1,
MAX(CASE WHEN SEQNUM = 2 THEN POLICY_CONTACT_ROLE END) as POLICY_CONTACT_ROLE_2,
MAX(CASE WHEN SEQNUM = 3 THEN POLICY_CONTACT_ROLE END) as POLICY_CONTACT_ROLE_3
FROM (SELECT PHC.*,
ROW_NUMBER() OVER (PARTITION BY POLICY_ID ORDER BY ID ) AS SEQNUM
FROM P_POL_HEADER_CONTACT PHC
) PHC
WHERE POLICY_ID = 20001
GROUP BY POLICY_ID;
I'm not sure what your filtering on ORDERNO is really doing. If you have duplicates, use DENSE_RANK() instead of ROW_NUMBER(). However, without knowing what your data looks like, I am guessing that is unnecessary.
Exclude CONTACT_ID from query. And use STUFF query to convert your rows into columns

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);

How to find most frequent value in SQL column and return that value?

I was trying to do something like this:
select nume_produs
from incasari
group by id
having count(nume_produs) = max(count(nume_produs));
but it doesn't work
Do a GROUP BY. Order by count descending. Fetch the first row (highest count) only.
select nume_produs, count(*) as cnt
from incasari
group by nume_produs
order by cnt desc
fetch first 1 row with ties
For the most common value in the column:
select num_produs
from (select nume_produs, count(*) as cnt,
row_number() over (order by count(*)) as seqnum
from incasari
group by nume_produs
) i
where seqnum = 1;
If you want multiple values in the event of duplicates, use rank() instead of row_number().
If you want the most common value per id, then add partition by:
select num_produs
from (select nume_produs, count(*) as cnt,
row_number() over (partition by id order by count(*)) as seqnum
from incasari
group by nume_produs
) i
where seqnum = 1;
SELECT `nume_produs`,
COUNT(`nume_produs`) AS `value_occurrence`
FROM `incasari`
GROUP BY `nume_produs`
ORDER BY `value_occurrence` DESC
LIMIT 1;
Increase 1 if you want to see the N most common values of the column.

Convert SQL CTE expression to normal subquery

is there a way to convert the following sql query with CTE expression into a subquery version?
It works on SQL 8 but i need to run this on SQL 5
WITH no_duplicate AS
( SELECT * , ROW_NUMBER() OVER (PARTITION BY lead_google_client_id ORDER BY lead_google_client_id DESC) AS single_googleClientID
FROM properties
)
SELECT lead_referral,
count(*) as total,
count(case when state = 'rejected' and priority != 3 then 1 end) as rejected
FROM no_duplicate
WHERE single_googleClientID=1
GROUP BY lead_referral
Disclaimer: I am not sure what you are trying to accomplish. For that you will have to provide more information, like sample data from the properties table.
Try this:
SELECT
ROW_NUMBER() OVER (PARTITION BY lead_google_client_id ORDER BY lead_google_client_id DESC) AS single_googleClientID, lead_referral,
count(*) as total,
count(case when state = 'rejected' and priority != 3 then 1 end) as rejected
FROM properties
WHERE single_googleClientID=1
GROUP BY lead_referral