How to query between hours and minute in Oracle? - sql

I have the following query:
...
CASE WHEN TO_NUMBER(TO_CHAR(SYSDATE,'hh24')) BETWEEN 2 AND 4 THEN 0 else count(*) end....
But I'd like to change until 4:30AM only (04:31 not apply anymore). How can I do it? I now I can get with to_char(...,'hh24:mi') but it will be a char value.
Also, I have tried:
select TO_DATE(TO_CHAR(SYSDATE,'hh24:mi'),'HH24:MI') from dual;
but the date goes wrong.
I want something like it:
CASE WHEN TO_DATE(SYSDATE,'hh24:mi') BETWEEN TO_DATE('02:00','HH24:MI') AND TO_DATE('04:30','HH24:MI')

Actually you can still do a range comparison using text hh:mm strings:
CASE WHEN TO_CHAR(SYSDATE, 'hh24') >= '02:00' AND
TO_CHAR(SYSDATE, 'hh24') <= '04:30'
THEN 0 ELSE COUNT(*) END

One option is to use INTERVAL DAY TO SECOND data types:
CASE
WHEN (SYSDATE - TRUNC(SYSDATE)) DAY TO SECOND
BETWEEN INTERVAL '02:00:00' HOUR TO SECOND
AND INTERVAL '04:30:00' HOUR TO SECOND
THEN 0
ELSE count(*)
END
Or, you can do the same with arithmetic:
CASE
WHEN (SYSDATE - TRUNC(SYSDATE)) BETWEEN 2/24 AND 4.5/24
THEN 0
ELSE count(*)
END

Related

Obtain data from Friday, Saturday and Sunday if today is Monday SQL Oracle

I am looking to obtain all data in a table from yesterday in SQL Oracle.
This is simply enough using the WHERE clause, i.e,
SELECT *
FROM My_Data
WHERE TO_DATE(My_Data.Date,'YYYY-MM-DD') = TRUNC(SYSDATE)-1
However if I now need to add more logic where if the day of the query is a Monday (SYSDATE) then obtain data between Friday and Sunday.
Using a between statement is no issue, I'm just not sure if I can include in a where statement given I'm unable to use case statement here.
Thanks
SELECT
*
FROM
My_Data
WHERE
TO_DATE(My_Data.Date,'YYYY-MM-DD')
Between Case When To_Char(SYSDATE, 'DY') = 'MON' Then TRUNC(SYSDATE)-3 ELSE TRUNC(SYSDATE)-1 END
And TRUNC(SYSDATE)-1
You can use the Case expression in Where clause. Regards...
Don't use TO_DATE on a column that is already a date (and if it is a string then don't store dates as strings).
So you are not dependent on the date language session parameter, you can compare the date to the start of the ISO week (which is independent of language) and you can compare on a date range so that Oracle can use an index on your date column:
SELECT *
FROM My_Data
WHERE "DATE" < TRUNC(SYSDATE)
AND "DATE" >= CASE TRUNC(SYSDATE) - TRUNC(SYSDATE, 'IW')
WHEN 0 -- Monday
THEN TRUNC(SYSDATE) - 3
ELSE TRUNC(SYSDATE) - 1
END;
or:
SELECT *
FROM My_Data
WHERE "DATE" < TRUNC(SYSDATE)
AND ( ( TRUNC(SYSDATE) - TRUNC(SYSDATE, 'IW') = 0 AND "DATE" >= TRUNC(SYSDATE) - 3 )
OR "DATE" >= TRUNC(SYSDATE) - 1
);

Oracle SQL - How to retrieve the ID Count difference between today vs yesterday

