Using IW and MM in Oracle - sql

I'm using IW for weekly result and MM for Monthly result. But I always get an error:
ORA-00979: not a GROUP BY expression
00979. 00000 - "not a GROUP BY expression"
My queries are these
(Weekly)
SELECT 'Data'
|| ',' || TO_CHAR(d.dtime_day, 'MM/dd/yyyy')
|| ',' || NVL(o.cnt_opened, 0) --as cnt_opened
|| ',' || NVL(c.cnt_closed, 0) --as cnt_closed
FROM owner_dwh.dc_date d
LEFT JOIN (
SELECT
TRUNC(t.create_time, 'IW') AS report_date,
count(*) AS cnt_opened
FROM app_account.otrs_ticket t
WHERE t.create_time BETWEEN SYSDATE - 30 AND SYSDATE
GROUP BY TRUNC(t.create_time)
) o ON d.dtime_day = o.report_date
LEFT JOIN (
SELECT
TRUNC(t.close_time, 'IW') AS report_date,
count(*) AS cnt_closed
FROM app_account.otrs_ticket t
WHERE t.close_time BETWEEN SYSDATE - 30 AND SYSDATE
GROUP BY TRUNC(t.close_time)
) c ON d.dtime_day = c.report_date
WHERE d.dtime_day BETWEEN SYSDATE - 30 AND SYSDATE
ORDER BY d.dtime_day;
(Monthly)
SELECT 'Graph,ColumnChart,Open vs. Close Issues' FROM DUAL;
SELECT 'Data,Date,Opened,Closed' from dual;
SELECT 'Data'
|| ',' || TO_CHAR(d.dtime_day, 'MM/dd/yyyy')
|| ',' || NVL(o.cnt_opened, 0) --as cnt_opened
|| ',' || NVL(c.cnt_closed, 0) --as cnt_closed
FROM owner_dwh.dc_date d
LEFT JOIN ( SELECT
TRUNC(t.create_time, 'MM') AS report_date,
count(*) AS cnt_opened
FROM app_account.otrs_ticket t
WHERE t.create_time BETWEEN SYSDATE - 365 AND SYSDATE
GROUP BY TRUNC(t.create_time);
) o ON d.DTIME_DAY=o.REPORT_DATE
LEFT JOIN ( SELECT TRUNC(t.CLOSE_TIME, 'MM') AS report_date,
count(*) AS cnt_closed
FROM APP_ACCOUNT.OTRS_TICKET t
WHERE t.CLOSE_TIME BETWEEN SYSDATE -365 AND SYSDATE
GROUP BY TRUNC(t.CLOSE_TIME);
) c ON D.DTIME_DAY= C.REPORT_DATE
WHERE d.DTIME_DAY BETWEEN SYSDATE -365 AND SYSDATE
ORDER BY D.DTIME_DAY;

You have to group by the same expression you use in the SELECT clause.
So if you:
SELECT TRUNC(t.CREATE_TIME, 'MM') AS report_date,count(*) AS cnt_opened
... then you have to ...
GROUP BY TRUNC(t.CREATE_TIME,'MM')

Related

Connecting two queries using UNION ALL

