Convert SQL CTE expression to normal subquery - sql

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

Related

Oracle SQL-count number of null by group and add a new column

I am trying to count number of open cases grouped by ID (by counting number of "null" in the CloseDate column), and add a new column into the table. I am not sure how to do that. Any thoughts will be appreciated, thank you!
The idea result would be:
This uses a SUM window function (don't use COUNT() with a CASE statement like this because the 0's would get included as part of the "count", which isn't what you want).
This also avoids using a subquery, so it'll perform faster than any query that does (especially if you're dealing with large table) because it doesn't need to reread data from the same table. One of the main advantages to using window functions is that they prevent the need to reread table data, so don't force your query to reread from the table by putting the window function in a separate subquery if you can avoid it.
Assuming your table's name is t
select
ClientID,
Service,
Status,
CloseDate,
sum(
case
when CloseDate is null
then 1
else 0
end
) over(
partition by ClientID
) as OpenCount
from t;
I think you can use the below query with having window function -
SELECT ClientID,
Service,
Status,
CloseDate,
OpenCount,
SUM(CASE WHEN CloseDate IS NULL THEN 1 ELSE 0 END) OVER(PARTITION BY ClientID)
FROM YOUR_TABLE;
With a subquery inside the select clause, you can reach the desired output.
In sql
SELECT ClientID,
Service,
Status,
CloseDate,
ISNULL((SELECT TOP 1 COUNT(*) OVER(PARTITION BY ClientID ORDER BY ClientID) FROM t1 WHERE t1.ClientID = t.ClientID AND t1.CloseDate IS NULL),0) AS OpenCount
FROM t1 t;
In oracle
SELECT ClientID,
Service,
Status,
CloseDate,
coalesce((SELECT COUNT(*) OVER(PARTITION BY clientid ORDER BY clientid) FROM t1 WHERE t1.ClientID = t.ClientID AND t1.CloseDate IS NULL FETCH FIRST 1 ROWS ONLY),0) AS OpenCount
FROM t1 t;
sql demo dbfiddle
oracle demo dbfiddle
You could count the number of times that the closedate is null:
select t.*,
sum(case when closedate is null then 1 else 0 end) over (partition by clientid)
from t;
Or you could count the number of opens and subtract the number of closes:
select t.*,
sum(case status when 'open' then 1 when 'closed' then -1) over (partition by clientid)
from t;
These are equivalent for the data you provided. I'm not sure if one is really better for your problem than the other.

SQL to find records with last 3 same status

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;

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

Get data from records having multiple count and manipulate them

I have a sample record like below in one of my SQL tables:
What I want is my select query should take the student record which has multiple count of same subjects, ie, Student A has a count(6) for subject COD and use a case statement to give the first record as failed and rest of the record as After Fail.
Ex output:
I'm not able to implement a correct logic to get this.
Thanks in advance!
You can use window functions. The logic is to enumerate and count the number of records having the same student and subject in a subquery, then use that information in the outer query:
select id, student, subject, marks,
case
when cnt > 1 and rn = 1 then 'Fail'
when cnt > 1 and rn > 1 then 'After fail'
end output
from (
select t.*,
row_number() over(partition by student, subject order by id) rn,
count(*) over(partition by student, subject) cnt
from mytable t
) t
In SQL Server it seems you're looking for something like this
with
students_cte as (
select *, row_number() over (partition by Student order by ID) rn
from SomeTable),
multi_cte as (
select *, max(case when rn>1 then 1 else 0 end) over (partition by Student order by ID) multi
from students_cte)
select case when multi=1 and rn=1 then 'Fail' else
case when multi=1 and rn>1 then 'after fail' else null end end [output]
from multi_cte
order by ID;

Select MAX issue SQL

Scenario:
I have a table with order status, for example:
/ ORDER LOG NUMBER LOG CODE
1 1 1 Preparing
2 1 2 Prepared
3 1 3 Sent
4 2 1 Preparing
5 2 2 Prepared
6 3 1 Preparing
I've been looking for a way to select orders, where last log code is Prepared.
For example I want to see all ORDERS where last LOG CODE is Prepared (last log)
Oracle supports Windowed Aggregates:
select *
from
( select
ORDER
,LOG_NUMBER
,LOG_CODE
-- last log number for each order
,max(LOG_NUMBER) over (partition by ORDER) as maxnum
from mytable
) dt
where LOG_NUMBER = maxnum
and LOG_CODE = 'Prepared'
or
select *
from
( select
ORDER
,LOG_NUMBER
,LOG_CODE
-- youngest row gets row_number 1
,ROW_NUMBER() over (partition by ORDER order by LOG_NUMBER desc) as rn
from mytable
) dt
where rn = 1
and LOG_CODE = 'Prepared'
You can use the analytic function to do so
https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions070.htm
It should be something like:
SELECT order LAG(log_code, 1, 0) OVER (PARTITION BY order ORDER BY log_number) AS prev_code FROM orders
This will at least deliver you a resultset which has the last code information.
Instead of using an outer select you should be able to extend the query with
"having prev_code = 'Prepared'"
A pretty efficient way is to use correlated subqueries:
select t.*
from t
where t.lognumber = (select max(t2.lognumber) from t t2 where t.order = t2.order) and
t.logcode = 'Prepared';