Pivot without aggregate function - sql

I am trying to turn some parts of my rows into columns. To my knowledge, I am only able to use a pivot with an aggregate function,but I would just be pivoting text. For each client I have up to 4 rows grouped by a DLSEQUENCE field. Instead of having the 4 rows, I would like everything to be on 1 row.
SELECT CASE
WHEN Sched_time BETWEEN TRUNC(SCHED_TIME) + INTERVAL '8' HOUR + INTERVAL '30' MINUTE
AND TRUNC(SCHED_TIME) + INTERVAL '14' HOUR + INTERVAL '45' MINUTE AND
TO_CHAR(SCHED_TIME, 'DY') IN ('MON', 'TUE', 'WED', 'THU', 'FRI')
THEN 'ABC'
ELSE 'DEF'
END AS Organization,
Client_Last_Name,
Client_First_Name,
Sched_Time,
Field_Name,
CASE
WHEN Recoded_Response = '1' THEN 'Yes'
WHEN Recoded_Response = '2' THEN 'No'
ELSE Recoded_Response
END AS Responses,
Dlsequence
FROM DAILY_LOG_CUSTOM_DATA
WHERE SERVICE_NAME = 'Medical'
AND FIELD_CATEGORY = 'Background Information'
AND Field_Name IN
(
'Restraint?',
'History',
'Findings',
'Treatment'
)
AND Sched_Time >= TO_DATE('2020-03-01 01:00:00', 'YYYY/MM/DD HH:MI:SS')
AND Sched_Time < TO_DATE('2020-03-31 12:59:00', 'YYYY/MM/DD HH:MI:SS')
Order BY Dlsequence
Here is my table:
I would like the response fields that go with ('Restraint?','History','Findings','Treatment') to have their own column for each DLSEQUENCE field.

The following should do what you had in mind:
SELECT DLSEQUENCE,
ORGANIZATION,
CLIENT_LAST_NAME,
CLIENT_FIRST_NAME,
SCHED_TIME,
LISTAGG("Restraint?", ',') WITHIN GROUP (ORDER BY DLSEQUENCE) AS "Restraint?",
LISTAGG("Findings", ',') WITHIN GROUP (ORDER BY DLSEQUENCE) AS "Findings",
LISTAGG("History", ',') WITHIN GROUP (ORDER BY DLSEQUENCE) AS "History",
LISTAGG("Treatment", ',') WITHIN GROUP (ORDER BY DLSEQUENCE) AS "Treatment"
FROM (SELECT DLSEQUENCE,
ORGANIZATION,
CLIENT_LAST_NAME,
CLIENT_FIRST_NAME,
SCHED_TIME,
CASE
WHEN FIELD_NAME = 'Restraint?' THEN RESPONSES
ELSE NULL
END AS "Restraint?",
CASE
WHEN FIELD_NAME = 'Findings' THEN RESPONSES
ELSE NULL
END AS "Findings",
CASE
WHEN FIELD_NAME = 'History' THEN RESPONSES
ELSE NULL
END AS "History",
CASE
WHEN FIELD_NAME = 'Treatment' THEN RESPONSES
ELSE NULL
END AS "Treatment"
FROM YOUR_TABLE)
GROUP BY DLSEQUENCE,
ORGANIZATION,
CLIENT_LAST_NAME,
CLIENT_FIRST_NAME,
SCHED_TIME
db<>fiddle here

Related

Case Expression and dates

