PostgresSql max dates last 30 dates - max

In my dataset I have a list dates
How do I tag the latest 30 dates as "max"?
Col A: Dates
Col B: Values
Col C: Tag as "Max" or "NA"

I am making the assumptions that you don't know how recent to the current date the set will be or if it contains sparse dates. I don't have a running Postgres instance at the moment but this should be extremely close.
SELECT
t.ColA
, t.ColB
, CASE WHEN t2.ColA IS NOT NULL THEN 'Max' ELSE 'NA' END AS ColC
FROM TableName t
LEFT OUTER JOIN (SELECT DISTINCT inner_t.ColA
FROM TableName inner_t
ORDER BY 1 DESC
LIMIT 30) t2
ON t.ColA = t2.ColA

Related

How to use select statement insert first row of dummy dash value with 2 table combination

table_A
no desciption
1 Apple
2 orange
3 banana
4 kiwi
5 papaya
table_B
no price mydate
1 10.00 20210801
2 8.00 20210802
3 5.00 20210803
4 12.00 20210804
5 4.00 20210805
Hi, I try to use this SQL and union all but show an error.
select '-' a.description, '-' b.price from dual union all select a.description,sum(b.price) from table_A a, table_B b where a.no=b.no and b.mydate='20210801' group by a.description;
ORA-00923 : FROM keyword not found where expected
I need result
a.description sum(b.price)
- - <-----dummy dash always on first row
Apple 10.00
Anyone help is much appreciated.
There is no aliases a and b in your first part of union all, so just remove a. and b.
Don't use implicit conversion from char literals to date, use literal dates instead:
select '-' as description, '-' as price from dual
union all
select a.description,to_char(sum(b.price))
from
table_A a
join table_B b
on a.no=b.no
where b.mydate=date'2021-08-01'
group by a.description;
One option is to
use a subquery
it contains additional rn column (where 1 means that those values will represent "row number 1" in the result)
apply to_char function to sum(b.price) because - with union - queries have to match in number of columns and their datatypes
So:
SELECT description, price
FROM (SELECT 1 rn, '-' description, '-' price FROM DUAL
UNION ALL
SELECT 2 rn, a.description, TO_CHAR (SUM (b.price))
FROM table_A a, table_B b
WHERE a.no = b.no
AND b.mydate = '20210801'
GROUP BY a.description)
ORDER BY rn
which - applied to your sample data - returns
DESCRIPTION PRICE
--------------- ----------------------------------------
- -
apple 10
Note that:
mydate should be a true date datatype column; don't use strings because nothing prevents you from entering e.g. 2f$8-23 into a varchar2 column, and that certainly isn't a valid date value
try to switch to joins; leave where clause for conditions data should meet in order to be returned
Something like this:
from table_a a join table_b b on a.no = b.no --> JOIN
where b.mydate = date '2021-08-01' --> MYDATE being DATE datatype

I want to get the last available value in a previous row in MySQL8 in a calculated column

I have a table in mysql database this data.
id date close previous_close
1 07-10-2020 200 300
2 06-10-2020 300 1000
3 05-10-2020 0 1000
4 04-10-2020 1000 15
I've had a look at using the lag() function but can't get my head round it. How can I craft a query such that the calculated column previous_close obtains the most recently available value in the close column where it's not zero?
Here is one way:
WITH cte AS (
SELECT *,
MAX(CASE WHEN close > 0 THEN date END) OVER
(ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) AS last_date
FROM yourTable
)
SELECT
t1.id,
t1.date,
t1.close,
t2.close AS previous_close
FROM cte t1
LEFT JOIN yourTable t2
ON t2.date = t1.last_date
ORDER BY t1.date DESC;
The strategy here is that the CTE finds the latest date corresponding to a non zero close occurring strictly before each given row, as sorted by date. Then, all we have to do is to join this CTE back to your original table to find the actual matching latest previous close value.

How to select data from multiple row into one row with multiple column dynamically?

