ignoring timestamp in WHERE clause when comparing to date - sql

My table has records like these
23-MAY-11 11.40.39.000000 AM
The following query brings nothing
SELECT *
FROM my_table
WHERE tenant_pha = 'test'
AND create_date >= TO_DATE('05/10/2011','mm/dd/yyyy')
AND create_date <= TO_DATE('05/23/2011','mm/dd/yyyy')
However, the below query will bring data
SELECT *
FROM my_table
WHERE tenant_pha = 'test'
AND create_date >= TO_DATE('05/10/2011','mm/dd/yyyy')
AND create_date <= TO_DATE('05/24/2011','mm/dd/yyyy')
I think this is because create_date column is time stamp.
How can I change my query to bring the desired result ( I want to avoid doing functions on the left side columns because they will make the query long).

You are right about the timestamp. '05/23/2011' is the same as '05/23/2011 12:00 AM'.
To include the whole day I usually move my date up by a day. < '05/24/2011' will include all of 5/23.
or change to '05/23/2011 23:59:59'

You can use trunc() without problems, you only need to create a function based index.
If you create this index:
CREATE INDEX idx_trunc_date ON my_table (trunc(create_date));
then the following condition will make use of that index:
AND trunc(create_date) >= TO_DATE('05/10/2011','mm/dd/yyyy')

Related

Is there a work around to avoid using TRUNC(Date) in sql in order to get benefit from indexes?

I have a table BOOKING_DETAILS which DEFINITE_DATE is a column with 'DATE' type. (DB is Oracle 12 c). also, DEFINITE_DATE column is indexed. I want the following query to optimize in order to use the index created for DEFINITE_DATE.
How can I do that?
select *
from BOOKING_DETAILS
where trunc(DEFINITE_DATE) = trunc(TO_DATE('2018-10-26', 'YYYY-MM-DD'))
You may use a between condition in the WHERE clause:
select *
from BOOKING_DETAILS
where DEFINITE_DATE >= date '2018-10-26' and
DEFINITE_DATE < date '2018-10-27';
This would return all records where the definite date falls on 26-October-2018 proper. The above WHERE clause is sargable, because it allows Oracle to use an index on DEFINITE_DATE, should it exist.
If you don't want to create index on trunc(DEFINITE_DATE) and use existing query, you can
select *
from BOOKING_DETAILS
where DEFINITE_DATE >= TO_DATE('2018-10-26', 'YYYY-MM-DD')
and DEFINITE_DATE < TO_DATE('2018-10-26', 'YYYY-MM-DD') + INTERVAL '1' DAY

SQL: How to use 'LIKE' with a date 'between'?

So, i´m trying to select rows between two dates.
In db, the dates also have time.
Therefor i need to use LIKE.
SQL
$query = "SELECT * FROM table WHERE date >= LIKE :selectedDateFrom AND <= LIKE :selectedDateTo";
$query_params = array(':selectedDateFrom' => $selectedDateFrom.="%", ':selectedDateTo' => $selectedDateTo.="%");
This one returns error!
How should it look like?
In db, the dates also have time.
Therefor i need to use LIKE.
No, you don't.
To select all date/times where the date component is between (from) and (to), inclusive, you can write it as
SELECT *
FROM table
WHERE date >= :selectedDateFrom
AND date < :selectedDateToPlusOne
(Note the < instead of <=, and set the second parameter to one day after the last day you want to include in your results.) This works even when the column includes times.
you can't use like with dates in SQL
SO use this:
$query = "SELECT * FROM table WHERE date >= :selectedDateFrom AND date <= :selectedDateTo";
You'd strip the time part from a datetime with DATE().
SELECT *
FROM mytable
WHERE date(mydate) >= :selectedDateFrom
AND date(mydate) <= :selectedDateTo;
Or with BETWEEN for better readability:
SELECT *
FROM mytable
WHERE date(mydate) BETWEEN :selectedDateFrom AND :selectedDateTo;

Postgresql querying timestamp data with date only