I have the below case expression.
SELECT end_dt,
CASE WHEN TO_CHAR(A.END_DT,'MM/DD/YYYY') = '01/01/3000' THEN ''
WHEN TO_CHAR(A.END_DT,'MM/DD/YYYY') > TO_CHAR(SYSDATE,'MM/DD/YYYY') THEN TO_CHAR(SYSDATE,'MM/DD/YYYY')
ELSE TO_CHAR(A.END_DT,'MM/DD/YYYY')
END ENDDATE,
CASE WHEN TO_CHAR(A.END_DT,'YYYYMM') = '300001' THEN ''
WHEN TO_CHAR(A.END_DT,'YYYYMM') > TO_CHAR(SYSDATE,'YYYYMM') THEN TO_CHAR(SYSDATE,'YYYYMM')
ELSE TO_CHAR(A.END_DT,'YYYYMM')
END ENDDATE_YYYYMM,
CASE WHEN TO_CHAR(A.END_DT,'YYYY') = '3000' THEN ''
WHEN TO_CHAR(A.END_DT,'YYYY') > TO_CHAR(SYSDATE,'YYYY') THEN TO_CHAR(SYSDATE,'YYYY')
WHEN TO_CHAR(A.END_DT,'YYYY') > TO_CHAR(SYSDATE,'YYYY') THEN TO_CHAR(SYSDATE,'YYYY')
ELSE TO_CHAR(A.END_DT,'YYYY')
END ENDDATE_YYYY
FROM A
LEFT D ON A.ID = D.ID
WHERE 1=1
ORDER BY 1
OutPut:
End_dt ENDDATE ENDDATE_YYYYMM ENDDATE_YYYY
12/5/2012 14:33:24 01/05/2018 201212 2012
Expected output:
End_dt ENDDATE ENDDATE_YYYYMM ENDDATE_YYYY
12/5/2012 14:33:24 12/5/2012 201212 2012
Why do I get a result of 01/05/2018 and not 12/5/2012?
You're doing string comparisons on dates. Stop. Do date comparisons on dates.
The string '12/5/2012' is greater than the string '01/05/2018' because 1 is greater than 0. Oracle is performing a binary comparison.
SQL> select *
2 from dual
3 where '12/5/2012' > '01/05/2018';
D
-
X
Stop converting all your dates to strings and all will be well
SQL> select *
2 from dual
3 where date '2018-05-01' > date '2012-05-12';
D
-
X
Incidentally, the empty string '' is equivalent to NULL in Oracle.
Your query should look like:
CASE WHEN A.END_DT = date '3000-01-01' then null
WHEN A.END_DT > SYSDATE THEN TO_CHAR(SYSDATE,'MM/DD/YYYY')
ELSE TO_CHAR(A.END_DT,'MM/DD/YYYY')
END ENDDATE,
Don't do date comparisons as strings. It works for the other values, because you have the right format -- YYYYMMDD (or a partial piece of that).
Try this logic:
SELECT end_dt,
(CASE WHEN TO_CHAR(A.END_DT, 'MM/DD/YYYY') = '01/01/3000' THEN ''
WHEN A.END_DT > SYSDATE
THEN TO_CHAR(SYSDATE, 'MM/DD/YYYY')
ELSE TO_CHAR(A.END_DT, 'MM/DD/YYYY')
END) as ENDDATE,
(CASE WHEN TO_CHAR(A.END_DT, 'YYYYMM') = '300001' THEN ''
WHEN TO_CHAR(A.END_DT, 'YYYYMM') > TO_CHAR(SYSDATE, 'YYYYMM')
THEN TO_CHAR(SYSDATE,'YYYYMM')
ELSE TO_CHAR(A.END_DT,'YYYYMM')
END) as ENDDATE_YYYYMM,
(CASE WHEN TO_CHAR(A.END_DT, 'YYYY') = '3000' THEN ''
WHEN TO_CHAR(A.END_DT, 'YYYY') > TO_CHAR(SYSDATE, 'YYYY')
THEN TO_CHAR(SYSDATE, 'YYYY')
WHEN TO_CHAR(A.END_DT, 'YYYY') > TO_CHAR(SYSDATE,'YYYY')
THEN TO_CHAR(SYSDATE, 'YYYY')
ELSE TO_CHAR(A.END_DT, 'YYYY')
END) as ENDDATE_YYYY

Hive end of the last month

INSERT OVERWRITE TABLE test_month
PARTITION (dt= LAST_DAY('${CURRENT_DATE}'))
SELECT '${CURRENT_DATE}', LAST_DAY('${CURRENT_DATE}');
Current date is first day of the month. I want to achieve something like above. It is not working. This will be HiveQL used in oozie.
Their may be couple ways, here is one way
select order_date, date_sub(concat(
(case
WHEN MONTH(order_date) = '12' THEN concat( (YEAR(order_date) +1) , '-01')
WHEN MONTH(order_date) >= '10' THEN concat( (YEAR(order_date)) , '-', (MONTH(order_date) +1))
WHEN MONTH(order_date) >= '1' THEN concat( (YEAR(order_date)) , '-0', (MONTH(order_date) +1))
ELSE 'XX' END) ,'-01' ) ,1)

ora-02287 Sequence number not allowed