I am trying to select multiple rows of data into one row through multiple columns which will change dynamically.
This is in Oracle database. I want to count repeated work done by the LEAD_TECHNISIAN_ID within a duration. If the difference of last work delivery date and new work receive date is 15 or below 15 then LEAD_TECHNISIAN_ID has one repeated work.
List item
SELECT *
FROM (WITH CTE AS (
SELECT ROW_NUMBER () OVER (ORDER BY ID) AS RW,
RECEIVED_DATE,
DELIVERY_DATE,
SERVICE_NO,
LEAD_TECHNISIAN_ID,
ID,
SERVICE_CENTER
FROM ( SELECT cc.SERVICE_CENTER,
CC.ID,
CC.BARCODE,
TRUNC (cc.CREATED_DATE) RECEIVED_DATE,
TRUNC (CC.DELIVERY_DATE) DELIVERY_DATE,
cc.SERVICE_NO,
CC.LEAD_TECHNISIAN_ID
FROM customer_complains cc
WHERE cc.BARCODE IN (SELECT BARCODE
FROM (SELECT BARCODE,
COUNT (BARCODE)
FROM customer_complains c
WHERE c.BARCODE <> 'UNDEFINE'
AND C.BARCODE = NVL ('351950102757821', BARCODE)
AND c.SEGMENT3 = NVL ('',c.SEGMENT3)
AND c.SEGMENT3 IN (SELECT SEGMENT3
FROM ITEM_MST
WHERE PRODUCT_GROUP = NVL ('',PRODUCT_GROUP))
GROUP BY c.BARCODE
HAVING COUNT (c.BARCODE) >1))
ORDER BY ID DESC)
ORDER BY ID DESC)
SELECT a.id,
a.DELIVERY_DATE,
a.RECEIVED_DATE,
b.RECEIVED_DATE PRE_RCV,
b.DELIVERY_DATE PRE_DEL,
(a.RECEIVED_DATE - b.DELIVERY_DATE) AS DIFF,
a.SERVICE_NO,
a.LEAD_TECHNISIAN_ID,
b.LEAD_TECHNISIAN_ID PRE_TECH --, a.DELIVERY_DATE
FROM CTE a
LEFT JOIN CTE b ON a.RW = b.RW + 1
)
WHERE DIFF <= 15
Here is the output for a specific barcode. but when I try for All the barcode I have in My Customer_complains table. The query provides irrelevant output.
Currently your code is giving numbers 1,2,3,4... to rows irrespective of LEAD_TECHNISIAN_ID and then you are joining it with RW. It will not consider LEAD_TECHNISIAN_ID while giving row numbers.
RW must start with 1 for each LEAD_TECHNISIAN_ID.
You just need to change calculation of RW as following:
ROW_NUMBER () OVER (PARTITION BY LEAD_TECHNISIAN_ID ORDER BY ID) AS RW
Cheers!!

Datepart function in oracle

I have some sample records in Oracle 12
Date_Time Item
10/1/2012 12:05:00 AM 3
12/3/2012 06:00:00 AM 2
11/8/2012 14:05:05 PM 10
12/9/2012 16:00:59 PM 5
I like to aggregate the Item field based on military time or in three different times: 00:00:00AM to 05:59:00AM, 06:00:00AM to 15:59:00PM, and 16:00:00PM to 23:59:00PM. I was able to use the Datepart function in SQL to do this. I was wondering what function in Oracle 12 that allows me to count the Item between these three different times.
My desired output would be:
Date_Time Count
00:00:00AM to 05:59:00AM = 3
06:00:00AM to 15:59:00PM = 12
16:00:00PM to 23:59:00PM = 5
In oracle, date datatype contains date+time ,so you just need just use group by
SELECT Date_Time, COUNT(*) item FROM YOUR_TABLES
GROUP BY Date_Time;
NEW Answer:
SELECT TO_CHAR(DATE_TIME,'HH24') time, count(*) FROM YOUR_TABLE
WHERE TO_CHAR(DATE_TIME,'HH24') >= '00'
AND TO_CHAR(DATE_TIME,'HH24') < '06'
GROUP BY TO_CHAR(DATE_TIME,'HH24')
UNION ALL
SELECT TO_CHAR(DATE_TIME,'HH24') time, count(*) FROM YOUR_TABLE
WHERE TO_CHAR(DATE_TIME,'HH24') >= '06'
AND TO_CHAR(DATE_TIME,'HH24') < '16'
GROUP BY TO_CHAR(DATE_TIME,'HH24')
UNION ALL
SELECT TO_CHAR(DATE_TIME,'HH24') time, count(*) FROM YOUR_TABLE
WHERE TO_CHAR(DATE_TIME,'HH24') >= '16'
AND TO_CHAR(DATE_TIME,'HH24') < '00'
GROUP BY TO_CHAR(DATE_TIME,'HH24');
and if your table is huge :
first :partition it
second: create local functional index on TO_CHAR(DATE_TIME,'HH24:MI:SS')
Assuming that date_time column is datatype DATE, we can use the TO_CHAR function to extract a two character representation... in the range 00 to 23.
(The selected answer demonstrates this approach to extracting the "hour" from an Oracle DATE.)
Assuming that we want every non-null time value to fall into one of three time ranges... that is, if we don't want any of time values to be omitted because of a crack/gap in between the ranges, and we don't want any overlap in the ranges...
We can use a simple "less than" tests in a CASE expression.
Consider a time close to a boundary: '05:59:33'. That's after 05:59:00 but before 06:00:00. If we want that included in the first range, we can just test for hour < '06'.
If was grouping the rows into three ranges, and I wanted a total of the item column, I'd do something like this:
SELECT CASE
WHEN TO_CHAR( t.date_time ,'HH24') < '06' THEN '00:00:00 to 05:59:59'
WHEN TO_CHAR( t.date_time ,'HH24') < '16' THEN '06:00:00 to 15:59:59'
WHEN TO_CHAR( t.date_time ,'HH24') < '24' THEN '16:00:00 to 23:59:59'
END AS time_range
, SUM(t.item)
FROM mytable t
GROUP
BY CASE
WHEN TO_CHAR( t.date_time ,'HH24') < '06' THEN '00:00:00 to 05:59:59'
WHEN TO_CHAR( t.date_time ,'HH24') < '16' THEN '06:00:00 to 15:59:59'
WHEN TO_CHAR( t.date_time ,'HH24') < '24' THEN '16:00:00 to 23:59:59'
END
and add an ORDER BY clause if I want the results returned in a particular order.
If the table contains any NULL values of date_time, the query above will also return a fourth time_range with a NULL value.
Here is how you would get the desired result in three columns (rather than three rows), which makes more sense for most applications. You can change this easily to get the result in rows instead.
Note that if dt is any date in Oracle, dt - trunc(dt) is the number of days (a fraction with value less than 1) since midnight.
select sum(case when dt-trunc(dt) < 6/24 then item else 0 end) as morning,
sum(case when dt-trunc(dt) >= 6/24
and dt-trunc(dt) < 16/24 then item else 0 end) as daytime,
sum(case when dt-trunc(dt) >= 16/24 then item else 0 end) as evening
from your_table
;

