Oracle results from last X days while ignoring time - sql

Right now I have the following query which returns results from the last 60 days
select * from my_table where date_col > sysdate - 60
But it is also taking time of the day into consideration. For example today is
Sept 30 2021 10:30:00 AM
and the query would return results from Oct 01 2021 10:31:00 AM, but not from Oct 01 2021 10:29:00 AM
How can I modify the query that it does not care about the time when getting the last 60 days? I would the query to return results even if the row had a date of Oct 01 2021 00:00:01 AM

It sounds like you just want to trunc the sysdate. I'd guess that you want to do a >= as well.
WHERE date_col >= trunc(sysdate) - 60

Related

How to order by for customer week number which contains year number too

I have a table with one row
employee(date)
date
52 week in 2021
23 week in 2022
34 week in 2021
1 week in 2022
52 week in 2022
I tried the below query but it's not working
select date from employee order by date desc
I want to order by in desc for above column. I'm expecting output like below
date
52 week in 2022
23 week in 2022
1 week in 2022
52 week in 2021
34 week in 2021
Extracting year and week part and then performing sort:
SELECT *
FROM tab
ORDER BY RIGHT(date,4) DESC, CAST(LEFT(date,2) AS INT) DESC

Subtraction of inventory from Demand in BigQuery everday and adding new inventory

