sql subquery that collects from 3 rows - sql

I have a huge database with over 4 million rows that look like that:
Customer ID Shop
1 Asda
1 Sainsbury
1 Tesco
2 TEsco
2 Tesco
I need to count customers that within last 4 weeks had shopped in all 3 shops Tesco Sainsbury and Asda. Can you please advice if its possible to do it with subqueries?

This is an example of a "set-within-sets" subquery. You can solve it with aggregation:
select customer_id
from Yourtable t
where <shopping date within last four weeks>
group by customer_id
having sum(case when shop = 'Asda' then 1 else 0 end) > 0 and
sum(case when shop = 'Sainsbury' then 1 else 0 end) > 0 and
sum(case when shop = 'Tesco' then 1 else 0 end) > 0;
This structure is quite flexible. So if you wanted Asda and Tesco but not Sainsbury, then you would do:
select customer_id
from Yourtable t
where <shopping date within last four weeks>
group by customer_id
having sum(case when shop = 'Asda' then 1 else 0 end) > 0 and
sum(case when shop = 'Sainsbury' then 1 else 0 end) = 0 and
sum(case when shop = 'Tesco' then 1 else 0 end) > 0;
EDIT:
If you want a count, then use this as a subquery and count the results:
select count(*)
from (select customer_id
from Yourtable t
where <shopping date within last four weeks>
group by customer_id
having sum(case when shop = 'Asda' then 1 else 0 end) > 0 and
sum(case when shop = 'Sainsbury' then 1 else 0 end) > 0 and
sum(case when shop = 'Tesco' then 1 else 0 end) > 0
) t

Related

Adding a dummy identifier to data that varies by position and value

I am working on a project in SQL Server with diagnosis codes and a patient can have up to 4 codes but not necessarily more than 1 and a patient cannot repeat a code more than once. However, codes can occur in any order. My goal is to be able to count how many times a Diagnosis code appears in total, as well as how often it appears in a set position.
My data currently resembles the following:
PtKey
Order #
Order Date
Diagnosis1
Diagnosis2
Diagnosis3
Diagnosis 4
345
1527
7/12/20
J44.9
R26.2
NULL
NULL
367
1679
7/12/20
R26.2
H27.2
G47.34
NULL
325
1700
7/12/20
G47.34
NULL
NULL
NULL
327
1710
7/12/20
I26.2
J44.9
G47.34
NULL
I would think the best approach would be to create a dummy column here that would match up the diagnosis by position. For example, Diagnosis 1 with A, and Diagnosis 2 with B, etc.
My current plan is to rollup the diagnosis using an unpivot:
UNPIVOT ( Diag for ColumnALL IN (Diagnosis1, Diagnosis2, Diagnosis3, Diagnosis4)) as unpvt
However, this still doesn’t provide a way to count the diagnoses by position on a sales order.
I want it to look like this:
Diagnosis
Total Count
Diag1 Count
Diag2 Count
Diag3 Count
Diag4 Count
J44.9
2
1
1
0
0
R26.2
1
1
0
0
0
H27.2
1
0
1
0
0
I26.2
1
1
0
0
0
G47.34
3
1
0
2
0
You can unpivot using apply and aggregate:
select v.diagnosis, count(*) as cnt,
sum(case when pos = 1 then 1 else 0 end) as pos_1,
sum(case when pos = 2 then 1 else 0 end) as pos_2,
sum(case when pos = 3 then 1 else 0 end) as pos_3,
sum(case when pos = 4 then 1 else 0 end) as pos_4
from data d cross apply
(values (diagnosis1, 1),
(diagnosis2, 2),
(diagnosis3, 3),
(diagnosis4, 4)
) v(diagnosis, pos)
where diagnosis is not null;
Another way is to use UNPIVOT to transform the columns into groupable entities:
SELECT Diagnosis, [Total Count] = COUNT(*),
[Diag1 Count] = SUM(CASE WHEN DiagGroup = N'Diagnosis1' THEN 1 ELSE 0 END),
[Diag2 Count] = SUM(CASE WHEN DiagGroup = N'Diagnosis2' THEN 1 ELSE 0 END),
[Diag3 Count] = SUM(CASE WHEN DiagGroup = N'Diagnosis3' THEN 1 ELSE 0 END),
[Diag4 Count] = SUM(CASE WHEN DiagGroup = N'Diagnosis4' THEN 1 ELSE 0 END)
FROM
(
SELECT * FROM #x UNPIVOT (Diagnosis FOR DiagGroup IN
([Diagnosis1],[Diagnosis2],[Diagnosis3],[Diagnosis4])) up
) AS x GROUP BY Diagnosis;
Example db<>fiddle
You can also manually unpivot via UNION before doing the conditional aggregation:
SELECT Diagnosis, COUNT(*) As Total Count
, SUM(CASE WHEN Position = 1 THEN 1 ELSE 0 END) As [Diag1 Count]
, SUM(CASE WHEN Position = 2 THEN 1 ELSE 0 END) As [Diag2 Count]
, SUM(CASE WHEN Position = 3 THEN 1 ELSE 0 END) As [Diag3 Count]
, SUM(CASE WHEN Position = 4 THEN 1 ELSE 0 END) As [Diag4 Count]
FROM
(
SELECT PtKey, Diagnosis1 As Diagnosis, 1 As Position
FROM [MyTable]
UNION ALL
SELECT PtKey, Diagnosis2 As Diagnosis, 2 As Position
FROM [MyTable]
WHERE Diagnosis2 IS NOT NULL
UNION ALL
SELECT PtKey, Diagnosis3 As Diagnosis, 3 As Position
FROM [MyTable]
WHERE Diagnosis3 IS NOT NULL
UNION ALL
SELECT PtKey, Diagnosis4 As Diagnosis, 4 As Position
FROM [MyTable]
WHERE Diagnosis4 IS NOT NULL
) d
GROUP BY Diagnosis
Borrowing Aaron's fiddle, to avoid needing to rebuild the schema from scratch, and we get this:
https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=d1f7f525e175f0f066dd1749c49cc46d

