Have table: item (int) and timestamp (datetime).
Need to know if there are any records with timestamp after last 6 AM.
Example:
At 5 AM it should check if there are any records from after 6 AM
yesterday. AT 7 AM it should check if there are any records from
after 6 AM today
This could be done of course by making a variable with datepart as:
if time now is < 6 AM datepart should be yesterday if time now
is >= 6 AM datepart should be today
but there must be a simpler way ?
This expression should always return the most recent 06:00 in the past:
select DATEADD(hour,
(DATEDIFF(hour,'2014-01-01T06:00:00',CURRENT_TIMESTAMP)/24)*24,
'2014-01-01T06:00:00')
It works by asking how many hours have happened since some arbitrary, known, 6AM. We then round this number down to the closest multiple of 24 (by dividing and multiplying with integer maths), and add this number back onto the same, arbitrary, 6AM
Related
In PL/SQL I have 2 dates and I need to find out the number of months between them and the days as well. For example date 1 is 1/10/2022 and date 2 is 2/12/2022 that would be 1 month and 2 days. I'm pretty secure in obtaining the number of months, but the days number has been a thorn in my side. Sometimes it comes out correct, sometimes it comes out short and other times it comes out too far. I would imagine it is because of the different number of days in the months, but I can't prove that just yet. Any help is appreciated.
Oracle provides a months_between function to do the calculation.
That isn't a good idea as the number of days in a month varies, it's not exactly known what the decimal part of the number represents.
select months_between(date '2022-04-03', date '2022-01-01') from dual;
MONTHS_BETWEEN(DATE'2022-04-03',DATE'2022-01-01')
3.06451612903225806451612903225806451613
If you assume every month has 30 days, then comparisons over larger date ranges (years) will be out by more and more days the larger the difference gets.
However, if you combine methods, using months_between to get the months, and then assume 30 days for a month to get the days part from the remainder, it's more consistent over longer periods…
with dates as (select date '2022-01-01' as date_from, date '2022-04-03' as date_to from dual)
select months_between(date_to, date_from) ,trunc(months_between(date_to, date_from)) as months ,round(mod(months_between(date_to, date_from),1)*30) as days
from dates
MONTHS_BETWEEN(DATE_TO,DATE_FROM) MONTHS DAYS
3.06451612903225806451612903225806451613 3 2
Background
I've been working on some reporting views that get a multi-day work shift and are supposed to do some calculations based on data, but I'm a bit stuck here.
A typical shift is either 3 calendar days usually 1 half-day and two full days, or a whole week consisting of 2 half-days (end and start) and 5 full days.
Specifications
I have the following specifications for what is a full day and half-day. These rules are based on regulation and can't be changed.
2 half-days != 1 full-day, the 2 halves is more "valuable"
Given a started_at iso datetime and end_at iso datetime
I want to get two numbers, full_days, and half_days
A half day is
A day at the start of the range starting at or after 12.00
A day at the end of the range which ends before 19.00
A full day is
A day within the range (traditional 24hours)
A day at the start of the range starting before 12.00
A day at the end of the range which ends at or after 19.00
I'm thinking either a row per full-day and half-day or an aggregated row with half_days and full_days as two separate columns would be ideal in the view to connect it with my other views.
Simplified model
I simplified the data model to leave out unnecessary columns.
create table if not exists [trip]
(
trip_id integer
constraint trip_pk
primary key,
started_at text default (datetime('now')),
end_at text default (datetime('now'))
);
And I'm a bit stuck with how I should design this query. A simple time delta doesn't work.
SQLFiddle with sample data and answers: http://sqlfiddle.com/#!5/de7551/2
You can solve this with a CTE which calculates the day span (number of days the shift spans). Since half days are always 1, 2 or 0 (only occur on end and start) we don't actually need to consider each day by itself.
You can use julianday to get the day as a number, however julian days start at noon so you'll need to subtract 0.5 to get the "actual" day for your calculation. Floor the ending day to avoid a to long span if the end time is later then the start time on each respective day, and round up the result to include partial days as a spanned day.
At this point we can calculate number of half days by checking the end and start. To get the number of full days we simply subtract the half days from the result.
with trip_spans as (
select
ceil(julianday(end_at)-0.5 - floor(julianday(started_at)-0.5)) day_span
, t.*
, (
iif(time(started_at) > time('12:00'), 1, 0)
+
iif(time(end_at) <= time('19:00'), 1, 0)
) half_days
from trip t
)
select
trip_spans.*
, day_span-half_days full_days
from trip_spans
I apologize, I am new at SQL. I am using BigQuery. I have a field called "last_engaged_date", this field is a datetime value (2021-12-12 00:00:00 UTC). I am trying to perform a count on the number of records that were "engaged" 12 months ago, 18 months ago, and 24 months ago based on this field. At first, to make it simple for myself, I was just trying to get a count of the number of records per year, something like:
Select count(id), year(last_engaged_date) as last_engaged_year
from xyz
group by last_engaged_year
order by last_engaged_year asc
I know that there are a lot of things wrong with this query but primarily, BQ says that "Year" is not a valid function? Either way, What I really need is something like:
Date() - last_engaged_date = int(# of months)
count if <= 12 months as "12_months_count" (# of records where now - last engaged date is less than or equal to 12 months)
count if <= 18 months as "18_months_count"
count if <= 24 months as "24_months_count"
So that I have a count of how many records for each last_engaged_date period there are.
I hope this makes sense. Thank you so much for any ideas
[How to] Return the number of months between now and datetime value [in BigQuery] SQL
The simples way is just to use DATE_DIFF function as in below example
date_diff(current_date(), date(last_engaged_date), month)
So in my query, I simply need to narrow down the results by whoever's status was last updated 3 weeks ago.
The line:
AND DATE_ADD(user_status_updated, INTERVAL - 21 DAY)
returns the results as an interval from now and 21 days from now. I am only interested in the exact date 21 days ago, but cannot find the right function to use.
I am writing automatic emails and part of this project is to check daily for users that have been inactive for 3 weeks, so it will always be a matter of NOW() minus 21 days. But I don't want the interval, I want the exact 21 days ago since last updated results.
Ok I found my solution.
WHERE user_status_updated= DATE_SUB(DATE(NOW()), INTERVAL 21 DAY)
The user_status_updated is a DATETIME field
USERS
ID TIMEMODIFIED
1 1400481271
2 1400481489
3 1400486453
4 1400486525
5 1401777484
I have timemodified field, From timemodified, I need to get the rows of last 4 weeks by taking from today's date.
SELECT id FROM USERS
WHERE FROM_UNIXTIME(timemodified,'%d-%m-%Y') >= curdate()
AND FROM_UNIXTIME(timemodified,'%d-%m-%Y') < curdate()-1
Your times are already in Unix timestamp format. Bear in mind that it'll be far more efficient to compare [TIMEMODIFIED] against the current date converted to a Unix timestamp. In addition, you don't need to check any upper bound unless [TIMEMODIFIED] can be in the future.
Try:
-- 60x60x24x7x4 = 2419200 seconds in four weeks
SET #unix_four_weeks_ago = UNIX_TIMESTAMP(curdate()) - 2419200;
SELECT id FROM USERS
WHERE timemodified >= #unix_four_weeks_ago;
NB. Four weeks ago (i.e. today – 28 days) was 1,437,696,000 (24th July) at the time of this answer. The latest record in the sample you provided has a timestamp going back to the 3rd June 2014, and so none of these records will be returned by the query.