I am trying to run the following query to fill a table with the proper values. I have ran the select statement alone, without the price_s and the created_by, creation_date, last_updated_by, and last_update_date, and it pulls everything that I need. When I add those values, it gives errors, I have gotten through some of them, but I am stuck on this one ORA-02287: Sequence number not allowed here, I have looked everywhere and cannot find what I am doing wrong. It is probably some simple answer, but I just cannot see it right now.
Here is the code:
CREATE SEQUENCE price_s START WITH 1001;
INSERT INTO price (price_id, item_id, price_type, active_flag, start_date, end_date, amount, created_by, creation_date, last_updated_by, last_update_date)
SELECT price_s.nextval, i.item_id,
active_flag,
cl.common_lookup_id,TRUNC (i.release_date),
CASE
WHEN (TRUNC (SYSDATE) - TRUNC (i.release_date)) < 31 AND active_flag = 'N' THEN NULL
WHEN (TRUNC (SYSDATE) - TRUNC (i.release_date)) > 30 AND active_flag = 'N' THEN TRUNC (i.release_date) + 30
END AS END_DATE,
CASE
WHEN (TRUNC (SYSDATE) - TRUNC (i.release_date)) < 31 AND active_flag = 'Y' THEN
CASE
WHEN rental_days = 1 THEN '3'
WHEN rental_days = 3 THEN '10'
WHEN rental_days = 5 THEN '15'
END
WHEN (TRUNC (SYSDATE) - TRUNC (i.release_date)) > 30 AND active_flag = 'N' THEN
CASE
WHEN rental_days = 1 THEN '3'
WHEN rental_days = 3 THEN '10'
WHEN rental_days = 5 THEN '15'
END
WHEN (TRUNC (SYSDATE) - TRUNC (i.release_date)) > 30 AND active_flag = 'Y' THEN
CASE
WHEN rental_days = 1 THEN '1'
WHEN rental_days = 3 THEN '3'
WHEN rental_days = 5 THEN '5'
END
END AS AMOUNT,
1,SYSDATE,1,SYSDATE
FROM item i CROSS JOIN
(SELECT 'Y' AS active_flag FROM dual
UNION ALL
SELECT 'N' AS active_flag FROM dual) af CROSS JOIN
(SELECT '1' AS rental_days FROM dual
UNION ALL
SELECT '3' AS rental_days FROM dual
UNION ALL
SELECT '5' AS rental_days FROM dual) dr INNER JOIN
common_lookup cl ON dr.rental_days = SUBSTR(cl.common_lookup_type,1,1)
WHERE NOT ((TRUNC (SYSDATE) - TRUNC (i.release_date)) <= 31 AND active_flag = 'N')
AND NOT cl.common_lookup_table = 'RENTAL_ITEM'
ORDER BY 1, 2, 3;
Any ideas on what I am doing wrong?
Well I figured out what was wrong with my statement. I knew it was simple I just could not see it at the time. I forgot to take out the
ORDER BY 1, 2, 3; it was messing everything up, sorry to take up anyone's time.

Oracle SQL Count Records per Hour