How to calculate a Cumulative total using SQL

I have a Tickets table in My database , each Ticket have a status_id (1,2,3)
1: Ticket IN PROGRESS
2: Ticket Out Of time
3: Ticket Closed
I want using SQL to calculate the number of tickets for each status .
Calculate the cumulative total for each Status in a specific Date, I have already a column affectation_Date that contains the date where the status of ticket has been changed .
Use conditional aggregation as
SELECT TicketID,
AffectationDate,
SUM(CASE WHEN StatusID = 1 THEN 1 ELSE 0 END) InProgress,
SUM(CASE WHEN StatusID = 2 THEN 1 ELSE 0 END) OuOfTime,
SUM(CASE WHEN StatusID = 3 THEN 1 ELSE 0 END) Closed,
COUNT(1) Total
FROM Tickets
GROUP BY TicketID,
AffectationDate
ORDER BY TicketID,
AffectationDate;
Or if you want to GROUP BY AffectationDate only
SELECT AffectationDate,
SUM(CASE WHEN StatusID = 1 THEN 1 ELSE 0 END) TotalInProgress,
SUM(CASE WHEN StatusID = 2 THEN 1 ELSE 0 END) TotalOutOfTime,
SUM(CASE WHEN StatusID = 3 THEN 1 ELSE 0 END) TotalClosed,
COUNT(1) TotalStatusThisDate
FROM Tickets
GROUP BY AffectationDate
ORDER BY AffectationDate;
Live Demo
Using conditional counts.
SELECT affectation_Date,
COUNT(CASE WHEN status_id = 1 THEN 1 END) AS TotalInProgress,
COUNT(CASE WHEN status_id = 2 THEN 1 END) AS TotalOutOfTime,
COUNT(CASE WHEN status_id = 3 THEN 1 END) AS TotalClosed
FROM Tickets t
GROUP BY affectation_Date
ORDER BY affectation_Date
you may use the desired filter condition for the date criteria
SELECT COUNT(1), STATUS
FROM tickets
WHERE affectation_Date >= 'someDate'
group by status
Regards
You just need to group by status and count the number of tickets in each group:
select status, count(*) as number
from Tickets
where dt >= '2019-01-01 00:00:00' and dt < '2019-01-02 00:00:00'
group by status
having status >= 1 and status <= 3
This adds the Cumulative Sum to the existing answers:
SELECT AffectationDate,
Sum(CASE WHEN StatusID = 1 THEN 1 ELSE 0 END) AS TotalInProgress,
Sum(CASE WHEN StatusID = 2 THEN 1 ELSE 0 END) AS TotalOutOfTime,
Sum(CASE WHEN StatusID = 3 THEN 1 ELSE 0 END) AS TotalClosed,
Count(*) as TotalStatusThisDate,
Sum(Sum(CASE WHEN StatusID = 1 THEN 1 ELSE 0 END)) Over (ORDER BY AffectationDate) AS cumTotalInProgress,
Sum(Sum(CASE WHEN StatusID = 2 THEN 1 ELSE 0 END)) Over (ORDER BY AffectationDate) AS cumTotalOutOfTime,
Sum(Sum(CASE WHEN StatusID = 3 THEN 1 ELSE 0 END)) Over (ORDER BY AffectationDate) AS cumTotalClosed,
Sum(Count(*)) Over (ORDER BY AffectationDate) AS cumTotalStatusThisDate
FROM Tickets
GROUP BY AffectationDate
ORDER BY AffectationDate;