I have this data.
this is my query
SELECT transaction_date
FROM
tenant1.txn_transaction_record where '2015-04-14'
The said query renders empty result. Is it possible to query timestamp field using only date?
When you do:
transaction_date = '2015-04-14'
PG will convert string '2015-04-14' to timestamp '2015-04-14 00:00:00' value.
If you do:
transaction_date::date = '2015-04-14'
PG will convert both values to date (wich is only date part, without time part), and it'll work.
BUT... BE CAREFUL WHEN CASTING COLUMNS IN WHERE CLAUSE, because PG will not be able to take advantage of an index that contains that column, unless you've created the index with same cast on the column.
If you create only this index:
create index i_foo_1 on foo ( timestamp_field );
This query WILL NOT use that index:
select *
from foo
where timestamp_field::date = '2015-04-15';
So, or you'll need to create an aditional index:
create index i_foo_2 on foo ( timestamp_field::date );
Or you'll have to change your original "where clause":
select *
from foo
where timestamp_field >= ('2015-04-15'::timestamp)
and timestamp_field < (('2015-04-15'::date)+1)::timestamp;
No, If you do like transaction_date = '2015-04-14' It will automatically search for transaction_date = '2015-04-14T00:00:00' So you wont yield any result. Therefore if you want to search the date try transaction_date::date = '2015-04-14'
So the final query is,
SELECT transaction_date
FROM
tenant1.txn_transaction_record where transaction_date::date = '2015-04-14'
SELECT transaction_date
FROM
tenant1.txn_transaction_record where date_trunc('day', transaction_date) = '2015-04-14 00:00:00'
I don't have a postgres database up to try it :-)

How do I match an entire day to a datetime field?

I have a table for matches. The table has a column named matchdate, which is a datetime field.
If I have 3 matches on 2011-12-01:
2011-12-01 12:00:00
2011-12-01 13:25:00
2011-12-01 16:00:00
How do I query that? How do I query all matches on 1 single date?
I have looked at date_trunc(), to_char(), etc.
Isn't there some "select * where datetime in date" function?
Cast your timestamp value to date if you want simple syntax. Like this:
SELECT *
FROM tbl
WHERE timestamp_col::date = '2011-12-01'; -- date literal
However, with big tables this will be faster:
SELECT *
FROM tbl
WHERE timestamp_col >= '2011-12-01 0:0' -- timestamp literal
AND timestamp_col < '2011-12-02 0:0';
Reason: the second query does not have to transform every single value in the table and can utilize a simple index on the timestamp column. The expression is sargable.
Note excluded the upper bound (< instead of <=) for a correct selection.
You can make up for that by creating an index on an expression like this:
CREATE INDEX tbl_ts_date_idx ON tbl (cast(timestamp_col AS date));
Then the first version of the query will be as fast as it gets.
not sure if i am missing something obvious here, but i think you can just
select * from table where date_trunc('day', ts) = '2011-12-01';
Just use the SQL BETWEEN function like so:
SELECT * FROM table WHERE date BETWEEN '2011-12-01' AND '2011-12-02'
You may need to include times in the date literals, but this should include the lover limit and exclude the upper.
From rails I believe you can do:
.where(:between => '2011-12-01'..'2011-12-02')

Mysql optimization

I'm currently trying to optimize a MYSQL statement that is taking quite some time. The table this is running on is 600k+ and the query is taking over 10 seconds.
SELECT DATE_FORMAT( timestamp, '%Y-%m-%d' ) AS date, COUNT( DISTINCT (
email
) ) AS count
FROM log
WHERE timestamp > '2009-02-23'
AND timestamp < '2020-01-01'
AND TYPE = 'play'
GROUP BY date
ORDER BY date DESC
I've just indexes on timestamp and type and also one on timestamp_type (type_2).
Here is the explain results, the problem seems to be a file sort but I don't know how to get around this...
id: 1
select_type: SIMPLE
table: log
type: ref
possible_keys: type,timestamp,type_2
key: type_2
key_len: 1
ref: const
rows: 226403
Extra: Using where; Using filesort
Thanks
Things to try:
Have a separate date column (indexed) and use that instead of your timestamp column
Add an index across type and date
Use BETWEEN (don't think it will affect the speed but it's easier to read)
So ideally you would
Create a date column and fill it using UPDATE table SET date = DATE(timestamp)
Index across type and date
Change your select to ... type = ? AND date BETWEEN ? AND ?
Try rewriting to filter on TYPE alone first. Then apply your date range and aggregates. Basically create an inline view that filters type down. I know it's likely that the optimizer is doing this already, but when trying to improve performance I find it's helpful to be very certain of what things are happening first.
DATE_FORMAT will not utilizing the indexes.
You can still use the below query to utilize the index on timestamp column
SELECT timestamp AS date, COUNT( DISTINCT (
email
) ) AS count
FROM log
WHERE timestamp > '2009-02-23 00:00:00'
AND timestamp < '2020-01-01 23:59:59'
AND TYPE = 'play'
GROUP BY date
ORDER BY date DESC
Format the datetime value to date while printing/using