So, what I'm trying to do basically is count the amount of shipments, per hour, per carrier, but I'm having difficulties getting it to sum in the columns I want. The goal is to instead of having 1 or 2 under Hour 1 or Hour 2 it would have sum(total shipments). Essentially 24 hours so we could see trends in time of day...
Code:
select router_destination_code,
case when to_char(app_last_updated_date_utc, 'HH24') = '00' then '1' else NULL end as "Hour 1",
case when to_char(app_last_updated_date_utc, 'HH24') = '01' then '2' else NULL end as "Hour 2",
case when to_char(app_last_updated_date_utc, 'HH24') = '02' then '3' else NULL end as "Hour 3",
--case when app_last_updated_date_utc between 'dec/07/2013 16:00:00' and 'dec/14/2013 17:00:00' then count(Router_Destination_code) else NULL end as "Hour_1"
count(Router_Destination_code) as Shipments
from booker.routing_container_history
where
app_last_updated_by_module in ('ManualSlam', 'slam')
and app_last_updated_date_utc between 'dec/07/2013 16:00:00' and 'dec/14/2013 16:00:00'
group by
router_destination_code,
case when to_char(app_last_updated_date_utc, 'HH24') = '00' then '1' else NULL end,
case when to_char(app_last_updated_date_utc, 'HH24') = '01' then '2' else NULL end,
case when to_char(app_last_updated_date_utc, 'HH24') = '02' then '3' else NULL end
order by
case when to_char(app_last_updated_date_utc, 'HH24') = '00' then '1' else NULL end,
case when to_char(app_last_updated_date_utc, 'HH24') = '01' then '2' else NULL end,
case when to_char(app_last_updated_date_utc, 'HH24') = '02' then '3' else NULL end,
count(Router_Destination_code) desc;
Output:
But, the Goal is to have the shipments underneath the hour.
Thank you.
Here is a new approach I did.. But it is showing lots of zeros, and would like it only to show numbers the whole way across.
select router_destination_code,
count(case when to_char(app_last_updated_date_utc, 'HH24') = '16' then router_destination_code else NULL end) as "Hour 1",
count(case when to_char(app_last_updated_date_utc, 'HH24') = '17' then router_destination_code else NULL end) as "Hour 2"
--case when app_last_updated_date_utc between 'dec/07/2013 16:00:00' and 'dec/14/2013 17:00:00' then count(Router_Destination_code) else NULL end as "Hour_1"
--count(Router_Destination_code) as Shipments
from booker.routing_container_history
where
app_last_updated_by_module in ('ManualSlam', 'slam')
and app_last_updated_date_utc between 'dec/07/2013 16:00:00' and 'dec/14/2013 16:00:00'
group by
router_destination_code,
case when to_char(app_last_updated_date_utc, 'HH24') = '16' then router_destination_code else NULL end,
case when to_char(app_last_updated_date_utc, 'HH24') = '17' then router_destination_code else NULL end
order by
case when to_char(app_last_updated_date_utc, 'HH24') = '16' then router_destination_code else NULL end,
case when to_char(app_last_updated_date_utc, 'HH24') = '17' then router_destination_code else NULL end,
count(Router_Destination_code) desc;
I do not know if I understood you well but you may try to just extract hour from date and then group by:
Check this fiddle (sorry for bad syntax):
http://sqlfiddle.com/#!4/a0a97/6
create table a (id number, data date);
insert into a (id, data)
values (1, to_date( '2013-01-01 13:12:01', 'yyyy-mm-dd hh24:mi:ss'));
insert into a (id, data)
values (1, to_date( '2013-01-01 13:12:01', 'yyyy-mm-dd hh24:mi:ss'));
insert into a (id, data)
values (1, to_date( '2013-01-01 14:12:01', 'yyyy-mm-dd hh24:mi:ss'));
select to_char(data,'HH24'), count(1) from a group by to_char(data,'HH24');

ORDER BY Alias not working

