I have 4 tables and I am trying to get Last two maximum dates from these 4 tables. I have listed my query below:
WITH LAST_ATT_DATE AS
(
SELECT NUMREF AS NUMBER1,DATE AS LAST_DATE
FROM TABLE1
WHERE NUM_REF='E1'
UNION
SELECT NUMREF AS NUMBER1,DATE AS LAST_DATE
FROM TABLE2
WHERE NUM_REF='E1'
UNION
SELECT NUMREF AS NUMBER1,DATE AS LAST_DATE
FROM TABLE3
WHERE NUMREF='E1'
UNION
SELECT NUMREF AS NUMBER1,DATE AS LAST_DATE
FROM TABLE4
WHERE NUMREF='E1'
)
SELECT MAX(decode(RANK,1,LAST_DATE)),MAX(decode(RANK,2,LAST_DATE))
FROM (SELECT NUMBER1,LAST_DATE,Row_Number() OVER(PARTITION BY NUMBER1
ORDER BY LAST_DATE DESC) AS RANK
FROM LAST_ATT_DATE) WHERE RANK <= 2
GROUP BY NUMBER1 ORDER BY NUMBER1;
For some records, it's working properly and for many records, it's showing the same date(only the first maximum date) even though it's having a 2nd maximum date.
Someone please correct this code or suggest any other alternative method.
Hoping, I understood the question correctly. Please check below query.
WITH LAST_ATT_DATE AS
(
SELECT NUMREF AS NUMBER1,DATE AS LAST_DATE
FROM TABLE1
WHERE NUM_REF='E1'
UNION
SELECT NUMREF AS NUMBER1,DATE AS LAST_DATE
FROM TABLE2
WHERE NUM_REF='E1'
UNION
SELECT NUMREF AS NUMBER1,DATE AS LAST_DATE
FROM TABLE3
WHERE NUMREF='E1'
UNION
SELECT NUMREF AS NUMBER1,DATE AS LAST_DATE
FROM TABLE4
WHERE NUMREF='E1'
)
SELECT NUMBER1 , MAX(CASE WHEN RN=1 THEN LAST_DATE END) LAST_DATE_1,
MAX(CASE WHEN RN=2 THEN LAST_DATE END) LAST_DATE_2
FROM (SELECT NUMBER1,LAST_DATE,Row_Number() OVER(
ORDER BY LAST_DATE DESC) AS RN
FROM LAST_ATT_DATE) WHERE RN <= 2
GROUP BY NUMBER1 ORDER BY NUMBER1;
You need to use dense_rank() rather than row_number():
SELECT NUMBER1,
MAX(CASE WHEN seqnum = 1 THEN LAST_DATE END),
MAX(CASE WHEN seqnum = 2 THEN LAST_DATE)
FROM (SELECT NUMBER1, LAST_DATE,
DENSE_RANK() OVER (PARTITION BY NUMBER1
ORDER BY LAST_DATE DESC
) AS seqnum
FROM LAST_ATT_DATE
) lad
WHERE seqnum <= 2
GROUP BY NUMBER1
ORDER BY NUMBER1;
Thanks all for your replies.
I got a solution to my question. I just truncated the date column and tried it's worked.
SELECT NUMREF AS NUMBER1,trunc(DATE) AS LAST_DATE
FROM TABLE1 WHERE NUMREF='E1';
Again thanks all.
Related
I have a requirement to write a query to retrieve the records which have POS_ORDER_ID in the table with same POS_ORDER_ID which comes within 30days as new record with status 'Canceled', 'Discontinued' and need to mark previous POS_ORDER_ID record as it as not eligible
Table columns:
POS_ORDER_ID,
Status,
Order_date,
Error_description
A query containing MAX() and ROW_NUMBER() analytic functions might help you such as :
with t as
(
select t.*,
row_number() over (partition by pos_order_id order by Order_date desc ) as rn,
max(Order_date) over (partition by pos_order_id) as mx
from tab t -- your original table
)
select pos_order_id, Status, Order_date, Error_description,
case when rn >1
and t.status in ('Canceled','Discontinued')
and mx - t.Order_date <= 30
then
'Not eligible'
end as "Extra Status"
from t
Demo
Please use below query,
Select and validate
select POS_ORDER_ID, Status, Order_date, Error_description, row_number()
over(partition by POS_ORDER_ID order by Order_date desc)
from table_name;
Update query
merge into table_name t1
using
(select row_id, POS_ORDER_ID, Status, Order_date, Error_description,
row_number() over(partition by POS_ORDER_ID order by Order_date desc) as rnk
from table_name) t2
on (t1.POS_ORDER_ID = t2.POS_ORDER_ID and t1.row_id = t2.row_id)
when matched then
update
set
case when t2.rnk = 1 then 'Canceled' else 'Not Eligible';
I'm trying to return the number of unique users that converted over time.
So I have the following query:
WITH CTE
As
(
SELECT '2020-04-01' as date,'userA' as user,1 as goals Union all
SELECT '2020-04-01','userB',0 Union all
SELECT '2020-04-01','userC',0 Union all
SELECT '2020-04-03','userA',1 Union all
SELECT '2020-04-05','userC',1 Union all
SELECT '2020-04-06','userC',0 Union all
SELECT '2020-04-06','userB',0
)
select
date,
COUNT(DISTINCT
IF
(goals >= 1,
user,
NULL)) AS cad_converters
from CTE
group by date
I'm trying to count distinct user but I need to find a way to apply the distinct count to the whole date. I probably need to do something like a cumulative some...
expected result would be something like this
date, goals, total_unique_converted_users
'2020-04-01',1,1
'2020-04-01',0,1
'2020-04-01',0,1
'2020-04-03',1,2
'2020-04-05',1,2
'2020-04-06',0,2
'2020-04-06',0,2
Below is for BigQuery Standard SQL
#standardSQL
SELECT t.date, t.goals, total_unique_converted_users
FROM `project.dataset.table` t
LEFT JOIN (
SELECT a.date,
COUNT(DISTINCT IF(b.goals >= 1, b.user, NULL)) AS total_unique_converted_users
FROM `project.dataset.table` a
CROSS JOIN `project.dataset.table` b
WHERE a.date >= b.date
GROUP BY a.date
)
USING(date)
I would approach this by tagging when the first goal is scored for each name. Then simply do a cumulative sum:
select cte.* except (seqnum), countif(seqnum = 1) over (order by date)
from (select cte.*,
(case when goals = 1 then row_number() over (partition by user, goals order by date) end) as seqnum
from cte
) cte;
I realize this can be expressed without the case in the subquery:
select cte.* except (seqnum), countif(seqnum = 1 and goals = 1) over (order by date)
from (select cte.*,
row_number() over (partition by user, goals order by date) as seqnum
from cte
) cte;
I am trying to group some records to find the first one for a particular site for a given client. The problem is that the records go back and forth between sites, so I need to keep non-consecutive site date ranges separate.
Given the sample data, I want to end up with 3 records - one for site 1 starting 7/3/18, a second for site 2 starting on 9/3/18 and the third for site 1 again starting 11/3/18.
SELECT 9999 AS CLIENT_ID, 1 AS SITE_NUM, '2018-07-03' AS START_DATE, '2018-08-05' AS CREATED_DATE, 1 AS RECORD_ID
INTO #TEMP
UNION
SELECT 9999 AS MEMBER_ID, 1 AS SITE_NUM, '2018-08-01' AS CONSENT_SIGN_DATE, '2018-10-05' AS CREATED_DATE, 2
UNION
SELECT 9999 AS MEMBER_ID, 1 AS SITE_NUM, '2018-07-03' AS CONSENT_SIGN_DATE, '2018-09-22' AS CREATED_DATE, 3
UNION
SELECT 9999 AS MEMBER_ID, 2 AS SITE_NUM, '2018-09-03' AS CONSENT_SIGN_DATE, '2018-09-05' AS CREATED_DATE, 4
UNION
SELECT 9999 AS MEMBER_ID, 2 AS SITE_NUM, '2018-10-03' AS CONSENT_SIGN_DATE, '2018-10-05' AS CREATED_DATE, 5
UNION
SELECT 9999 AS MEMBER_ID, 1 AS SITE_NUM, '2018-11-03' AS CONSENT_SIGN_DATE, '2018-11-05' AS CREATED_DATE, 6
UNION
SELECT 9999 AS MEMBER_ID, 1 AS SITE_NUM, '2018-12-01' AS CONSENT_SIGN_DATE, '2018-12-05' AS CREATED_DATE, 7
I've been playing with ROW_NUM but haven't been able to figure out how to separate the two sets of dates for Site 1.
SELECT *, ROW_NUMBER()OVER(PARTITION BY T.CLIENT_ID, T.SITE_NUM ORDER BY T.START_DATE, T.RECORD_ID)
FROM #TEMP T
LEFT JOIN #TEMP T2 ON T2.CLIENT_ID = T.CLIENT_ID AND T2.RECORD_ID = T.RECORD_ID - 1
ORDER BY T.RECORD_ID
How can I group the results by client and consecutive dates for a single site?
This is a gaps-and-islands problem. For this, the difference of row numbers is the best approach:
select t.client_id, t.site_num, min(t.start_date), max(t.start_date)
from (select t.*,
row_number() over (partition by t.client_id order by T.START_DATE, T.RECORD_ID) as seqnum_c,
row_number() over (partition by t.client_id, t.site_num order by T.START_DATE, T.RECORD_ID) as seqnum_cs
from #temp t
) t
group by client_id, site_num, (seqnum_c - seqnum_cs)
WHat you want is consecutive rows should not have the same SITE_NUM value. All you need to do is add a where clause at the end of your query.
SELECT *, ROW_NUMBER()OVER(PARTITION BY T.CLIENT_ID, T.SITE_NUM ORDER BY T.START_DATE, T.RECORD_ID)
FROM #TEMP T
LEFT JOIN #TEMP T2 ON T2.CLIENT_ID = T.CLIENT_ID AND T2.RECORD_ID = T.RECORD_ID - 1
ORDER BY T.RECORD_ID
WHERE T.SITE_NUM <> T2.SITE_NUM OR T2.SITE_NUM IS NULL
EDIT As suggested by #SteveB to add T2.SITE_NUM IS NULL to show last record too.
I am fairly new to SQL (SQL Management Studio 2016) and I only joined the site this morning...so my first post! I have been looking for a solution on the site regarding my issue. I have found a few links but none that (I think) will work having tried a few. I have a table that holds boiler service data. One address can have multiple dates/sequence numbers. I am looking to create a script that proves the latest sequential numbers start date is less than or equal to the latest sequential end date. So, in my example, I'd want to select the MAX seq_no for the start_date field and the 2nd MAX seq_no for the end_date field to make sure they haven't breached timescale.
My sample data has been added as an image (hopefully!)...just two addresses but there are 1000's in reality):
I have tried SLQ to get max seq_no's for just the end date initially but it just keeps bringing back all the entries:
select max (seq_no) as SEQNO, end_date, cmpnt_ref, prty_id
FROM hgmpcych
where prty_id in ('ABBEY10_TD12','ABBEY12_TD12') and cmpnt_ref='Boiler' and cycle_no='5'
group by end_date,prty_id,cmpnt_ref,seq_no
order by prty_id
This will probably be quite basic, but I am still pretty new to SQL. Any hints, advice or tips would be very much appreciated.
You could use ROW_NUMBER() to mark the rows in each group and only select the rows marked with 1 or 2 (The two "latest" rows)...
WITH
enumerated_hgmpcych AS
(
SELECT
seq_no, start_date, end_date, cmpnt_ref, prty_id,
ROW_NUMBER() OVER (PARTITION BY prty_id, cmpnt_ref
ORDER BY seq_no DESC
)
desc_seq_enumerator
FROM
hgmpcych
WHERE
prty_id in ('ABBEY10_TD12','ABBEY12_TD12')
AND cmpnt_ref='Boiler'
AND cycle_no='5'
)
SELECT
*
FROM
enumerated_hgmpcych
WHERE
desc_seq_enumerator <= 2
ORDER BY
prty_id,
cmpnt_ref,
seq_no
If you wanted to, you could collapse that to one row per group...
WITH
enumerated_hgmpcych AS
(
SELECT
seq_no, start_date, end_date, cmpnt_ref, prty_id,
ROW_NUMBER() OVER (PARTITION BY prty_id, cmpnt_ref
ORDER BY seq_no DESC
)
desc_seq_enumerator
FROM
hgmpcych
WHERE
prty_id in ('ABBEY10_TD12','ABBEY12_TD12')
AND cmpnt_ref='Boiler'
AND cycle_no='5'
)
SELECT
prty_id,
cmpnt_ref,
MAX(CASE WHEN desc_seq_enumerator = 1 THEN seq_no END) AS final_seq_no,
MAX(CASE WHEN desc_seq_enumerator = 1 THEN start_date END) AS final_start_date,
MAX(CASE WHEN desc_seq_enumerator = 1 THEN end_date END) AS final_end_date,
MAX(CASE WHEN desc_seq_enumerator = 2 THEN seq_no END) AS prev_seq_no,
MAX(CASE WHEN desc_seq_enumerator = 2 THEN start_date END) AS prev_start_date,
MAX(CASE WHEN desc_seq_enumerator = 2 THEN end_date END) AS prev_end_date
FROM
enumerated_hgmpcych
WHERE
desc_seq_enumerator <= 2
GROUP BY
prty_id,
cmpnt_ref
ORDER BY
prty_id,
cmpnt_ref
If you have max(seq_no), then you don't want it in the group by:
select max (seq_no) as SEQNO, end_date, cmpnt_ref, prty_id
from hgmpcych
where prty_id in ('ABBEY10_TD12', 'ABBEY12_TD12') and
cmpnt_ref = 'Boiler' and cycle_no = '5'
group by end_date, prty_id, cmpnt_ref
order by prty_id;
My objective is produce a dataset that shows a boatload of data from, in total, just shy of 50 tables, all in the same Oracle SQL database schema. Each table except the first consists of, as far as the report I'm building cares, two elements:
A foreign-key identifier that matches a row on the first table
A date
There may be many rows on one of these tables corresponding to one case, and it will NOT be the same number of rows from table to table.
My objective is to have each row in the first table show up as many times as needed to display all the results from the other tables once. So, something like this (except on a lot more tables):
CASE_FILE_ID INITIATED_DATE INSPECTION_DATE PAYMENT_DATE ACTION_DATE
------------ -------------- --------------- ------------ -----------
1000 10-JUL-1986 14-JUL-1987 10-JUL-1986
1000 14-JUL-1988 10-JUL-1987
1000 14-JUL-1989 10-JUL-1988
1000 10-JUL-1989
My current SQL code (shrunk down to five tables, but the rest all follow the same format as T1-T4):
SELECT DISTINCT
A.CASE_FILE_ID,
T1.DATE AS INITIATED_DATE,
T2.DATE AS INSPECTION_DATE,
T3.DATE AS PAYMENT_DATE,
T4.DATE AS ACTION_DATE
FROM
RECORDS.CASE_FILE A
LEFT OUTER JOIN RECORDS.INITIATE T1 ON A.CASE_FILE_ID = T1.CASE_FILE_ID
LEFT OUTER JOIN RECORDS.INSPECTION T2 ON A.CASE_FILE_ID = T2.CASE_FILE_ID
LEFT OUTER JOIN RECORDS.PAYMENT T3 ON A.CASE_FILE_ID = T3.CASE_FILE_ID
LEFT OUTER JOIN RECORDS.ACTION T4 ON A.CASE_FILE_ID = T4.CASE_FILE_ID
ORDER BY
A.CASE_FILE_ID
The problem is, the output this produces results in distinct combinations; so in the above example (where I added a 'WHERE' clause of A.CASE_FILE_ID = '1000'), instead of four rows for case 1000, it'd show twelve (1 Initiated Date * 3 Inspection Dates * 4 Payment Dates = 12 rows). Suffice it to say, as the number of tables increases, this would get very prohibitive in both display and runtime, very quickly.
What is the best way to get an output loosely akin to the ideal above, where any one date is only shown once? Failing that, is there a way to get it to only show as many lines for one CASE_FILE as it needs to show all the dates, even if some dates repeat within that?
There isn't a good way, but there are two ways. One method involves subqueries for each table and complex outer joins. The second involves subqueries and union all. Let's go with that one:
SELECT CASE_FILE_ID,
MAX(INITIATED_DATE) as INITIATED_DATE,
MAX(INSPECTION_DATE) as INSPECTION_DATE,
MAX(PAYMENT_DATE) as PAYMENT_DATE,
MAX(ACTION) as ACTION
FROM ((SELECT A.CASE_FILE_ID, NULL as INITIATED_DATE, NULL as INSPECTION_DATE,
NULL as PAYMENT_DATE, NULL as ACTION_DATE,
1 as seqnum
FROM RECORDS.CASE_FILE A
) UNION ALL
(SELECT T1.CASE_FILE_ID, DATE as INITIATED_DATE, NULL as INSPECTION_DATE,
NULL as PAYMENT_DATE, NULL as ACTION_DATE,
ROW_NUMBER() OVER (PARTITION BY CASE_FILE_ID ORDER BY DATE) as seqnum
FROM RECORDS.INITIATE
) UNION ALL
(SELECT T1.CASE_FILE_ID, NULL as INITIATED_DATE, DATE as INSPECTION_DATE,
NULL as PAYMENT_DATE, NULL as ACTION_DATE,
ROW_NUMBER() OVER (PARTITION BY CASE_FILE_ID ORDER BY DATE) as seqnum
FROM RECORDS.INSPECTION
) UNION ALL
(SELECT T1.CASE_FILE_ID, NULL as INITIATED_DATE, NULL as INSPECTION_DATE,
DATE as PAYMENT_DATE, NULL as ACTION_DATE,
ROW_NUMBER() OVER (PARTITION BY CASE_FILE_ID ORDER BY DATE) as seqnum
FROM RECORDS.PAYMENT
) UNION ALL
(SELECT T1.CASE_FILE_ID, NULL as INITIATED_DATE, NULL as INSPECTION_DATE,
NULL as PAYMENT_DATE, ACTION as ACTION_DATE,
ROW_NUMBER() OVER (PARTITION BY CASE_FILE_ID ORDER BY DATE) as seqnum
FROM RECORDS.ACTION
)
) a
GROUP BY CASE_FILE_ID, seqnum;
Hmmm, a closely related solution is easier to maintain:
SELECT CASE_FILE_ID,
MAX(CASE WHEN type = 'INITIATED' THEN DATE END) as INITIATED_DATE,
MAX(CASE WHEN type = 'INSPECTION' THEN DATE END) as INSPECTION_DATE,
MAX(CASE WHEN type = 'PAYMENT' THEN DATE END) as PAYMENT_DATE,
MAX(CASE WHEN type = 'ACTION' THEN DATE END) as ACTION
FROM ((SELECT A.CASE_FILE_ID, NULL as TYPE, NULL as DATE,
1 as seqnum
FROM RECORDS.CASE_FILE A
) UNION ALL
(SELECT T1.CASE_FILE_ID, 'INSPECTION', DATE,
ROW_NUMBER() OVER (PARTITION BY CASE_FILE_ID ORDER BY DATE) as seqnum
FROM RECORDS.INITIATE
) UNION ALL
(SELECT T1.CASE_FILE_ID, 'INSPECTION', DATE,
ROW_NUMBER() OVER (PARTITION BY CASE_FILE_ID ORDER BY DATE) as seqnum
FROM RECORDS.INSPECTION
) UNION ALL
(SELECT T1.CASE_FILE_ID, 'PAYMENT', DATE,
ROW_NUMBER() OVER (PARTITION BY CASE_FILE_ID ORDER BY DATE) as seqnum
FROM RECORDS.PAYMENT
) UNION ALL
(SELECT T1.CASE_FILE_ID, 'ACTION', DATE,
ROW_NUMBER() OVER (PARTITION BY CASE_FILE_ID ORDER BY DATE) as seqnum
FROM RECORDS.ACTION
)
) a
GROUP BY CASE_FILE_ID, seqnum;