I want to amend my current query to only display the accounts (all fields) that do not have Keep_Flag = 'N' in the query results.
The query's intent is to identify accounts who met a specific condition in order for them to qualify for additional rate discounts. They have to meet the condition for every single month otherwise they are rejected from discount program (the query will pull the past 12 months from today's date).
Query that creates the monthly qualification as a 'Y' or 'N':
SELECT id, account_id, reg_con, tagg_reading, read_date,
CASE
WHEN reg_con * tagg_reading < 60
AND TO_CHAR(read_date, 'MM-DD') BETWEEN '06-15' AND '10-15' THEN 'Y'
WHEN reg_con * tagg_reading < 90
AND (TO_CHAR(read_date, 'MM-DD') BETWEEN '10-16' AND '12-31' OR TO_CHAR(read_date, 'MM-DD') BETWEEN '01-01' AND '06-14') THEN 'Y'
ELSE 'N'
END AS Keep_Flag
FROM test;
I have created a fiddle example with dummy data.
In the below screenshot, my expected results would only include Account_ID 1001. Account_ID 1002 would not qualify as it includes results that has a Keep_Flag ='N'.
The results I would like to see with the amended query
You could add an analytic/window function call to get the lowest flag value for each account ID, either in the same level of query by repeating the case expression, or more simply using a CTE or inline view (subquery):
SELECT id, account_id, reg_con, tagg_reading, read_date, Keep_Flag,
MIN(Keep_Flag) OVER (PARTITION BY account_id) AS Min_Keep_Flag
FROM (
SELECT id, account_id, reg_con, tagg_reading, read_date,
CASE
WHEN reg_con * tagg_reading < 60
AND TO_CHAR(read_date, 'MM-DD') BETWEEN '06-15' AND '10-15' THEN 'Y'
WHEN reg_con * tagg_reading < 90
AND (TO_CHAR(read_date, 'MM-DD') BETWEEN '10-16' AND '12-31' OR TO_CHAR(read_date, 'MM-DD') BETWEEN '01-01' AND '06-14') THEN 'Y'
ELSE 'N'
END AS Keep_Flag
FROM test
)
ORDER BY id;
ID | ACCOUNT_ID | REG_CON | TAGG_READING | READ_DATE | KEEP_FLAG | MIN_KEEP_FLAG |
---|---|---|---|---|---|---|
1 | 1001 | 4 | 20 | 10-DEC-23 | Y | Y |
2 | 1001 | 4 | 12 | 05-JAN-24 | Y | Y |
3 | 1001 | 2 | 40 | 25-FEB-24 | Y | Y |
4 | 1001 | 3 | 25 | 05-MAR-24 | Y | Y |
5 | 1001 | 1 | 10 | 20-APR-24 | Y | Y |
6 | 1001 | 4 | 12 | 10-MAY-24 | Y | Y |
7 | 1001 | 2 | 20 | 19-JUN-24 | Y | Y |
8 | 1001 | 1 | 35 | 25-JUL-24 | Y | Y |
9 | 1001 | 3 | 14 | 05-AUG-24 | Y | Y |
10 | 1001 | 1 | 10 | 20-SEP-24 | Y | Y |
11 | 1001 | 4 | 13 | 10-OCT-24 | Y | Y |
12 | 1001 | 2 | 33 | 15-NOV-24 | Y | Y |
13 | 1001 | 3 | 27 | 10-DEC-24 | Y | Y |
14 | 1002 | 1 | 10 | 10-DEC-23 | Y | N |
15 | 1002 | 4 | 36 | 05-JAN-24 | N | N |
16 | 1002 | 2 | 24 | 24-FEB-24 | Y | N |
17 | 1002 | 4 | 26 | 05-MAR-24 | N | N |
18 | 1002 | 2 | 22 | 20-APR-24 | Y | N |
19 | 1002 | 1 | 30 | 10-MAY-24 | Y | N |
20 | 1002 | 2 | 20 | 19-JUN-24 | Y | N |
21 | 1002 | 1 | 35 | 25-JUL-24 | Y | N |
22 | 1002 | 3 | 14 | 05-AUG-24 | Y | N |
23 | 1002 | 1 | 10 | 20-SEP-24 | Y | N |
24 | 1002 | 4 | 13 | 10-OCT-24 | Y | N |
25 | 1002 | 2 | 23 | 15-NOV-24 | Y | N |
26 | 1002 | 1 | 41 | 10-DEC-24 | Y | N |
And then filter out all the rows which don't have 'Y' as the lowest flag value, which exclude the accounts with any 'N' flags:
SELECT id, account_id, reg_con, tagg_reading, read_date, Keep_Flag
FROM (
SELECT id, account_id, reg_con, tagg_reading, read_date, Keep_Flag,
MIN(Keep_Flag) OVER (PARTITION BY account_id) AS Min_Keep_Flag
FROM (
SELECT id, account_id, reg_con, tagg_reading, read_date,
CASE
WHEN reg_con * tagg_reading < 60
AND TO_CHAR(read_date, 'MM-DD') BETWEEN '06-15' AND '10-15' THEN 'Y'
WHEN reg_con * tagg_reading < 90
AND (TO_CHAR(read_date, 'MM-DD') BETWEEN '10-16' AND '12-31' OR TO_CHAR(read_date, 'MM-DD') BETWEEN '01-01' AND '06-14') THEN 'Y'
ELSE 'N'
END AS Keep_Flag
FROM test
)
)
WHERE Min_Keep_Flag = 'Y'
ORDER BY id;
ID | ACCOUNT_ID | REG_CON | TAGG_READING | READ_DATE | KEEP_FLAG |
---|---|---|---|---|---|
1 | 1001 | 4 | 20 | 10-DEC-23 | Y |
2 | 1001 | 4 | 12 | 05-JAN-24 | Y |
3 | 1001 | 2 | 40 | 25-FEB-24 | Y |
4 | 1001 | 3 | 25 | 05-MAR-24 | Y |
5 | 1001 | 1 | 10 | 20-APR-24 | Y |
6 | 1001 | 4 | 12 | 10-MAY-24 | Y |
7 | 1001 | 2 | 20 | 19-JUN-24 | Y |
8 | 1001 | 1 | 35 | 25-JUL-24 | Y |
9 | 1001 | 3 | 14 | 05-AUG-24 | Y |
10 | 1001 | 1 | 10 | 20-SEP-24 | Y |
11 | 1001 | 4 | 13 | 10-OCT-24 | Y |
12 | 1001 | 2 | 33 | 15-NOV-24 | Y |
13 | 1001 | 3 | 27 | 10-DEC-24 | Y |
Or with CTEs instead of nested inline views:
WITH cte1 AS (
SELECT id, account_id, reg_con, tagg_reading, read_date,
CASE
WHEN reg_con * tagg_reading < 60
AND TO_CHAR(read_date, 'MM-DD') BETWEEN '06-15' AND '10-15' THEN 'Y'
WHEN reg_con * tagg_reading < 90
AND (TO_CHAR(read_date, 'MM-DD') BETWEEN '10-16' AND '12-31' OR TO_CHAR(read_date, 'MM-DD') BETWEEN '01-01' AND '06-14') THEN 'Y'
ELSE 'N'
END AS Keep_Flag
FROM test
),
cte2 AS (
SELECT id, account_id, reg_con, tagg_reading, read_date, Keep_Flag,
MIN(Keep_Flag) OVER (PARTITION BY account_id) AS Min_Keep_Flag
FROM cte1
)
SELECT id, account_id, reg_con, tagg_reading, read_date, Keep_Flag
FROM cte2
WHERE Min_Keep_Flag = 'Y'
ORDER BY id;
ID | ACCOUNT_ID | REG_CON | TAGG_READING | READ_DATE | KEEP_FLAG |
---|---|---|---|---|---|
1 | 1001 | 4 | 20 | 10-DEC-23 | Y |
2 | 1001 | 4 | 12 | 05-JAN-24 | Y |
3 | 1001 | 2 | 40 | 25-FEB-24 | Y |
4 | 1001 | 3 | 25 | 05-MAR-24 | Y |
5 | 1001 | 1 | 10 | 20-APR-24 | Y |
6 | 1001 | 4 | 12 | 10-MAY-24 | Y |
7 | 1001 | 2 | 20 | 19-JUN-24 | Y |
8 | 1001 | 1 | 35 | 25-JUL-24 | Y |
9 | 1001 | 3 | 14 | 05-AUG-24 | Y |
10 | 1001 | 1 | 10 | 20-SEP-24 | Y |
11 | 1001 | 4 | 13 | 10-OCT-24 | Y |
12 | 1001 | 2 | 33 | 15-NOV-24 | Y |
13 | 1001 | 3 | 27 | 10-DEC-24 | Y |