UPDATING QUESTION:
ERROR: column "Fruits" does not exist
Running Postgres 7.4(Yeah we are upgrading)
Why can't I ORDER BY the column alias? wants tof."TypeOfFruits" in the ORDER BY as well, why?
SELECT (CASE
WHEN tof."TypeOfFruits" = 'A' THEN 'Apple'
WHEN tof."TypeOfFruits" = 'P' THEN 'Pear'
WHEN tof."TypeOfFruits" = 'G' THEN 'Grapes'
ELSE 'Other' END) AS "Fruits",
SUM(CASE WHEN r.order_date
BETWEEN DATE_TRUNC('DAY', LOCALTIMESTAMP) AND DATE_TRUNC('DAY', LOCALTIMESTAMP) + INTERVAL '1 DAY'
THEN 1 ELSE 0 END) AS daily,
SUM(CASE WHEN r.order_date
BETWEEN DATE_TRUNC('MONTH', LOCALTIMESTAMP) AND DATE_TRUNC('MONTH', LOCALTIMESTAMP) + INTERVAL '1 MONTH'
THEN 1 ELSE 0 END) AS monthly,
SUM(CASE WHEN r.order_date
BETWEEN DATE_TRUNC('YEAR', LOCALTIMESTAMP) AND DATE_TRUNC('YEAR', LOCALTIMESTAMP) + INTERVAL '1 YEAR'
THEN 1 ELSE 0 END) AS yearly,
SUM(CASE WHEN r.order_date >= '01-01-2011 00:00:00' THEN 1 ELSE 0 END) AS lifetime
FROM reports AS r, "TypeOfFruits" AS tof
WHERE r.id = tof."ID"
GROUP BY "Fruits"
ORDER BY CASE
WHEN "Fruits" = 'Apple' THEN 1
WHEN "Fruits" = 'Pear' THEN 2
WHEN "Fruits" = 'Grapes' THEN 3
ELSE 4
END
Results as of now
Fruits;daily;monthly;yearly;lifetime
"Apple";17;1174;3136;3136
"Pear";28;94;94;94
"Grapes";0;191;490;490
"Other";0;2;27;27
"Other";0;0;1;1
"Other";0;0;27;27
"Other";0;6;28;28
"Other";0;58;229;229
"Other";0;3;3;3
"Other";0;0;1;1
Desired results would be one row with the "Other" total, so four rows altogether
(x would be the total)
Fruits;daily;monthly;yearly;lifetime
"Apple";17;1174;3136;3136
"Pear";28;94;94;94
"Grapes";0;191;490;490
"Other";x;x;x;x
You can use ORDER BY 1 to order by the first field, which is "Fruits". The same is valid for GROUP BY
Update
For the order, instead of doing the case in the order by, create a new column in.. say.. the second position:
(CASE
WHEN "Fruits" = 'Apple' THEN 1
WHEN "Fruits" = 'Pear' THEN 2
WHEN "Fruits" = 'Grapes' THEN 3
ELSE 4 ) as Order
Then in you ORDER BY 2.
The reason for this can be found in the documentation:
Each expression [in the ORDER BY list] can be the name or ordinal number of an output column (SELECT list item), or it can be an arbitrary expression formed from input-column values.
(my emphasis)
The reason for this is that old versions of the SQL standard (SQL-92) only allowed sorting by output column name or number, whereas newer versions allow sorting by arbitrary expressions, but those expressions are formed from input column values.
Other answers already contain various suitable workarounds for your case.
The alias is assigned after the order by so you can't use it in the order by. Use this instead:
(CASE
WHEN tof."TypeOfFruits" = 'A' THEN 'Apple'
WHEN tof."TypeOfFruits" = 'P' THEN 'Pear'
WHEN tof."TypeOfFruits" = 'G' THEN 'Grapes'
ELSE 'Other' END)
Consider something like this:
SELECT * FROM (SELECT (CASE
WHEN tof."TypeOfFruits" = 'A' THEN 'Apple'
WHEN tof."TypeOfFruits" = 'P' THEN 'Pear'
WHEN tof."TypeOfFruits" = 'G' THEN 'Grapes'
ELSE 'Other' END) AS "Fruits",
(CASE
WHEN tof."TypeOfFruits" = 'A' THEN 1
WHEN tof."TypeOfFruits" = 'P' THEN 2
WHEN tof."TypeOfFruits" = 'G' THEN 3
ELSE 4 END) as NUM
FROM ..... <rest of your query without group by and order by .....
)
GROUP BY Fruits
ORDER BY NUM
You could try something like this ... untested, but I've seen similar queries.
Let me know if it works...
SELECT "Fruits",
SUM(CASE WHEN r.order_date
BETWEEN DATE_TRUNC('DAY', LOCALTIMESTAMP) AND DATE_TRUNC('DAY', LOCALTIMESTAMP) + INTERVAL '1 DAY'
THEN 1 ELSE 0 END) AS daily,
SUM(CASE WHEN r.order_date
BETWEEN DATE_TRUNC('MONTH', LOCALTIMESTAMP) AND DATE_TRUNC('MONTH', LOCALTIMESTAMP) + INTERVAL '1 MONTH'
THEN 1 ELSE 0 END) AS monthly,
SUM(CASE WHEN r.order_date
BETWEEN DATE_TRUNC('YEAR', LOCALTIMESTAMP) AND DATE_TRUNC('YEAR', LOCALTIMESTAMP) + INTERVAL '1 YEAR'
THEN 1 ELSE 0 END) AS yearly,
SUM(CASE WHEN r.order_date >= '01-01-2011 00:00:00' THEN 1 ELSE 0 END) AS lifetime
FROM reports AS r
,(SELECT "ID",
CASE
WHEN tof."TypeOfFruits" = 'A' THEN 'Apple'
WHEN tof."TypeOfFruits" = 'P' THEN 'Pear'
WHEN tof."TypeOfFruits" = 'G' THEN 'Grapes'
ELSE 'Other'
END AS "Fruits" FROM "TypeOfFruits" ) AS "tof"
WHERE r.id = tof."ID"
GROUP BY "Fruits"
ORDER BY CASE
WHEN "Fruits" = 'Apple' THEN 1
WHEN "Fruits" = 'Pear' THEN 2
WHEN "Fruits" = 'Grapes' THEN 3
ELSE 4
END
Try using backticks (`) instead of single/double quotes to wrap your alias name.
Had the same issue with MySQL; backticks fixed the problem.