I have a table that captures when a customer purchases a product. It captures a unique purchase id along with a timestamp of when the purchase was made.
I want to be able to query, the difference between how many purchases were taken today vs yesterday?
Not sure how to query this on oracle?
You can use conditional aggregation:
select sum(case when trunc(datecol) = trunc(sysdate - 1) then 1 else 0 end) as num_yesterday,
sum(case when trunc(datecol) = trunc(sysdate) then 1 else 0 end) as num_today,
sum(case when trunc(datecol) = trunc(sysdate) then 1
when trunc(datecol) = trunc(sysdate - 1) then -1
end) as diff
from t
where datecol >= trunc(sysdate - 1);
you can use the Group function to grouping the purchase day with timestamp information and count the purchase id.
select trunc(purchase_ts) Day, count(purchase_id) Count
from purchase
group by trunc(purchase_ts)
order by 1
Using TRUNC on the column will prevent Oracle from using an index on that column (instead you would need a separate function-based index); instead use a CASE statement to test whether the date is between the start of the day and the start of the next day and then COUNT the values between those ranges:
SELECT COUNT(
CASE
WHEN TRUNC( SYSDATE ) - INTERVAL '1' DAY <= your_date_column
AND your_date_coumn < TRUNC( SYSDATE )
THEN 1
END
) AS count_for_yesterday,
COUNT(
CASE
WHEN TRUNC( SYSDATE ) <= your_date_column
AND your_date_coumn < TRUNC( SYSDATE ) + INTERVAL '1' DAY
THEN 1
END
) AS count_for_today
FROM your_table
WHERE TRUNC( SYSDATE ) - INTERVAL '1' DAY <= your_date_column
AND your_date_coumn < TRUNC( SYSDATE ) + INTERVAL '1' DAY

How to get last month's date from specific date in postgresql

I have a max date in my query and If the max date is current month then I want always get previous month’s date. How can I do that?
For example, today is 20160825. If the max date is 20160801 then I want to get 20160701. But, if the max date is 20160501 then I just want to get without changes - 20160501.
SELECT
DEFN_DK,
MAX(SNAPSHOT_MTH)
FROM myTable
WHERE TOT_AMT >0
GROUP BY DEFN_DK
Since your SNAPSHOT_MTH column is an integer (why?) you can not use any of the otherwise very useful timestamp functions. So it's back to integer math, creating a "month" from your snapshot "date" through integer division by 100. This can be compared to CURRENT_DATE by converting that to a string and then casting it to an integer. Going back 1 month similarly requires some math. Not entirely efficient, but here goes:
SELECT DEFN_DK,
CASE max(SNAPSHOT_MTH) / 100
WHEN tochar(CURRENT_DATE, 'YYYYMM')::int THEN
((max(SNAPSHOT_MTH) / 100) - 1) * 100 + 1
-- or max(SNAPSHOT_MTH) - 100, if you know it always ends in 01
ELSE max(SNAPSHOT_MTH)
END AS SNAPSHOT_MTH
FROM myTable
WHERE TOT_AMT > 0
GROUP BY DEFN_DK;
select
defn_dk,
case max(snapshot_mth)
when date_trunc('month', current_date) then max(snapshot_mth) - interval '1 month'
else max(snapshot_mth)
end
from mytable
where tot_amt >0
group by defn_dk
show this, two examples:
select
case when date_trunc('month',dd) = date_trunc('month',now())
then dd - interval'1 month' else date_trunc('day',dd) end
from
(
select '2016-08-04'::date as dd
) d;
and
select
case when date_trunc('month',dd) = date_trunc('month',now())
then dd - interval'1 month' else date_trunc('day',dd) end
from
(
select '2016-05-04'::date as dd
) d;

Oracle. Missing keyword when using case statement. Error 00905