Alternate for decode function

I have a table 'Holiday' which lists a set of holiday details.If i specify a date,I should obtain a result date after 5 days of specified date.If there is holiday in between it should exclude them and display the non holiday date.I have table named holiday which includes holiday date,holiday type|(weekly off,local holiday).Now i have used nested decode for continuous holiday checking.Tell me how this can be changed in case function.
DECODE
(date,
holidaydate, DECODE
(date + 1,
holidaydate + 1, DECODE
(date + 2,
holidaydate + 2, DECODE
(date + 3,holidaydate+3,date+4,date+3),date+2),date+1),date);
This can be achieved with a simple subquery which counts the number of holiday dates between a specified date and date+5. The following will return a date that is five non-holiday days in the future:
testdate+(select 5+count(1)
from holiday
where holidaydate between testdate
and testdate + 5)
Simply change both "5"s so another number to change the evaluation period.
SQLFiddle here
Edit - based on comment below, my code doesn't evaluate any days after the fifth day. This would probably be much easier with a function, but the following cte-based code will work also:
with cte as ( (select alldate,holidaydate
from (select to_date('20130101','yyyymmdd')+level alldate
from dual
connect by level < 10000 -- adjust for period to evaluate
) alldates
left join holiday on alldate=holidaydate) )
select
testdate,test_plus_five
from (
select
alldate test_plus_five,testdate,
sum(case when holidaydate is null
then 1
else 0 end) over (partition by testdate order by alldate) lastday
from
cte,
testdates
where
alldate >= testdate
group by
alldate,holidaydate,testdate)
where
lastday = 6
This script builds a calendar table so it can evaluate each day (holiday or non-holiday); then we get a running count of non-holiday days, and use the sixth one.
SQLFiddle here
AFAIK, You can use CASE alternative to DECODE in Oracle
CASE [ expression ]
WHEN condition_1 THEN result_1
WHEN condition_2 THEN result_2
...
WHEN condition_n THEN result_n
ELSE result
END
Finally i found the optimal solution.Thanks for ur response guys. SELECT dt FROM
(SELECT dt FROM (SELECT TO_DATE('15-AUG-2013','dd-mon-yyyy')+LEVEL dt FROM DUAL
CONNECT BY LEVEL < 30)
WHERE
(SELECT COUNT (*) FROM mst_holiday WHERE holidaydate = dt) = 0 )
where rownum=1

Resources