Here's how my data looks like:
date
sku
inventory_added
demand
22nd Nov 2021
XYZ
70
18
23rd Nov 2021
XYZ
0
18
24th Nov 2021
XYZ
0
50
25th Nov 2021
XYZ
0
15
26th Nov 2021
XYZ
80
30
27th Nov 2021
XYZ
0
20
28th Nov 2021
XYZ
0
15
29th Nov 2021
XYZ
0
20
30th Nov 2021
XYZ
0
10
1st Dec 2021
XYZ
100
40
2nd Dec 2021
XYZ
0
10
I want to create a new column named solution using BigQuery SQL where in the 1st row, i.e. 22nd Nov 2021, I want formula as - inventory_added - demand.
This will give me 1st row's value for solution will be 52.
Now what I am not able to do is from 2nd row:
So, next now, will be 52 (remaining inventory from previous day) + 0 (inventory_added on 23rd Nov 2021) - 18 (demand on 23 Nov 2021). This is equal to 34.
Similarly going to next row, i.e. 24th November:
value in solution will be 34 + 0 - 50 = -16. Now since it is negative, it should be put as 0.
I tried this - MAX(solutions, 0).
The result will look like this:
date
sku
inventory_added
demand
solution
22nd Nov 2021
XYZ
70
18
52
23rd Nov 2021
XYZ
0
18
34
24th Nov 2021
XYZ
0
50
0
25th Nov 2021
XYZ
0
15
0
26th Nov 2021
XYZ
80
30
50
27th Nov 2021
XYZ
0
20
30
28th Nov 2021
XYZ
0
15
15
29th Nov 2021
XYZ
0
20
0
30th Nov 2021
XYZ
0
10
0
1st Dec 2021
XYZ
100
40
60
2nd Dec 2021
XYZ
0
10
50
I am not sure if this can be accomplished by BigQuery, but all suggestions are welcome.
Thanks!
Without the condition "it is negative, it should be put as 0" you may use window (in BigQuery terms - analytic) variant of SUM() function:
SELECT *,
SUM(inventory_added - demand) OVER (PARTITION BY sku ORDER BY date) AS solution
FROM source_table
With this condition the output become iterative, and you must use recursive CTE (if available in BigQuery) or iterative stored procedure.
I see that recursive CTE is not available in BigQuery ... Can you provide a pseudo code may as a starting point for stored procedures? – Shantanu Jain
CREATE PROCEDURE procname()
BEGIN
CREATE temptable;
OPEN CURSOR FOR SELECT * FROM datatable ORDER BY date;
SET #solution = 0;
FETCH CURSOR INTO #date, #sku, #inventory_added, #demand;
LOOP ​
​ SET #solution = GREATEST(#solution + #inventory_added - #demand, 0);
​ INSERT INTO temptable VALUES (#date, #sku, #inventory_added, #demand, #solution);
FETCH CURSOR INTO #date, #sku, #inventory_added, #demand;
UNTIL NO_ROWS_IN_CURSOR END LOOP;
SELECT * FROM temptable;
DROP temptable;
END
AS an option - consider use of recently introduced FOR...IN Loop
declare result int64;
declare prev_sku string;
create temp table results as (select *, 0 as solution from your_table where false);
set (result, prev_sku) = (0, '');
for record in (select *, parse_date('%d %B %Y', regexp_replace(date, r'(\d*)(\w*)( \w{3} \d{4})', r'\1 \3')) dt from your_table order by sku, dt) do
if record.sku != prev_sku then set result = 0; end if;
set result = result + record.inventory_added - record.demand;
if result < 0 then set result = 0; end if;
insert into results values(record.date, record.sku, record.inventory_added, record.demand, result);
set prev_sku = record.sku;
end for;
select * from results
order by sku, parse_date('%d %B %Y', regexp_replace(date, r'(\d*)(\w*)( \w{3} \d{4})', r'\1 \3'));
If applied to sample data in your question - output is
Note: While delivering expected result - obviously this is going to be extremely slow (as any cursor based solution) - so while applicable for learning - I don't think appropriate for real production use

How do I bring back the data for just weekends and evenings in SQL?

I'm creating two separate views. One for the day staff and one for the nights and weekend team. The first query works (or brings back data at least) between 08:00 - 21:00 Mon-Fri and 09:00 - 17:00 Sat.
The second query brings back the same data but I want it to bring back 00:00 - 08:00 & 21:00 23:59 Mon - Fri 00:00 - 09:00 & 17:00 - 23:59 Sat and all day Sunday.
Is it something to do with needing more parenthesis?
1st Query -
((DATEPART(hh,[Timestamp]) >= 08 AND DATEPART(hh,[Timestamp]) <= 21
AND
DATEPART(dw,[Timestamp]) >= 2 AND DATEPART(dw,[Timestamp]) <= 6))
OR
((DATEPART(hh,[Timestamp]) >= 09 AND DATEPART(hh,[Timestamp]) <= 17
AND
DATEPART(dw,[Timestamp]) != 7))
2nd Query -
((DATEPART(hh,[Timestamp]) < 08
AND
DATEPART(dw,[Timestamp]) >= 2 AND DATEPART(dw,[Timestamp]) <= 6))
or
((DATEPART(hh,[Timestamp]) > 21
AND
DATEPART(dw,[Timestamp]) >= 2 AND DATEPART(dw,[Timestamp]) <= 6))
OR
((DATEPART(hh,[Timestamp]) < 09
AND
DATEPART(dw,[Timestamp]) != 7))
OR
((DATEPART(hh,[Timestamp]) > 17
AND
DATEPART(dw,[Timestamp]) != 7))
OR
((DATEPART(dw,[Timestamp]) != 1))
I think you almost had it, but you used != (not equal) instead of just =. So it should be something like this:
(DATEPART(hh,[Timestamp]) < 08 OR DATEPART(hh,[Timestamp]) >= 21) AND (DATEPART(dw,[Timestamp]) >= 2 AND DATEPART(dw,[Timestamp]) <= 6) -- MON-FRI
OR
(DATEPART(hh,[Timestamp]) < 09 OR DATEPART(hh,[Timestamp]) >= 17) AND (DATEPART(dw,[Timestamp]) = 7 ) --SAT
OR
(DATEPART(dw,[Timestamp]) = 1 ) -- SUN
It seems to me you'd probably be better off creating a configuration table like this. SQL Server data types of the columns would be: int,time,time,varchar. Values in DayOfWeek need to be aligned with however the DATEPART() function works on your particular SQL Server for days of week values.
DayOfWeek
StartTime
EndTime
Staff
1
00:00:00
08:00:00
night
1
08:00:00
17:00:00
day
1
17:00:00
23:59:59
day
2
00:00:00
08:00:00
night
...
...
...
...
Then just join your original table/view to the new one on
DATEPART(dw,[yourdate])=newtable.DayOfWeek
AND CAST([yourdate] AS time)>=newtable.StartTime
AND CAST([yourdate] AS time)<newtable.EndTime
Finally you can filter on day or night staff by applying a WHERE clause like this:
WHERE newtable.Staff='day'

Showing data order from Monday-Sunday full week only and hide non-full week data

sorry if I'm shooting newbie questions here.
I want to create a weekly report, but for this weekly report, I want full data from Monday to Sunday
Condition:
Last 4 weeks only
Showing full week (Monday - Sunday)
Hide the result if it's not full week
If i use getdate -14, if I access the data on Wednesday, they will start counting last week from Wednesday 2 weeks ago instead of last Monday. Meanwhile, I want the report to show full week only.
Can anyone share how to do that in SQL?
Here I provide sample data:
Column name = DATE -- Column name: TOTAL_PERSON
- Fri, 1 Jun 2018 -- 10
- Sat, 2 Jun 2018 -- 4
- Sun, 3 Jun 2018 -- 12
- Mon, 4 Jun 2018 -- 15
- Tue, 5 Jun 2018 -- 10
- Wed, 6 Jun 2018 -- 3
- Thu, 7 Jun 2018 -- 1
- Fri, 8 Jun 2018 -- 13
- Sat, 9 Jun 2018 -- 9
- Sun, 10 Jun 2018 -- 23
- Mon, 11 Jun 2018 -- 5
- Tue, 12 Jun 2018 -- 3
- Wed, 13 Jun 2018 -- 1
- Thu, 14 Jun 2018 -- (TODAY)
In this case, if I am accessing on Thu 6 Jun 2018 I want to get TOTAL PERSON data from Mon, 4 Jun 2018 to Sun, 10 Jun 2018 only and not showing data from the rest since the week is not full.
Can anyone help me how to do that?
Thanks a lot!
I think you want:
where datediff(week, date, getdate()) <= 2
This counts the number of week boundaries between two dates, so it returns an entire week.
For MySQL, you can use such a select:
SELECT * FROM `myDB` WHERE `Date`
BETWEEN DATE_SUB(NOW()-INTERVAL DATE_FORMAT(CURRENT_DATE, '%w') DAY, INTERVAL 28 DAY)
AND NOW()- INTERVAL DATE_FORMAT(CURRENT_DATE, '%w') DAY
This uses the capability to transform the current day of this week into a number and substract this to get the last Sunday. from there, we select an intervall of 28 days.
(Only testet with 14 days and a very limited test-dataset, but should work)

getting first day and last day of a quarter and 2 quarters back for a date

how to get first day and last day of a quarter for a date?
and also first day and last day of 2 quarters back for a date in Hive or sql
for example for Feb 03 2014 first day and last day of the quarter will be
Jan 01 2014 and Mar 31 2014
and for the same date first and last day of 2 quarters back will be Jul 01 2013 and Sep 31 2013
You can accomplish this in the following way (not too fancy, but there is no direct way). To make it simpler, I just concatenated both output dates
-- before Hive 1.3
select
case
when ceil(month(mydate)/ 3.0) = 1 then concat("Jan 01 ",year(mydate),"|","Mar 31 ",year(mydate))
when ceil(month(mydate)/ 3.0) = 2 then then concat("Apr 01 ",year(mydate),"|","Jun 30 ",year(mydate))
when ceil(month(mydate)/ 3.0) = 3 then then concat("Jul 01 ",year(mydate),"|","Sep 30 ",year(mydate))
when ceil(month(mydate)/ 3.0) = 4 then then concat("Oct 01 ",year(mydate),"|","Dec 31 ",year(mydate))
else
null
end,
ceil(month(mydate)) as quarter
from (
select
from_unixtime(unix_timestamp('Feb 03 2014' , 'MMM dd yyyy')) as mydate
) t;
--Hive 1.3 or higher
select
case
when quarter(mydate) = 1 then concat("Jan 01 ",year(mydate),"|","Mar 31 ",year(mydate))
when quarter(mydate) = 2 then then concat("Apr 01 ",year(mydate),"|","Jun 30 ",year(mydate))
when quarter(mydate) = 3 then then concat("Jul 01 ",year(mydate),"|","Sep 30 ",year(mydate))
when quarter(mydate) = 4 then then concat("Oct 01 ",year(mydate),"|","Dec 31 ",year(mydate))
else
null
end,
ceil(month(mydate)) as quarter
from (
select
from_unixtime(unix_timestamp('Feb 03 2014' , 'MMM dd yyyy')) as mydate
) t;
just replace the hardcoded date for your column in the select in the inner query