问题
This is in continuation of this thread I have the below query to have the value as heading using
SELECT *
FROM (SELECT prod_id,
start_date AS dt,
start_date,
hours
FROM prod_timings t) PIVOT (SUM (hours)
FOR start_date
IN (TO_DATE ('18-SEP-17', 'DD-MON-YY') AS wed,
TO_DATE ('19-SEP-17', 'DD-MON-YY') AS thu))
ORDER BY prod_id, dt
Can I use the below query to use inside the IN clause of PIVOT to have the dates dynamic? The idea is to have a dynamic query inside the IN clause to avoid hard-coding of dates
SELECT *
FROM ( SELECT (TO_DATE (:end_date, 'DD-MM-YYYY') - LEVEL + 1) AS day
FROM DUAL
CONNECT BY LEVEL <=
( TO_DATE (:end_date, 'DD-MM-YYYY')
- TO_DATE (:start_date, 'DD-MM-YYYY')
+ 1))
Bind values
end_date - 19-Sep-17
start_date - 18-Sep-17
The output of the above is
19-Sep-17
18-Sep-17
Expected output is
╔═════════╦════════════╦════════╦════════╦═══════════╗
║ PROD_ID ║ START_DATE ║ MON-18 ║ TUE-19 ║ TOT_HOURS ║
╠═════════╬════════════╬════════╬════════╬═══════════╣
║ PR220 ║ 19-Sep-17 ║ ║ 0 ║ 0 ║
║ PR2230 ║ 19-Sep-17 ║ ║ 2 ║ 2 ║
║ PR9702 ║ 19-Sep-17 ║ ║ 3 ║ 3 ║
║ PR9036 ║ 19-Sep-17 ║ ║ 0.6 ║ 0.6 ║
║ PR9036 ║ 18-Sep-17 ║ 3.4 ║ ║ 3.4 ║
║ PR9609 ║ 18-Sep-17 ║ 5 ║ ║ 5 ║
║ PR91034 ║ 18-Sep-17 ║ 4 ║ ║ 4 ║
║ PR7127 ║ 18-Sep-17 ║ 0 ║ ║ 0 ║
╚═════════╩════════════╩════════╩════════╩═══════════╝
Table structure and values
CREATE TABLE PROD_TIMINGS
(
PROD_ID VARCHAR2(12 BYTE),
START_DATE DATE,
TOT_HOURS NUMBER
);
SET DEFINE OFF;
Insert into PROD_TIMINGS
(PROD_ID, START_DATE, TOT_HOURS)
Values
('PR220', TO_DATE('09/19/2017 00:00:00', 'MM/DD/YYYY HH24:MI:SS'), 0);
Insert into PROD_TIMINGS
(PROD_ID, START_DATE, TOT_HOURS)
Values
('PR2230', TO_DATE('09/19/2017 00:00:00', 'MM/DD/YYYY HH24:MI:SS'), 2);
Insert into PROD_TIMINGS
(PROD_ID, START_DATE, TOT_HOURS)
Values
('PR9702', TO_DATE('09/19/2017 00:00:00', 'MM/DD/YYYY HH24:MI:SS'), 3);
Insert into PROD_TIMINGS
(PROD_ID, START_DATE, TOT_HOURS)
Values
('PR9036', TO_DATE('09/19/2017 00:00:00', 'MM/DD/YYYY HH24:MI:SS'), 0.6);
Insert into PROD_TIMINGS
(PROD_ID, START_DATE, TOT_HOURS)
Values
('PR9036', TO_DATE('09/18/2017 00:00:00', 'MM/DD/YYYY HH24:MI:SS'), 3.4);
Insert into PROD_TIMINGS
(PROD_ID, START_DATE, TOT_HOURS)
Values
('PR9609', TO_DATE('09/18/2017 00:00:00', 'MM/DD/YYYY HH24:MI:SS'), 5);
Insert into PROD_TIMINGS
(PROD_ID, START_DATE, TOT_HOURS)
Values
('PR91034', TO_DATE('09/18/2017 00:00:00', 'MM/DD/YYYY HH24:MI:SS'), 4);
Insert into PROD_TIMINGS
(PROD_ID, START_DATE, TOT_HOURS)
Values
('PR7127', TO_DATE('09/18/2017 00:00:00', 'MM/DD/YYYY HH24:MI:SS'), 0);
COMMIT;
回答1:
Something like:
VARIABLE cur REFCURSOR;
DECLARE
dates VARCHAR2(4000);
start_date DATE := DATE '2017-09-18';
end_date DATE := DATE '2017-09-19';
BEGIN
SELECT LISTAGG(
'DATE ''' || TO_CHAR( dt, 'YYYY-MM-DD' )
|| ''' AS "' || TO_CHAR( dt, 'FMDY-DD' ) || '"',
','
) WITHIN GROUP ( ORDER BY dt )
INTO dates
FROM (
SELECT start_date + LEVEL - 1 AS dt
FROM DUAL
CONNECT BY LEVEL <= end_date - start_date + 1
);
OPEN :cur FOR
'SELECT * FROM (
SELECT t.*,
MIN( start_date ) OVER ( PARTITION BY prod_id ) AS min_start_date,
SUM( tot_hours ) OVER ( PARTITION BY prod_id ) AS prod_tot_hours
FROM prod_timings t
WHERE start_date BETWEEN :1 AND :2
)
PIVOT (
SUM( tot_hours )
FOR start_date IN (' || dates || ')
)
ORDER BY prod_id'
USING start_date, end_date;
END;
/
PRINT cur;
回答2:
First of all, it's quite ridiculous to use pivot by dates when original date column also part of expected output. This introduces new columns but row count remains the same.
Secondly, it's not possible to make column names depend on bind values. Column names are defined on parse stage and Oracle re-uses the same plan for different binds.
If you, however, want to pass start and end_date as binds and have predefined column titles you can use either
- case (or decode) + group by
- pivot for xml
Update:
Normal solution
SQL> select prod_id, dt,
2 sum(decode(dt, :start_date, tot_hours)) start_date_hours,
3 sum(decode(dt, :end_date, tot_hours)) end_date_hours,
4 sum(tot_hours) tot_hours
5 from (select prod_id, start_date as dt, start_date, tot_hours
6 from prod_timings t)
7 group by dt, prod_id
8 order by dt desc, prod_id;
PROD_ID DT START_DATE_HOURS END_DATE_HOURS TOT_HOURS
------------ --------- -------------------- -------------------- ----------
PR220 19-SEP-17 .0 0
PR2230 19-SEP-17 2.0 2
PR9036 19-SEP-17 .6 .6
PR9702 19-SEP-17 3.0 3
PR7127 18-SEP-17 .0 0
PR9036 18-SEP-17 3.4 3.4
PR91034 18-SEP-17 4.0 4
PR9609 18-SEP-17 5.0 5
8 rows selected.
Bizarre solution
SQL> with t as
2 (select *
3 from (select prod_id, start_date as dt, start_date, tot_hours
4 from prod_timings t)
5 pivot xml(sum(tot_hours) as s for start_date in
6 (select :start_date from dual union all select :end_date from dual)))
7 select prod_id, dt, start_date_hours, end_date_hours,
8 nvl(start_date_hours, end_date_hours) tot_hours
9 from t,
10 xmltable('/PivotSet' passing start_date_xml
11 columns
12 start_date_hours number
13 path '/PivotSet/item[1]/column[@name="S"]/text()',
14 end_date_hours number
15 path '/PivotSet/item[2]/column[@name="S"]/text()') x
16 order by dt desc, prod_id;
PROD_ID DT START_DATE_HOURS END_DATE_HOURS TOT_HOURS
------------ --------- -------------------- -------------------- ----------
PR220 19-SEP-17 .0 0
PR2230 19-SEP-17 2.0 2
PR9036 19-SEP-17 .6 .6
PR9702 19-SEP-17 3.0 3
PR7127 18-SEP-17 .0 0
PR9036 18-SEP-17 3.4 3.4
PR91034 18-SEP-17 4.0 4
PR9609 18-SEP-17 5.0 5
8 rows selected.
As for DSQL approach for this task... this is far away from common sense.
来源:https://stackoverflow.com/questions/46441419/dynamic-query-for-pivot-in-clause