I want to connect the following two queries with union all.
First query is following:
WITH
week_source
AS
(SELECT week_desc,
TO_CHAR (day_date, 'IYYY') || 'W' || TO_CHAR (day_date, 'IW')
week,
(SELECT DISTINCT day_number
FROM period_day
WHERE day_key = d.day_key AND day_number NOT IN ('H', 'W') AND WEEK_NUM !=to_char(sysdate, 'WW')
)
workdays_count
FROM period_day d
WHERE TO_CHAR (day_date, 'IYYYIW') BETWEEN TO_CHAR (
(SYSDATE - 1) - 28,
'IYYYIW')
AND TO_CHAR (
(SYSDATE - 1),
'IYYYIW')
)
SELECT DISTINCT week_desc, week, workdays_count
FROM week_source
WHERE workdays_count IS NOT NULL
ORDER BY week;
It gives following table
The second query is:
SELECT 'W' || TO_CHAR (SYSDATE - 1, 'IW') WEEK_DESC,
TO_CHAR (SYSDATE - 1, 'IYYYIW') WEEK,
COUNT (day_date) WORKDAYS_COUNT
FROM period_day
WHERE day_number NOT IN ('H', 'W')
AND TO_CHAR (day_date, 'IYYYIW') =
TO_CHAR ((SYSDATE - 1), 'IYYYIW')
AND day_date <= (SYSDATE - 1)
which gives the following table
Any help?
You have to put order by clauseat the end.
If the first query returns 3 columns with data types varchar, int, varchar then the second query has to return columns of same data types.
WITH week_source AS
(SELECT week_desc,
TO_CHAR (day_date, 'IYYY') || 'W' || TO_CHAR (day_date, 'IW') week,
(SELECT DISTINCT day_number
FROM period_day
WHERE day_key = d.day_key
AND day_number NOT IN ('H', 'W')
AND WEEK_NUM !=to_char(sysdate, 'WW')) workdays_count
FROM period_day d
WHERE TO_CHAR (day_date, 'IYYYIW') BETWEEN
TO_CHAR ((SYSDATE - 1) - 28, 'IYYYIW')
AND
TO_CHAR ((SYSDATE - 1),'IYYYIW'))
SELECT DISTINCT week_desc, week, workdays_count
FROM week_source
WHERE workdays_count IS NOT NULL
union all
SELECT 'W' || TO_CHAR (SYSDATE - 1, 'IW') WEEK_DESC,
TO_CHAR (SYSDATE - 1, 'IYYYIW') WEEK,
to_char(COUNT(day_date)) WORKDAYS_COUNT
FROM period_day
WHERE day_number NOT IN ('H', 'W')
AND TO_CHAR (day_date, 'IYYYIW') = TO_CHAR ((SYSDATE - 1), 'IYYYIW')
AND day_date <= (SYSDATE - 1)
ORDER BY week
In this DEMO you can see the errors returning when the order by is located after the first query. Also you can see what error you get if I just remove the order by clause and this second error is because data types that first query is returning is different that the data types second row is returning. That is why I have added to_char to your count function in your second query. You could of also add to_number in your first query like this: SELECT DISTINCT to_number(day_number).

Oracle SQL Group by not working correctly

I am running a query to return a count of a number of completed jobs per week, with the weeks broken down into 4-weekly periods based on a separate financial period table, but the query isn't returning the correct count.
Here is a sample of the code:
select (SELECT (fp.financialperiod || ' week ' ||
ceil(floor((wo.actfinish - p.periodstart+1))/7))
FROM maximo.financialperiods fp
WHERE TRUNC (wo.actfinish) BETWEEN fp.periodstart
AND fp.periodend) fin_period,
wo.wo8 as assetgroup,
Count(wo.wonum)
from maximo.workorder wo
where (TRUNC (wo.actfinish) BETWEEN TO_DATE (:startdate, 'DD/MM/YYYY')
AND TO_DATE (:enddate, 'DD/MM/YYYY'))
group by wo.actfinish,
wo.wo8
I suspect the reason is that you need to aggregate by the first column. Given the structure of your query, this is most easily done using a subquery:
select fin_period, wo.wo8, count(wo.wonum) as cnt
from (select (SELECT (fp.financialperiod || ' week ' || ceil(floor((wo.actfinish - p.periodstart+1))/7))
FROM maximo.financialperiods fp
WHERE TRUNC (wo.actfinish) BETWEEN fp.periodstart AND fp.periodend
) as fin_period,
wo.wo8 as assetgroup, wo.wonum
from maximo.workorder wo
where TRUNC(wo.actfinish) BETWEEN TO_DATE (:startdate, 'DD/MM/YYYY')
AND TO_DATE (:enddate, 'DD/MM/YYYY')
) t
group by fin_period, wo.wo8;
SELECT
(SELECT (fp.financialperiod || ' week ' || ceil(floor((wo.actfinish - p.periodstart+1))/7))
FROM maximo.financialperiods fp
WHERE TRUNC (wo.actfinish) BETWEEN fp.periodstart AND fp.periodend) fin_period, wo.wo8 as assetgroup, Count(wo.wonum) AS [Count]
FROM maximo.workorder wo
WHERE (TRUNC (wo.actfinish) BETWEEN TO_DATE (:startdate, 'DD/MM/YYYY')
AND TO_DATE (:enddate, 'DD/MM/YYYY'))
GROUP BY wo.actfinish, wo.wo8, fp.financialperiod

