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
Related
I have varchar column name Calc_code, with for example this varchar '100201', first two characters are Year (2010), third and fourth are month (02) and the last two characters are not related with date so they are not important. How will I convert into date so that I can in select in where clause give something like this:
select *
from table_a
where Calc_code >= p_year_from || p_month_from
and Calc_code <= p_year_to || p_month_to
You need the first 4 chars and you can get them with the function substr():
select *
from table_a
where substr(Calc_code, 1, 4) >= p_year_from || p_month_from
and substr(Calc_code, 1, 4) <= p_year_to || p_month_to
I assume that p_year_from, p_month_from, p_year_to and p_month_to are strings (since you concatenate them), padded with a 0 at the left if necessary.
Need to take the first four digits into consideration and then we can convert it using TO_DATE as following:
select to_date(SUBSTR('100201',1,4),'YYMM') FROM DUAL;
Note that output will be the first date of the month as the date is not given in TO_DATE function
Cheers!!
Use TO_DATE with the first 4 character substring of your value:
SELECT TO_DATE( SUBSTR( calc_code, 1, 4 ), 'RRMM' )
FROM DUAL;
So your assuming your p_year_from, etc values are numbers then the code would be:
SELECT *
FROM table_a
WHERE TO_DATE( SUBSTR( calc_code, 1, 4 ), 'RRMM' )
BETWEEN TO_DATE( TO_CHAR( p_year_from, '00' ) || TO_CHAR( p_month_from, '00' ), 'RRMM' )
AND TO_DATE( TO_CHAR( p_year_to, '00' ) || TO_CHAR( p_month_to, '00' ), 'RRMM' )
with YR_FROM as (select to_char(to_date(SUBSTR('100201',1,4),'YYMM'), 'YYYY-MM') FROM DUAL),--2010 Feb
YR_TO as (select to_char(to_date(SUBSTR('100301',1,4),'YYMM'), 'YYYY-MM') FROM DUAL) --2010 March
Select * from table_a
where to_char(CREATE_DATE, 'YYYY-MM') between (select * from YR_FROM) and (select * from YR_TO);
--Will give zero results
with YR as (select to_char(to_date(SUBSTR('100201',1,4),'YYMM'), 'YYYY-MM') FROM DUAL)
Select * from table_a
where to_char(CREATE_DATE, 'YYYY-MM') >= (select * from YR)
and to_char(CREATE_DATE, 'YYYY-MM') <=(select * from YR);
/* Formatted on 2015/06/24 15:51 (Formatter Plus v4.8.5) */
SELECT (SELECT NAME
FROM dept
WHERE deptid = department) AS NAME, SUM (received),
SUM (notresponded)
FROM (SELECT TRIM (regexp_substr (b.dept, '[^,]+', 1, LEVEL)
) AS department,
COUNT (*) received,
COUNT (*)
- COUNT
(CASE
WHEN ROUND
( ( TO_DATE
(TO_CHAR (clssndtm,
'YYYY-MM-DD hh24:mi'
),
'YYYY-MM-DD hh24:mi'
)
- TO_DATE
(TO_CHAR (made,
'YYYY-MM-DD hh24:mi'
),
'YYYY-MM-DD hh24:mi'
)
)
* 24
) <= 1
THEN ROUND
( ( TO_DATE
(TO_CHAR
(clssndtm,
'YYYY-MM-DD hh24:mi'
),
'YYYY-MM-DD hh24:mi'
)
- TO_DATE
(TO_CHAR
(made,
'YYYY-MM-DD hh24:mi'
),
'YYYY-MM-DD hh24:mi'
)
)
* 24
)
ELSE NULL
END
) notresponded
FROM reportng a, routing b
WHERE a.ticket = b.ticket
AND (1 = 1)
AND a.rptflag = 1
AND a.clssndtm IS NOT NULL
AND companyid = 2682
CONNECT BY INSTR (dept, ',', 1, LEVEL - 1) > 0
AND TRUNC (made) BETWEEN TRUNC (TO_DATE ('06/01/2015',
'mm/dd/yyyy'
)
)
AND TRUNC (TO_DATE ('06/23/2015',
'mm/dd/yyyy'
)
)
GROUP BY TRIM (regexp_substr (dept, '[^,]+', 1, LEVEL)))
GROUP BY department
Firstly, you want the query to be readable, otherwise it's impossible to see what's going on:
SELECT
(SELECT NAME FROM dept WHERE deptid = department) AS NAME,
SUM (received),
SUM (notresponded)
FROM
(SELECT
TRIM (regexp_substr (b.dept, '[^,]+', 1, LEVEL) ) AS department,
COUNT () received,
COUNT () - COUNT (CASE WHEN ROUND ( ( TO_DATE (TO_CHAR (clssndtm, 'YYYY-MM-DD hh24:mi' ), 'YYYY-MM-DD hh24:mi' ) - TO_DATE (TO_CHAR (made, 'YYYY-MM-DD hh24:mi' ), 'YYYY-MM-DD hh24:mi' ) ) * 24 ) <= 1 THEN ROUND ( ( TO_DATE (TO_CHAR (clssndtm, 'YYYY-MM-DD hh24:mi' ), 'YYYY-MM-DD hh24:mi' ) - TO_DATE (TO_CHAR (made, 'YYYY-MM-DD hh24:mi' ), 'YYYY-MM-DD hh24:mi' ) ) * 24 ) ELSE NULL END ) notresponded
FROM
reportng a,
routing b
WHERE
a.ticket = b.ticket
AND (1 = 1)
AND a.rptflag = 1
AND a.clssndtm IS NOT NULL
AND companyid = 2682
CONNECT BY INSTR (dept, ',', 1, LEVEL - 1) > 0 AND TRUNC (made) BETWEEN TRUNC (TO_DATE ('06/01/2015', 'mm/dd/yyyy' ) ) AND TRUNC (TO_DATE ('06/23/2015', 'mm/dd/yyyy' ) )
GROUP BY
TRIM (regexp_substr (dept, '[^,]+', 1, LEVEL))
)
GROUP BY
department
Now, there's some Oracle specific stuff in there that I don't understand but we can see there's 2 different major steps here. There's the first inner query, that may or may not be running efficiently. Run that on its own to see how it goes. I'm going to assume it's fine (it may not be).
The outer bit is definitely going to be suboptimal as you have a correlated query in the SELECT clause. That needs to be split out into a join:
SELECT
dept.NAME,
SUM (received),
SUM (notresponded)
FROM
complex_inner_query
inner join dept on dept.deptid = complex_inner_query.department
GROUP BY
department
That may well solve your problems, but if not you need to start analyzing the inner query to find the inefficiency.
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
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')
I have a list of tables for example:
mytableA
mytableB
mytableC
The tables all have same column (timestamp).
I can do a count on each table individually:
select count(*) from mytableA where timestamp = to_char(sysdate-1, 'yyyymmdd') || '0000';
select count(*) from mytableB where timestamp = to_char(sysdate-1, 'yyyymmdd') || '0000';
select count(*) from mytableC where timestamp = to_char(sysdate-1, 'yyyymmdd') || '0000';
How can I combine this in one single query? Is there an easy way?
Expected Results:
MyTableName MyCnt
----------- -----
mytableA 121
mytableB 78
mytableC 2345
SELECT (
SELECT COUNT(*)
FROM table1
) AS tot1,
(
SELECT COUNT(*)
FROM table2
) AS tottab2,
(
SELECT COUNT(*)
FROM table3
) AS tottab3
You can't do it directly with a query like where table in (myTableA, myTableB, etc)
But you can pretify the union all solution:
select MyTableName, count(*)
FROM(
select 'myTableA' MyTableName, timestamp from mytableA
union all
select 'myTableB', timestamp from mytableB
union all
select 'myTableA', timestamp from mytableC
)
WHERE timestamp = to_char(sysdate-1, 'yyyymmdd') || '0000'
GROUP BY MyTableName;
I am not sure about Oracle, in SQLserver you can do this as,
select (select count(*) from table1) + (select count(*) from table2)
Update:
or like this,
select (select count(*) from table1) ,(select count(*) from table2)
OR,
(select count(*) from table1) union (select count(*) from table2)
select 'myTableA' MyTableName, count(*) MyCnt from mytableA where timestamp = to_char(sysdate-1, 'yyyymmdd') || '0000'
union all
select 'myTableB', count(*) from mytableB where timestamp = to_char(sysdate-1, 'yyyymmdd') || '0000'
union all
select 'myTableC', count(*) from mytableC where timestamp = to_char(sysdate-1, 'yyyymmdd') || '0000';
Using Oracle 11gR2:
select
(select count(*) from mytableA where timestamp = to_char(sysdate-1, 'yyyymmdd') || '0000') tabA,
(select count(*) from mytableB where timestamp = to_char(sysdate-1, 'yyyymmdd') || '0000') tabB,
(select count(*) from mytableC where timestamp = to_char(sysdate-1, 'yyyymmdd') || '0000') tabC
from dual;
Results in:
tabA| tabB| tabC
----|-----|-----
121| 78| 2345
Try this
select 'mytableA' as tablename, count(*) from mytableA where timestamp = to_char(sysdate-1, 'yyyymmdd') || '0000'
union all
select 'mytableB' as tablename , count(*) from mytableB where timestamp = to_char(sysdate-1, 'yyyymmdd') || '0000'
union all
select'mytableB' as tablename , count(*) from mytableC where timestamp = to_char(sysdate-1, 'yyyymmdd') || '0000'
How about this?
SELECT
a, b, c
FROM
(select count(*) from mytableA where timestamp = to_char(sysdate-1, 'yyyymmdd') || '0000') AS a,
(select count(*) from mytableB where timestamp = to_char(sysdate-1, 'yyyymmdd') || '0000') AS b,
(select count(*) from mytableC where timestamp = to_char(sysdate-1, 'yyyymmdd') || '0000') AS c
dunno whether this works or not though :/