Reputation: 14731
I have the following data in table EMP_DATES
.
I would like to achieve the following output from the table:
How can I do this. I have used the following SQL query, however not sure how to get Day as column header.
SELECT TO_CHAR (start_date, 'Day'),
TO_CHAR (completion_date, 'Day'),
start_date,
completion_date,
ROUND ( (completion_date - start_date) * 24, 1)
FROM emp_dates
Table:
CREATE TABLE EMP_DATES
(
START_DATE DATE,
COMPLETION_DATE DATE
);
SET DEFINE OFF;
INSERT INTO EMP_DATES (START_DATE, COMPLETION_DATE)
VALUES (
TO_DATE ('02/29/2016 12:24:25', 'MM/DD/YYYY HH24:MI:SS'),
TO_DATE ('02/29/2016 15:30:00', 'MM/DD/YYYY HH24:MI:SS'));
INSERT INTO EMP_DATES (START_DATE, COMPLETION_DATE)
VALUES (
TO_DATE ('03/01/2016 07:00:00', 'MM/DD/YYYY HH24:MI:SS'),
TO_DATE ('03/01/2016 11:54:25', 'MM/DD/YYYY HH24:MI:SS'));
COMMIT;
Upvotes: 0
Views: 301
Reputation: 191235
You're trying to pivot your rows into columns, but as you're on 10g the actual PIVOT clause isn't available; so you need to do it the expanded way with case statements and aggregation:
SELECT
SUM(CASE WHEN TO_CHAR (start_date, 'FMDay') = 'Sunday' THEN
ROUND ( (completion_date - start_date) * 24, 1) END) AS "Sunday",
SUM(CASE WHEN TO_CHAR (start_date, 'FMDay') = 'Monday' THEN
ROUND ( (completion_date - start_date) * 24, 1) END) AS "Monday",
SUM(CASE WHEN TO_CHAR (start_date, 'FMDay') = 'Tuesday' THEN
ROUND ( (completion_date - start_date) * 24, 1) END) AS "Tuesday",
SUM(CASE WHEN TO_CHAR (start_date, 'FMDay') = 'Wednesday' THEN
ROUND ( (completion_date - start_date) * 24, 1) END) AS "Wednesday",
SUM(CASE WHEN TO_CHAR (start_date, 'FMDay') = 'Thursday' THEN
ROUND ( (completion_date - start_date) * 24, 1) END) AS "Thursday",
SUM(CASE WHEN TO_CHAR (start_date, 'FMDay') = 'Friday' THEN
ROUND ( (completion_date - start_date) * 24, 1) END) AS "Friday",
SUM(CASE WHEN TO_CHAR (start_date, 'FMDay') = 'Saturday' THEN
ROUND ( (completion_date - start_date) * 24, 1) END) AS "Saturday"
FROM emp_dates;
Sunday Monday Tuesday Wednesday Thursday Friday Saturday
---------- ---------- ---------- ---------- ---------- ---------- ----------
3.1 4.9
The 'FM' format modifier stops the value produced by to_char()
being padded by spaces, which is what happens by default with 'Day' and 'Dy'; without that the text literals would also need to be padded, e.g. 'Monday '
.
You could use a subquery to simplify the code a little:
SELECT
SUM(CASE WHEN dy = 'Sun' THEN hours END) AS "Sunday",
SUM(CASE WHEN dy = 'Mon' THEN hours END) AS "Monday",
SUM(CASE WHEN dy = 'Tue' THEN hours END) AS "Tuesday",
SUM(CASE WHEN dy = 'Wed' THEN hours END) AS "Wednesday",
SUM(CASE WHEN dy = 'Thu' THEN hours END) AS "Thursday",
SUM(CASE WHEN dy = 'Fri' THEN hours END) AS "Friday",
SUM(CASE WHEN dy = 'Sat' THEN hours END) AS "Saturday"
FROM (
SELECT TO_CHAR (start_date, 'FMDy', 'NLS_DATE_LANGUAGE=English') AS dy,
ROUND ( (completion_date - start_date) * 24, 1) AS hours
FROM emp_dates
);
Sunday Monday Tuesday Wednesday Thursday Friday Saturday
---------- ---------- ---------- ---------- ---------- ---------- ----------
3.1 4.9
I've also changed that use the abbreviated day name just because it's shorter, and specified the language to use for that - in case the client session running this isn't in English, which would make the comparison with the string literals fail. (You can read more about that in the documentation).
In the first version, for example, if the session language was French, the to_char()
would get 'Lundi', which would not match the fixed value 'Monday'. You could also use the day number for the comparison but that is also affected by NLS settings, and can't be changed the way the language can.
Upvotes: 2