Using MM in Oracle [duplicate]

This question already has an answer here:
Using IW and MM in Oracle
(1 answer)
Closed 9 years ago.
I don't know what's wrong with my query. I just put 'MM' in my query to get the monthly result. But when I run it, it gives me a daily result in 365 days, instead of monthly result. Please help me.
Here's my query:
SELECT 'Data'
|| ',' || TO_CHAR(d.dtime_day, 'MM/dd/yyyy')
|| ',' || NVL(o.cnt_opened, 0) --as cnt_opened
|| ',' || NVL(c.cnt_closed, 0) --as cnt_closed
FROM owner_dwh.dc_date d
LEFT JOIN (
SELECT
TRUNC(t.create_time, 'MM') AS report_date,
count(*) AS cnt_opened
FROM app_account.otrs_ticket t
WHERE t.create_time BETWEEN SYSDATE - 365 AND SYSDATE
GROUP BY TRUNC(t.create_time, 'MM')
) o ON d.dtime_day = o.report_date
LEFT JOIN (
SELECT
TRUNC(t.close_time, 'MM') AS report_date,
count(*) AS cnt_closed
FROM app_account.otrs_ticket t
WHERE t.close_time BETWEEN SYSDATE - 365 AND SYSDATE
GROUP BY TRUNC(t.close_time, 'MM')
) c ON d.dtime_day = c.report_date
WHERE d.dtime_day BETWEEN SYSDATE - 365 AND SYSDATE
ORDER BY d.dtime_day;
Result:
Data,01/25/2013,0,0
Data,01/26/2013,0,0
Data,01/27/2013,0,0
Data,01/28/2013,0,0
Data,01/29/2013,0,0
Data,01/30/2013,0,0
Your initial query against DC_DATE is getting every date in the last 365 days. If you ran just that part:
SELECT 'Data'
||','||TO_CHAR(D.DTIME_DAY,'MM/dd/yyyy')
FROM OWNER_DWH.DC_DATE d
WHERE d.DTIME_DAY BETWEEN SYSDATE -365 AND SYSDATE
ORDER BY D.DTIME_DAY;
... you would expect to get 365 rows returned.
The subqueries you are outer-joining to are only going to return a summary count for the first day of each month. So when you join you will get an actual value (which could be zero) on the first of each month, but always zero on every other date. You could avoid that just by adjusting your where clause, e.g.:
WHERE d.DTIME_DAY BETWEEN SYSDATE -365 AND SYSDATE
AND d.DTIME_DAY = TRUNC(s.DTIME_DAY, 'MM')
The that will only show you the first of each month, and the outer joins will still show dates with zero values if there is no matching data from the subqueries.

how to pass outer query's table in inner query