I keep getting an error 'ORA-00905: missing keyword' with the following statement, ever since I introduced the CASE statement, but I can't figure out what is missing.
SELECT
CYCLE_S_FACT_MAIN.STARTTIME,
CYCLE_S_FACT_MAIN.ENDTIME
FROM
CYCLE_S_FACT_MAIN
WHERE
(
CYCLE_S_FACT_MAIN.ENDTIME >
(SELECT SYSDATE,
CASE SYSDATE
WHEN TO_CHAR(SYSDATE, 'HH') < 6 THEN CONCAT(TO_CHAR(SYSDATE, 'DD-MM-YYYY'), ' 06:00:00')
ELSE CONCAT(TO_CHAR(SYSDATE - INTERVAL '1' DAY, 'DD-MM-YYYY'), ' 06:00:00')
END AS SYSDATE
FROM DUAL
)
AND
CYCLE_S_FACT_MAIN.ENDTIME <= SYSDATE
)
You're mixing up the two forms of CASE expressions. There's a simple expression (when you're just wanting to compare expressions for equality):
CASE Expr1
WHEN Expr2 THEN ...
WHEN Expr3 THEN ...
ELSE ...
END
And there's a searched CASE expression, where you want to evaluate separate predicates:
CASE
WHEN Predicate1 THEN ...
WHEN Predicate2 THEN ...
ELSE ...
END
For a searched CASE, you don't specify an expression between CASE and the first WHEN.
Damien_The_Unbeliever is right about mixing case styles, but you also don't need the subquery at all, and the one you have is getting two columns back - which you can't compare with a single value. You can just do this:
WHERE
CYCLE_S_FACT_MAIN.ENDTIME > CASE
WHEN TO_NUMBER(TO_CHAR(SYSDATE, 'HH24')) < 6
THEN TRUNC(SYSDATE) + INTERVAL '6' HOUR
ELSE TRUNC(SYSDATE) - INTERVAL '1' DAY + INTERVAL '6' HOUR END
AND CYCLE_S_FACT_MAIN.ENDTIME <= SYSDATE
This leaves the comparison as between two dates, rather than relying on implcit conversions. I've also used HH24; using HH would treat times between midday and 6pm the same as those between midnight and 6am, which I'm prety sure you didn't intend.
Try as
SELECT
CYCLE_S_FACT_MAIN.STARTTIME,
CYCLE_S_FACT_MAIN.ENDTIME
FROM
CYCLE_S_FACT_MAIN
WHERE
(
CYCLE_S_FACT_MAIN.ENDTIME >
(SELECT SYSDATE,
CASE
WHEN TO_CHAR(SYSDATE, 'HH') < 6 THEN CONCAT(TO_CHAR(SYSDATE, 'DD-MM-YYYY'), ' 06:00:00')
ELSE CONCAT(TO_CHAR(SYSDATE - INTERVAL '1' DAY, 'DD-MM-YYYY'), ' 06:00:00')
END AS "MY_SYSDATE"
FROM DUAL
)
AND
CYCLE_S_FACT_MAIN.ENDTIME <= SYSDATE
)
There two possible mistakes, one is it is expecting as CASE WHEN not as CASE sysdate WHEN and second one is sysdate as alias which is not possible to use as alias name.
SELECT TO_CHAR(SYSDATE,'HH'),
CASE
WHEN TO_CHAR(SYSDATE,'HH') < 6
THEN CONCAT(TO_CHAR(SYSDATE, 'DD-MM-YYYY'), ' 06:00:00')
ELSE CONCAT(TO_CHAR(SYSDATE - INTERVAL '1' DAY, 'DD-MM-YYYY'), ' 06:00:00')
END "sysdate" ,
TO_CHAR(SYSDATE, 'HH'),
CONCAT(TO_CHAR(SYSDATE, 'DD-MM-YYYY'), ' 06:00:00')
FROM dual;
12 24-07-2013 06:00:00 12 25-07-2013 06:00:00

How to use CASE together with date INTERVAL?

I want to have this query:
SELECT DATE(DATE_SUB(DATE('2010-09-10'), (CASE DATETYPE WHEN 'H' THEN INTERVAL 1 WEEK ELSE INTERVAL 1 YEAR END CASE))) AS wdt
MySQL says it's invalid
also I have tried
SELECT _DATE AS wdt
UNION ALL
CASE DATETYPE
WHEN 'H' THEN SELECT DATE(DATE_SUB(_DATE, INTERVAL 1 YEAR)) AS wdt ;
ELSE SELECT DATE(DATE_SUB(DATE('2010-09-10'), INTERVAL 1 WEEK )) AS wdt;
END CASE;
UNION ALL
SELECT DATE(DATE_SUB(_DATE, INTERVAL 2 WEEK)) AS wdt
which doesn't work also, error in query syntax.
How can I select interval 1 year for dates that are Holidays.
Using two DATE_SUB operations would work:
SELECT IF (DATETYPE = 'H',
DATE_SUB(DATE('2010-09-10'), INTERVAL 1 WEEK),
DATE_SUB(DATE('2010-09-10'), INTERVAL 1 YEAR))
as wdt;