How to nest a join into a complicated Select sum(case, group by statement

I am trying to generate a report, and so far have one completed that gives me how many orders, for each day, are in status 1-9.
TableA structure looks like this:
Sales Order | Order Status | Order Date
123456789 | 1 | 2017-02-22 00:00:00.000
123456790 | 0 | 2017-02-21 00:00:00.000
TableB structure looks like this:
Sales Order | Price
123456789 | 123.00
123456789 | 42.00
123456790 | 56.00
123456790 | 28.00
This code:
SELECT
MAX(year([OrderDate])) as Yr,
MAX(MONTH([OrderDate])) as M,
Day([OrderDate]) as Day,
sum(case when [OrderStatus]='0' THEN 1 ELSE 0 END) AS 'STATUS"0"',
sum(case when [OrderStatus]='1' THEN 1 ELSE 0 END) AS 'STATUS"1"',
sum(case when [OrderStatus]='2' THEN 1 ELSE 0 END) AS 'STATUS"2"',
sum(case when [OrderStatus]='4' THEN 1 ELSE 0 END) AS 'STATUS"4"',
sum(case when [OrderStatus]='8' THEN 1 ELSE 0 END) AS 'STATUS"8"',
sum(case when [OrderStatus]='9' THEN 1 ELSE 0 END) AS 'STATUS"9"',
sum(case when [OrderStatus]='S' THEN 1 ELSE 0 END) AS 'STATUS"S"',
sum(case when [OrderStatus]='*' THEN 1 ELSE 0 END) AS 'STATUS"*"',
sum(case when [OrderStatus]='/' THEN 1 ELSE 0 END) AS 'STATUS"/"'
FROM
SorMaster
WHERE
YEAR([OrderDate]) = YEAR(GETDATE())
GROUP BY
DATENAME(month, DateAdd(month, Month([OrderDate]) - 1, Cast('2008-01-01' AS Datetime))), Day([OrderDate])
ORDER BY
Yr DESC, M DESC, Day DESC
Returns this:
Yr | M | Day | STATUS"0" | STATUS"1" | STATUS"2" | STATUS"4" | STATUS"8" | STATUS"9" | STATUS"S" | STATUS"*" | STATUS"/"
2017 2 22 0 2 0 1 0 0 5 0 0
2017 2 21 0 0 0 7 0 0 0 0 0
This is PERFECT for my first report.
Now, comes the trouble. My Problem is that I need to nest-query Table B, so that instead of returning a count(orders), I need the sum(orders) those totals for each order are in Table B.
Using the above example, the query would need to return something like this:
Yr | M | Day | STATUS"0" | STATUS"1" | STATUS"2" | STATUS"4" | STATUS"8" | STATUS"9" | STATUS"S" | STATUS"*" | STATUS"/"
2017 2 22 0 165 0 0 0 0 0 0 0
2017 2 21 84 0 0 0 0 0 0 0 0
Any pointers?
Just join to TableB:
SELECT MAX(year([t1.OrderDate])) AS Yr,
MAX(MONTH([t2.OrderDate])) AS M,
DAY([t1.OrderDate]) AS Day,
SUM(CASE WHEN [OrderStatus] = '0' THEN t2.Price ELSE 0 END) AS 'STATUS"0"',
SUM(CASE WHEN [OrderStatus] = '1' THEN t2.Price ELSE 0 END) AS 'STATUS"1"',
SUM(CASE WHEN [OrderStatus] = '2' THEN t2.Price ELSE 0 END) AS 'STATUS"2"',
SUM(CASE WHEN [OrderStatus] = '4' THEN t2.Price ELSE 0 END) AS 'STATUS"4"',
SUM(CASE WHEN [OrderStatus] = '8' THEN t2.Price ELSE 0 END) AS 'STATUS"8"',
SUM(CASE WHEN [OrderStatus] = '9' THEN t2.Price ELSE 0 END) AS 'STATUS"9"',
SUM(CASE WHEN [OrderStatus] = 'S' THEN t2.Price ELSE 0 END) AS 'STATUS"S"',
SUM(CASE WHEN [OrderStatus] = '*' THEN t2.Price ELSE 0 END) AS 'STATUS"*"',
SUM(CASE WHEN [OrderStatus] = '/' THEN t2.Price ELSE 0 END) AS 'STATUS"/"'
FROM SorMaster t1
LEFT JOIN TableB t2
ON t1.[Sales Order] = t2.[Sales Order]
WHERE YEAR([OrderDate]) = YEAR(GETDATE())
GROUP BY DATENAME(month,DateAdd(month,Month([OrderDate])-1,Cast('2008-01-01' AS Datetime))),
DAY([OrderDate])
ORDER BY Yr DESC, M DEACLLSC, Day DESC
That's not too difficult, just a matter of LEFT JOINing in table B and then summing the prices in that. There's a couple of small tricks here. You want to LEFT JOIN to ensure that rows in table A always show up, even if there are no corresponding rows in table B. Secondly, in your SUM() statement, you'll need to add a COALESCE(...,0.00) to ensure you're summing decimals and no NULL values creep in from the LEFT JOIN. Oddly in databases, NULL + {anything} = NULL.
For the below query, you'll need to change the name of TableB to whatever the table name is, and the JOIN predicate will need to have the column names named accurately, and delimited correctly if they contain spaces. For example, in MSSQL the delimiters are [ and ], e.g. MyTable.[My Column With Spaces]
SELECT
MAX(YEAR([OrderDate])) as Yr,
MAX(MONTH([OrderDate])) as M,
DAY([OrderDate]) as Day,
sum(case when [OrderStatus]='0' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"0"',
sum(case when [OrderStatus]='1' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"1"',
sum(case when [OrderStatus]='2' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"2"',
sum(case when [OrderStatus]='4' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"4"',
sum(case when [OrderStatus]='8' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"8"',
sum(case when [OrderStatus]='9' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"9"',
sum(case when [OrderStatus]='S' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"S"',
sum(case when [OrderStatus]='*' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"*"',
sum(case when [OrderStatus]='/' THEN COALESCE(TableB.Price, 0.00) ELSE 0.00 END) AS 'STATUS"/"'
FROM SorMaster
LEFT OUTER JOIN TableB
ON TableB.SalesOrder = SorMaster.SalesOrder
WHERE YEAR([OrderDate]) = YEAR(GETDATE())
GROUP BY
DATENAME(month,DateAdd(month,Month([OrderDate])-1,Cast('2008-01-01' AS Datetime))),
DAY([OrderDate])
ORDER BY
Yr DESC,
M DESC,
Day DESC
By (left) joining tableB and replacing your 'count' ones by tableB.price you should get the sum of all positions of orders with the according status.

Need Help on Oracle Select Query

I am finding difficulty to frame a select query.
PFB, for the table and corresponding data:
ID DLS MATCH_STATUS LAST_UPDATE_TIME BO CH FT
1 0 0 09-07-2013 00:00:00 IT TE NA
1 1 1 09-07-2013 00:01:01 IT TE NA
2 0 0 09-07-2013 10:00:00 IP TE NA
3 0 0 09-07-2013 11:00:00 IT YT NA
3 2 2 09-07-2013 11:01:00 IT YT NA
Here
Match_Status 0-->Initial Record
1-->Singel Match
2-->Multi Match
For every record there will be a initial entry with match_status 0 and subsequent matching process end other number such as 1,2 will be update.
I am trying to retrieve records such as total record , waiting match ,single match and multi match group by BO, CH and FT
Below is the expected out put:
BO CH FT TOTAL_RECORD AWAITNG_MATCH SINGLE_MATCH MULTI_MATCH
IT TE NA 1 0 1 0
IP TE NA 1 1 0 0
IT YT NA 1 0 0 2
I have tried below query :
select BO,CH,FT,sum(case when match_status=0 then 1 else 0 end) as TOTAL_RECORD,
sum(case when match_status = 0 then 1 else 0 end) as AWAITING_MATCH,
sum(case when match_status = 1 then 1 else 0 end) as SINGLE_MATCH,
sum(case when match_status = 2 then 1 else 0 end) as MULTI_MATCH from
table1 where last_update_time >= current_timestamp-1
group by BO,CH,FT;
problem with the above query is, awaiting_match is getting populated same as total record as I understand because of match_status=0
Similarly I tried with
select BO,CH,FT,sum(case when match_status=0 then 1 else 0 end) as TOTAL_RECORD,
select (sum(case when t1.ms=0 then 1 else 0 end) from
(select max(match_status) as ms from table1 where last_update_time >= current_timestamp-1 group by id)t1) )awaiting_match,
sum(case when match_status = 1 then 1 else 0 end) as SINGLE_MATCH,
sum(case when match_status = 2 then 1 else 0 end) as MULTI_MATCH from
table1 where last_update_time >= current_timestamp-1
group by BO,CH,FT;
problem with the approach is awaiting_match is getting populated with the same value for subsequent row entry.
Please help me with a suitable query for the desired format.
Thanks a lot in advance.
It seems that you want the last match status. I am guessing that this is actually the maximum of the statuses. If so, the following solves the problem by first grouping on id and then doing the grouping to summarize:
select BO, CH, FT,
count(*) as TOTAL_RECORD,
sum(case when lastms = 0 then 1 else 0 end) as AWAITING_MATCH,
sum(case when lastms = 1 then 1 else 0 end) as SINGLE_MATCH,
sum(case when lastms = 2 then 1 else 0 end) as MULTI_MATCH
from (select id, bo, ch, ft, MAX(match_status) as lastms
from table1
where last_update_time >= current_timestamp-1
group by id, bo, ch, ft
) t
group by BO, CH, FT;
If you actually want the last update to provide the status for the id, then you can use row_number() to enumerate the rows for each id, order by update time descending, and choose the first one:
select BO, CH, FT,
count(*) as TOTAL_RECORD,
sum(case when lastms = 0 then 1 else 0 end) as AWAITING_MATCH,
sum(case when lastms = 1 then 1 else 0 end) as SINGLE_MATCH,
sum(case when lastms = 2 then 1 else 0 end) as MULTI_MATCH
from (select id, bo, ch, ft, match_status,
ROW_NUMBER() over (partition by id order by last_update_time desc) as seqnum
from table1
where last_update_time >= current_timestamp-1
) t
where seqnum = 1
group by BO, CH, FT;

How To Accumulator All The Values

the output i would like to display was accumulator of total EMPL_NUM. For example, the value show in the field TOTAL_FEBRUARY=TOTAL_JANUARY+TOTAL_FEBRUARY,while for the value exist in field TOTAL_MARCH=TOTAL_MARCH+TOTAL_JANUARY+TOTAL_FEBRUARY. I hope some of you can provide the solution for do it. Thank you very much. The coding is show as below:
SELECT
(CASE WHEN To_Char(A.EFFDT,'MM')=01 THEN 1
WHEN To_Char(A.EFFDT,'MM')=02 THEN 2
WHEN To_Char(A.EFFDT,'MM')=03 THEN 3
WHEN To_Char(A.EFFDT,'MM')=04 THEN 4
WHEN To_Char(A.EFFDT,'MM')=05 THEN 5
WHEN To_Char(A.EFFDT,'MM')=06 THEN 6
WHEN To_Char(A.EFFDT,'MM')=07 THEN 7
WHEN To_Char(A.EFFDT,'MM')=08 THEN 8
WHEN To_Char(A.EFFDT,'MM')=09 THEN 9
WHEN To_Char(A.EFFDT,'MM')=10 THEN 10
WHEN To_Char(A.EFFDT,'MM')=11 THEN 11
WHEN To_Char(A.EFFDT,'MM')=12 THEN 12
ELSE NULL END) AS MONTHS
,Count(*) AS EMPL_NUM
,Sum(CASE WHEN To_Char(A.EFFDT,'MM')=01 THEN 1 ELSE 0 END) AS TOTAL_JANUARY
,Sum(CASE WHEN To_Char(A.EFFDT,'MM')=02 THEN 1 ELSE 0 END) AS TOTAL_FEBRUARY
,Sum(CASE WHEN To_Char(A.EFFDT,'MM')=03 THEN 1 ELSE 0 END) AS TOTAL_MARCH
,Sum(CASE WHEN To_Char(A.EFFDT,'MM')=04 THEN 1 ELSE 0 END) AS TOTAL_APRIL
,Sum(CASE WHEN To_Char(A.EFFDT,'MM')=05 THEN 1 ELSE 0 END) AS TOTAL_MAY
,Sum(CASE WHEN To_Char(A.EFFDT,'MM')=06 THEN 1 ELSE 0 END) AS TOTAL_JUN
,Sum(CASE WHEN To_Char(A.EFFDT,'MM')=07 THEN 1 ELSE 0 END) AS TOTAL_JULY
,Sum(CASE WHEN To_Char(A.EFFDT,'MM')=08 THEN 1 ELSE 0 END) AS TOTAL_AUGUST
,Sum(CASE WHEN To_Char(A.EFFDT,'MM')=09 THEN 1 ELSE 0 END) AS TOTAL_SEPTEMBER
,Sum(CASE WHEN To_Char(A.EFFDT,'MM')=10 THEN 1 ELSE 0 END) AS TOTAL_OCTOBER
,Sum(CASE WHEN To_Char(A.EFFDT,'MM')=11 THEN 1 ELSE 0 END) AS TOTAL_NOVEMBER
,Sum(CASE WHEN To_Char(A.EFFDT,'MM')=12 THEN 1 ELSE 0 END) AS TOTAL_DECEMBER
FROM PS_JOB A
,PS_CITIZEN_PSSPRT B
,PS_CITIZENSHIP C
,PS_CITIZEN_STS_TBL D
WHERE A.HR_STATUS='A'
AND A.EFFDT=(SELECT Max(A1.EFFDT) FROM PS_JOB A1 WHERE A.EMPLID=A1.EMPLID AND A.EMPL_RCD=A1.EMPL_RCD AND A1.EFFDT<=SYSDATE)
AND A.EMPL_RCD=0
AND A.EFFSEQ=(SELECT Max(A2.EFFSEQ) FROM PS_JOB A2 WHERE A.EMPLID=A2.EMPLID AND A.EMPL_RCD=A2.EMPL_RCD AND A.EFFDT=A2.EFFDT)
AND A.EMPLID =B.EMPLID(+)
AND B.DEPENDENT_ID=' '
AND A.EMPLID=C.EMPLID
AND B.EMPLID=C.EMPLID
AND B.DEPENDENT_ID=C.DEPENDENT_ID
AND B.COUNTRY=C.COUNTRY
AND B.COUNTRY=D.COUNTRY
AND C.COUNTRY=D.COUNTRY
AND C.CITIZENSHIP_STATUS=D.CITIZENSHIP_STATUS
AND C.CITIZENSHIP_STATUS IN ('5','7')
AND To_Char(A.EFFDT,'YYYY')=2012
GROUP BY CASE WHEN To_Char(A.EFFDT,'MM')=01 THEN 1
WHEN To_Char(A.EFFDT,'MM')=02 THEN 2
WHEN To_Char(A.EFFDT,'MM')=03 THEN 3
WHEN To_Char(A.EFFDT,'MM')=04 THEN 4
WHEN To_Char(A.EFFDT,'MM')=05 THEN 5
WHEN To_Char(A.EFFDT,'MM')=06 THEN 6
WHEN To_Char(A.EFFDT,'MM')=07 THEN 7
WHEN To_Char(A.EFFDT,'MM')=08 THEN 8
WHEN To_Char(A.EFFDT,'MM')=09 THEN 9
WHEN To_Char(A.EFFDT,'MM')=10 THEN 10
WHEN To_Char(A.EFFDT,'MM')=11 THEN 11
WHEN To_Char(A.EFFDT,'MM')=12 THEN 12
ELSE NULL END
nter code here
Use <= operator when calculating SUM, e.g.:
Sum(CASE WHEN TO_NUMBER(To_Char(A.EFFDT,'MM')) <= 3 THEN 1 ELSE 0 END) AS TOTAL_MARCH
I think what you are asking for is a running total. Take a look at analytic functions (for example, the psoug site). If the core of your query is correct, do a regular aggregate in the inner query, then wrap that in an analytic function for the running total.
SELECT month
,SUM(month_count) OVER ( ROWS BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW )
AS running_total
FROM ( SELECT To_Char(A.EFFDT,'MM') AS month
,COUNT(*) AS month_count
FROM PS_JOB A
,PS_CITIZEN_PSSPRT B
,PS_CITIZENSHIP C
,PS_CITIZEN_STS_TBL D
WHERE A.HR_STATUS='A'
AND A.EFFDT=( SELECT Max(A1.EFFDT)
FROM PS_JOB A1
WHERE A.EMPLID=A1.EMPLID
AND A.EMPL_RCD=A1.EMPL_RCD
AND A1.EFFDT<=SYSDATE )
AND A.EMPL_RCD=0
AND A.EFFSEQ=( SELECT Max(A2.EFFSEQ)
FROM PS_JOB A2
WHERE A.EMPLID=A2.EMPLID
AND A.EMPL_RCD=A2.EMPL_RCD
AND A.EFFDT=A2.EFFDT )
AND A.EMPLID =B.EMPLID(+)
AND B.DEPENDENT_ID=' '
AND A.EMPLID=C.EMPLID
AND B.EMPLID=C.EMPLID
AND B.DEPENDENT_ID=C.DEPENDENT_ID
AND B.COUNTRY=C.COUNTRY
AND B.COUNTRY=D.COUNTRY
AND C.COUNTRY=D.COUNTRY
AND C.CITIZENSHIP_STATUS=D.CITIZENSHIP_STATUS
AND C.CITIZENSHIP_STATUS IN ('5','7')
AND To_Char(A.EFFDT,'YYYY')=2012
GROUP BY To_Char(A.EFFDT,'MM')
)
ORDER BY month