This is my whole query
SELECT empmst.emp_id, empmst.emp_name,
(SELECT RTRIM
(XMLAGG (XMLELEMENT (e, d || ',')).EXTRACT ('//text()').EXTRACT
('//text()'),
','
)
FROM (SELECT TO_DATE ('01-04-2012', 'dd-MM-yyyy') - 1
+ ROWNUM AS d
FROM all_objects
WHERE TO_DATE ('01-04-2012', 'dd-MM-yyyy') - 1 + ROWNUM <=
TO_DATE ('30-04-2012', 'dd-MM-yyyy')
MINUS
SELECT tsd.ts_date
FROM ts_dtl tsd
WHERE empmst.emp_id = tsd.emp_id
AND tsd.ts_date BETWEEN TO_DATE ('01-04-2012',
'dd-MM-yyyy'
)
AND TO_DATE ('30-04-2012',
'dd-MM-yyyy'
))) AS day11
FROM emp_mst empmst
WHERE TSD.EMP_ID=EMPMST.EMP_ID
ORDER BY empmst.emp_id
I want to pass EMPMST.EMP_ID of the outer query to the inner query but inner query does'nt get EMPMST.EMP_ID in the where clause.
Please tell me how to pass outer query from table to inner query.
Inner query is as follows
(SELECT RTRIM
(XMLAGG (XMLELEMENT (e, d || ',')).EXTRACT ('//text()').EXTRACT
('//text()'),
','
)
FROM (SELECT TO_DATE ('01-04-2012', 'dd-MM-yyyy') - 1 + ROWNUM AS d
FROM all_objects
WHERE TO_DATE ('01-04-2012', 'dd-MM-yyyy') - 1 + ROWNUM <=
TO_DATE ('30-04-2012', 'dd-MM-yyyy')
MINUS
SELECT tsd.ts_date
FROM emp_mst empmst, ts_dtl tsd
WHERE empmst.emp_id = tsd.emp_id
AND ts_date BETWEEN TO_DATE ('01-04-2012', 'dd-MM-yyyy')
AND TO_DATE ('30-04-2012', 'dd-MM-yyyy')))
I want emp_name and emp_id and TS_date where TS_DATE which are not present in TS_DTL of april means the rest of the days of april which are not there in TS_DTL table
Please find the below which will achieve the same
SELECT EMPMST.EMP_ID,
EMPMST.EMP_NAME,
rtrim(xmlagg(xmlelement(e, b.d1 || ',')).extract('//text()')
.extract('//text()'),
',') as day11
from (SELECT TO_DATE('01-04-2012', 'dd-MM-yyyy') - 1 + rownum AS d1
FROM all_objects
WHERE TO_DATE('01-04-2012', 'dd-MM-yyyy') - 1 + rownum <=
TO_DATE('30-04-2012', 'dd-MM-yyyy')) b,
EMP_MST EMPMST
WHERE EMPMST.EMAIL_ID IS NOT NULL
AND EMPMST.DEPT IN ('Technical')
AND EMPMST.EMP_STATUS_LKP_ID = 201
AND b.d1 NOT IN
(SELECT TSD.TS_DATE as d2
FROM TS_DTL TSD
WHERE TSD.TS_DATE BETWEEN TO_DATE('01-04-2012', 'dd-MM-yyyy') AND
TO_DATE('30-04-2012', 'dd-MM-yyyy')
AND TSD.EMP_ID = EMPMST.EMP_ID)
ORDER BY EMPMST.EMP_ID

Given year, month, day and monthwise weeknumber, how can I find the date?

I have
Year : 2011
Month: Nov
Day: Sun
WeekNumber(Monthwise): 4
Desire Output:
Date
--------
2011-11-20
How can I do so in a single SQL statement?
Thanks
I'd probably look at using the NEXT_DAY function which returns the first day of the weekday provided that occurs after the date given. Once you've got that, you can then add the required number of weeks.
An example of this might be:
with test_data as (
select
'2011' as the_year,
'Nov' as the_month,
'Sun' as the_day,
4 as the_week
from dual
)
select
the_year, the_month, the_day, the_week,
next_day(to_date(the_year||the_month, 'YYYYMON') - 1, the_day) +
7* (the_week -1) as the_date
from test_data
this may work.
SELECT NEXT_DAY( TO_DATE(TO_CHAR((4-1)*7) || '-' || 'NOV' || '-' || '2011','dd-mon-yyyy') ,'Sun')
FROM DUAL
see: http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/functions093.htm
try :
SELECT A.B + B.D YourDate
FROM (SELECT TO_DATE (Your4DigitYear || LPAD ( YourMonth, 2, '0' ) || LPAD ( DECODE (YourWeekOfMonth, 1, '1', (YourWeekOfMonth - 1) * 7 ), 2, '0' ), 'YYYYMMDD') B FROM DUAL) A, (SELECT LEVEL - 1 D FROM DUAL CONNECT BY LEVEL < 15) B WHERE
TO_CHAR (A.B + B.D, 'D' ) = YourDayOfWeek AND
TO_CHAR (A.B + B.D, 'W' ) = YourWeekOfMonth;