when querying a table which has a column "timestamp" (epoch timestamp, UTC, milliseconds, type integer in the bigquery table)
i want to be able to say:
timestamp between one_week_ago and now
without specifying the exact timestamps in each query.
i should add that i know the following working query:
WITH timerange AS
(SELECT *,
TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 7 * 24 HOUR) AS one_week_ago,
CURRENT_TIMESTAMP() AS now,
TIMESTAMP_SECONDS(timestamp) AS measurement_time
FROM table_name),
grouped AS
(SELECT field1, field2, count(*) count
FROM timerange
WHERE measurement_time BETWEEN one_week_ago AND now
GROUP BY field1, field2
)
SELECT * FROM timerange
WHERE field2 = "example"
but why am i not simply able to say:
timestamp between function_call1 and function_call2
?
these are examples of the timestamps: 1491544587, 1491422047, 1491882866, 1491881903 1491436515, 1491436771, 1491436593, 1491436621, 1491436390, 1491436334
https://cloud.google.com/bigquery/docs/reference/legacy-sql
https://cloud.google.com/bigquery/docs/reference/standard-sql/
You can certainly say in Standard SQL like you want:
SELECT *
FROM table
WHERE TIMESTAMP_SECONDS(timestamp) BETWEEN
TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 7 * 24 HOUR)
AND CURRENT_TIMESTAMP()
Related
In Oracle SQL Developer, I have a table called t1 who have two columns col1 defined as NUMBER(19,0) and col2 defined as TIMESTAMP(3).
I have these rows
col1 col2
1 03/01/22 12:00:00,000000000
2 03/01/22 13:00:00,000000000
3 26/11/21 10:27:11,750000000
4 26/11/21 10:27:59,606000000
5 16/12/21 11:47:04,105000000
6 16/12/21 12:29:27,101000000
My sysdate looks like this:
select sysdate from dual;
SYSDATE
03/03/22
I want to create a stored procedure (SP) which will delete rows older than 2 months and displayed message n rows are deleted
But when i execute this statement
select * from t1 where to_date(TRUNC(col2), 'DD/MM/YY') < add_months(sysdate, -2);
I don't get the first 2 rows of my t1 table. I get more than 2 rows
1 03/01/22 12:00:00,000000000
2 03/01/22 13:00:00,000000000
How can i get these rows and deleted it please ?
In Oracle, a DATE data type is a binary data type consisting of 7 bytes (century, year-of-century, month, day, hour, minute and second). It ALWAYS has all of those components and it is NEVER stored with a particular formatting (such as DD/MM/RR).
Your client application (i.e. SQL Developer) may choose to DISPLAY the binary DATE value in a human readable manner by formatting it as DD/MM/RR but that is a function of the client application you are using and not the database.
When you show the entire value:
SELECT TO_CHAR(ADD_MONTHS(sysdate, -2), 'YYYY-MM-DD HH24:MI:SS') AS dt FROM DUAL;
Then it outputs (depending on time zone):
DT
2022-01-03 10:11:28
If you compare that to your values then you can see that 2022-01-03 12:00:00 is not "more than 2 months ago" so it will not be matched.
What you appear to want is not "more than 2 months ago" but "equal to or more than 2 months, ignoring the time component, ago"; which you can get using:
SELECT *
FROM t1
WHERE col2 < add_months(TRUNC(sysdate), -2) + INTERVAL '1' DAY;
or
SELECT *
FROM t1
WHERE TRUNC(col2) <= add_months(TRUNC(sysdate), -2);
(Note: the first query would use an index on col2 but the second query would not; it would require a function-based index on TRUNC(col2) instead.)
Also, don't use TO_DATE on a column that is already a DATE or TIMESTAMP data type. TO_DATE takes a string as the first argument and not a DATE or TIMESTAMP so Oracle will perform an implicit conversion using TO_CHAR and if the format models do not match then you will introduce errors (and since any user can set their own date format in their session parameters at any time then you may get errors for one user that are not present for other users and is very hard to debug).
db<>fiddle here
Perhaps just:
select *
from t1
where col2 < add_months(sysdate, -2);
Unable to retrieve records properly with the formatted date values, need select query with right date format to get all records inserted per day
I have a date string like this in my script -
dateString :='26-MAR-20 05.00.00.00000000 AM';
I want to add 0.313 minutes to this date value. And also I want to
increment it to the next day something like this- '27-MAR-20
05.00.00.00000000 AM';
I tried this
dateString :='26-MAR-20 05.00.00.00000000 AM';
dateString :=to_char(dateField,'DD-MON-YYYY HH24:MI:SS.FF');
dateField := to_timestamp(dateString, 'DD/MON/YYYY HH24:MI:SS.FF') + 0.313 * INTERVAL '1' MINUTE;
I can see the output and inserted these values into the DB but
unable to retrieve records properly with these formatted date values..
I suspect it might be to do with the timestamp fields
When I run this query -
select *from rptallexceptions where exceptiontime between '27-MAR-2020 04.00.00.000000000 AM' and '28-MAR-2020 03.59.00.000000000 AM' order by exceptiontime desc;
--- this one gives 3833 records but expected is 4600
it shows only the records on 27th march., records inserted with timestamp containing 28th march are not retrieved..
select *from rptallexceptions where exceptiontime between '28-MAR-2020 04.00.00.000000000 AM' and '29-MAR-2020 03.59.00.000000000 AM' order by exceptiontime desc;
--- this one returns '0' rows
Excerpt from the script:
cnt :=cnt +1;
dateString :=to_char(dateField,'DD-MON-YYYY HH24:MI:SS.FF');
-- add time difference for each exception.
dateField := to_timestamp(dateString, 'DD/MON/YYYY HH24:MI:SS.FF') + 0.313 * INTERVAL '1' MINUTE;
-- after n*4600 exceptions,update date to next date.
IF REMAINDER(cnt,exceptionsPerDay) = 0 THEN
dateField := to_timestamp(dateField + 1,'DD/MON/YYYY HH24:MI:SS.FF');
END IF;
The way I see it, your problem is that you're comparing timestamps to strings.
Sample table:
SQL> create table test as
2 select to_timestamp('27.03.2020 04:00:00:000000', 'dd.mm.yyyy hh24:mi:ss:ff6') datum, 'A' name from dual
3 union all
4 select to_timestamp('28.03.2020 15:23:00:000000', 'dd.mm.yyyy hh24:mi:ss:ff6') datum, 'A' name from dual;
Table created.
Query should use timestamp, not string:
SQL> select *
2 from test
3 where datum between to_timestamp('25.03.2020 12:00:00:000000am', 'dd.mm.yyyy hh:mi:ss:ff6am') --> timestamp
4 and to_timestamp('28.03.2020 12:00:00:000000am', 'dd.mm.yyyy hh:mi:ss:ff6am'); --> timestamp
DATUM N
--------------------------------------------------------------------------- -
27.03.20 04:00:00,000000000 A
SQL>
You were kind of "lucky" (though, one might call it bad luck as your query didn't fail, but it produced wrong results, according to number of rows being returned) for not getting an error as my database raises (due to different NLS settings):
SQL> select *
2 from test
3 where datum between '25.03.2020 12:00:00:000000am' --> string
4 and '28.03.2020 12:00:00:000000am'; --> string
where datum between '25.03.2020 12:00:00:000000am'
*
ERROR at line 3:
ORA-01830: date format picture ends before converting entire input string
SQL>
Strings are handled differently than dates (or timestamps), or numbers. Maybe you'll see the difference clearly in this example:
SQL> with test (col) as
2 (select '1' from dual union all
3 select '9' from dual union all
4 select '20' from dual
5 )
6 select *
7 from test
8 where col < '9';
CO
--
1
20
SQL>
20 < 9? Yes, if those are strings. The same might have happened to you. Try with proper datatype.
When you do:
dateString :=to_char(dateField,'DD-MON-YYYY HH24:MI:SS.FF');
you are converting whatever is the initial value of dateField to a string; but it looks like that has has not been set yet, so you end up with an empty string (which is the same as null). Your original value of dateString is never being used.
If you skip that and just do:
dateString :='26-MAR-20 05.00.00.00000000 AM';
dateField := to_timestamp(dateString, 'DD/MON/YYYY HH24:MI:SS.FF') + 0.313 * INTERVAL '1' MINUTE;
then you are converting the 2-digit year 20 with a YYYY format element, which will turn it into year 0020, not 2020; but you also don't have AM in the format model, so it will get ORA-01830 anyway, and have HH24 instead of HH. I think your to_char() is attempting to 'correct' the string format, but that's not a great approach.
If you can't control the starting string format then the model has to match that:
dateString :='26-MAR-20 05.00.00.00000000 AM';
dateField := to_timestamp(dateString, 'DD-MON-RR HH:MI:SS.FF AM') + 0.313 * INTERVAL '1' MINUTE;
which gives dateField a value of 2020-03-26 05:00:18.780000.
Later on you do:
dateField := to_timestamp(dateField + 1,'DD/MON/YYYY HH24:MI:SS.FF');
which is also doing an implicit conversion of dateField + 1 - which is converted to a date, incidentally as timestamp + number is a date, not a timestamp - to a string; which will use your NLS_DATE_FORMAT. Presumably that is something like 'DD-MON-YYYY'.
So stepping through that:
dateField + 1 => date '2020-03-27 05:00:18' (losing fractional seconds)
implicit to_char(dateField + 1) => string '27-Mar-2020' (losing time)
to_timestamp(to_char(dateField + 1), '...') => timestamp '2020-03-27 00:00:00.000000' (with time at midnight).
So your between is, at best going to find records between 2020-03-26 05:00:18.780000 and 2020-03-27 00:00:00.0000000 - so it won't pick up any records later than midnight on the 27th.
Don't convert to and from strings when you don't need to; leave data in its native data type (timestamp in this case) and use direct manipulation with intervals.
Using between isn't ideal anyway, because it is inclusive; it would be better to end up with:
exceptiontime >= timestamp '2020-03-26 05:00:18.780000'
and exceptionTime < timestamp '2020-03-27 05:00:18.780000'
I need to get a count of items by date from field1 grouped by last update time. What I am looking for is how many times an item from field1 appears on a specific date for the last 30 days where field 2 = 0. This will be run every day so the date will roll. Field1 will be a number >0, field2 will be any number (negative and positive), last_upd_time will be a system time when the last update occurred. I don't need the time, only the date. My current query that returns all of the data is:
select field1, field2, trunc(last_upd_time)
from table
where field2 = '0' and last_upd_time >= SYSDATE - 30
I have attempted to use count, group by, and group by/having. Not saying I was using them correctly, but I did try.
Try this:
SELECT TO_CHAR(last_upd_time,'DD-MM-YYYY') last_upd_time, COUNT(DISTINCT field1)
FROM table WHERE field2='0' AND
last_upd_time>=SYSDATE - INTERVAL '30' DAY
GROUP BY TO_CHAR(last_upd_time,'DD-MM-YYYY');
I need to query 2 tables, one contains a TIMESTAMP(6) column, other contains a DATE column. I want to write a select statement that prints both values and diff between these two in third column.
SB_BATCH.B_CREATE_DT - timestamp
SB_MESSAGE.M_START_TIME - date
SELECT SB_BATCH.B_UID, SB_BATCH.B_CREATE_DT, SB_MESSAGE.M_START_TIME,
to_date(to_char(SB_BATCH.B_CREATE_DT), 'DD-MON-RR HH24:MI:SS') as time_in_minutes
FROM SB_BATCH, SB_MESSAGE
WHERE
SB_BATCH.B_UID = SB_MESSAGE.M_B_UID;
Result:
Error report -
SQL Error: ORA-01830: date format picture ends before converting entire input string
01830. 00000 - "date format picture ends before converting entire input string"
You can subtract two timestamps to get an INTERVAL DAY TO SECOND, from which you calculate how many minutes elapsed between the two timestamps. In order to convert SB_MESSAGE.M_START_TIME to a timestamp you can use CAST.
Note that I have also removed your implicit table join with an explicit INNER JOIN, moving the join condition to the ON clause.
SELECT t.B_UID,
t.B_CREATE_DT,
t.M_START_TIME,
EXTRACT(DAY FROM t.diff)*24*60 +
EXTRACT(HOUR FROM t.diff)*60 +
EXTRACT(MINUTE FROM t.diff) +
ROUND(EXTRACT(SECOND FROM t.diff) / 60.0) AS diff_in_minutes
FROM
(
SELECT SB_BATCH.B_UID,
SB_BATCH.B_CREATE_DT,
SB_MESSAGE.M_START_TIME,
SB_BATCH.B_CREATE_DT - CAST(SB_MESSAGE.M_START_TIME AS TIMESTAMP) AS diff
FROM SB_BATCH
INNER JOIN SB_MESSAGE
ON SB_BATCH.B_UID = SB_MESSAGE.M_B_UID
) t
Convert the timestamp to a date using cast(... as date). Then take the difference between the dates, which is a number - expressed in days, so if you want it in minutes, multiply by 24*60. Then round the result as needed. I made up a small example below to isolate just the steps needed to answer your question. (Note that your query has many other problems, for example you didn't actually take a difference of anything anywhere. If you need help with your query in general, please post it as a separate question.)
select ts, dt, round( (sysdate - cast(ts as date))*24*60, 2) as time_diff_in_minutes
from (select to_timestamp('2016-08-23 03:22:44.734000', 'yyyy-mm-dd hh24:mi:ss.ff') as ts,
sysdate as dt from dual )
;
TS DT TIME_DIFF_IN_MINUTES
-------------------------------- ------------------- --------------------
2016-08-23 03:22:44.734000000 2016-08-23 08:09:15 286.52
I have dates in this format in my database "01-APR-12" and the column is a DATE type.
My SQL statement looks like this:
SELECT DISTINCT c.customerno, c.lname, c.fname
FROM customer c, sales s
WHERE c.customerno = s.customerno AND s.salestype = 1
AND (s.salesdate BETWEEN '01-APR-12' AND '31-APR-12');
When I try to do it that way, I get this error -- ORA-01839: date not valid for month specified.
Can I even use the BETWEEN keyword with how the date is setup in the database?
If not, is there another way I can get the output of data that is in that date range without having to fix the data in the database?
Thanks!
April has 30 days not 31.
Change
SELECT DISTINCT c.customerno, c.lname, c.fname
FROM customer c, sales s
WHERE c.customerno = s.customerno AND s.salestype = 1
AND (s.salesdate BETWEEN '01-APR-12' AND '31-APR-12');
to
SELECT DISTINCT c.customerno, c.lname, c.fname
FROM customer c, sales s
WHERE c.customerno = s.customerno AND s.salestype = 1
AND (s.salesdate BETWEEN '01-APR-12' AND '30-APR-12');
and you should be good to go.
In case the dates you are checking for range from 1st day of a month to the last day of a month then you may modify the query to avoid the case where you have to explicitly check the LAST day of the month
SELECT DISTINCT c.customerno, c.lname, c.fname
FROM customer c, sales s
WHERE c.customerno = s.customerno
AND s.salestype = 1 AND (s.salesdate BETWEEN '01-APR-12' AND LAST_DAY(TO_DATE('APR-12', 'MON-YY'));
The LAST_DAY function will provide the last day of the month.
The other answers are missing out on something important and will not return the correct results. Dates have date and time components. If your salesdate column is in fact a date that includes time, you will miss out on any sales that happened on April 30 unless they occurred exactly at midnight.
Here's an example:
create table date_temp (temp date);
insert into date_temp values(to_date('01-APR-2014 15:12:00', 'DD-MON-YYYY HH24:MI:SS'));
insert into date_temp values(to_date('30-APR-2014 15:12:00', 'DD-MON-YYYY HH24:MI:SS'));
table DATE_TEMP created.
1 rows inserted.
1 rows inserted.
select * from date_temp where temp between '01-APR-2014' and '30-APR-2014';
Query Result: 01-APR-14
If you want to get all records from April that includes those with time-components in the date fields, you should use the first day of the next month as the second side of the between clause:
select * from date_temp where temp between '01-APR-2014' and '01-MAY-2014';
01-APR-14
30-APR-14