redshift sql current_date get_date() performance issue - sql

I would like to know whether using the current_date or get_date() function on redshift SQL would lower the query performance compared to using '2016-05-05' directly, for example.
Example 1:
select
*
from
table a
where time >= current_date - 1
and time < current_date
Example 2:
select
*
from table a
where time >='2016-05-08'
and time < '2016-05-09'
Would example 1 or example 2 have better performance? Or would both have the same?
Hope someone could shed some light on it

I just ran up against this, so I shall share my anecdotal experience:
select * from table where ts > current_date limit 20 was running for 10+mins before I got impatient and killed it.
select * from table where ts > '2017-06-08' limit 20 completed in 16s.
table has a sort key on ts, and was freshly analyzed

Related

Query records which have been in a certain status for one hour or more

So I have a question (running oracle sql developer), I can't seem to get the syntax of it right.
Let's say T1 has a stat_code column and a last_updated column; I want to query all records which have been in t1.stat_code < 90 for one hour or more.
From research I have come with the following query;
select * from t1
where t1.stat_code <90
and t1.last_updated > (SYSDATE-1/24);
This is right, but also pulls back records which are less than an hour old.
Any help is very much appreciated!
You could also use an INTERVAL literal to explicitly state the duration:
SELECT *
FROM t1
WHERE stat_code < 90
AND last_updated <= SYSTIMESTAMP - INTERVAL '1' HOUR;

SQLite query to get the closest datetime

I am trying to write an SQLite statement to get the closest datetime from an user input (from a WPF datepicker). I have a table IRquote(rateId, quoteDateAndTime, quoteValue).
For example, if the user enter 10/01/2000 and the database have only fixing stored for 08/01/2000, 07/01/2000 and 14/01/2000, it would return 08/01/2000, being the closest date from 10/01/2000.
Of course, I'd like it to work not only with dates but also with time.
I tried with this query, but it returns the row with the furthest date, and not the closest one:
SELECT quoteValue FROM IRquote
WHERE rateId = '" + pRefIndexTicker + "'
ORDER BY abs(datetime(quoteDateAndTime) - datetime('" + DateTimeSQLite(pFixingDate) + "')) ASC
LIMIT 1;
Note that I have a function DateTimeSQLite to transform user input to the right format.
I don't get why this does not work.
How could I do it? Thanks for your help
To get the closest date, you will need to use the strftime('%s', datetime) SQLite function.
With this example/demo, you will get the most closest date to your given date.
Note that the date 2015-06-25 10:00:00 is the input datetime that the user selected.
select t.ID, t.Price, t.PriceDate,
abs(strftime('%s','2015-06-25 10:00:00') - strftime('%s', t.PriceDate)) as 'ClosestDate'
from Test t
order by abs(strftime('%s','2015-06-25 10:00:00') - strftime('%s', PriceDate))
limit 1;
SQL explanation:
We use the strftime('%s') - strftime('%s') to calculate the difference, in seconds, between the two dates (Note: it has to be '%s', not '%S'). Since this can be either positive or negative, we also need to use the abs function to make it all positive to ensure that our order by and subsequent limit 1 sections work correct.
If the table is big, and there is an index on the datetime column, this will use the index to get the 2 closest rows (above and below the supplied value) and will be more efficient:
select *
from
( select *
from
( select t.ID, t.Price, t.PriceDate
from Test t
where t.PriceDate <= datetime('2015-06-23 10:00:00')
order by t.PriceDate desc
limit 1
) d
union all
select * from
( select t.ID, t.Price, t.PriceDate
from Test t
where t.PriceDate > datetime('2015-06-23 10:00:00')
order by t.PriceDate asc
limit 1
) a
) x
order by abs(julianday('2015-06-23 10:00:00') - julianday(PriceDate))
limit 1 ;
Tested in SQLfiddle.
Another useful solution is using BETWEEN operator, if you can determine upper and lower bounds for your time/date query. I encountered this solution just recently here in this link. This is what i've used for my application on a time column named t (changing code for date column and date function is not difficult):
select *
from myTable
where t BETWEEN '09:35:00' and '09:45:00'
order by ABS(strftime('%s',t) - strftime('%s','09:40:00')) asc
limit 1
Also, i must correct my comment on above post. I tried a simple examination of speed of these 3 approaches proposed by #BerndLinde, #ypercubeᵀᴹ and me . I have around 500 tables with 150 rows in each and medium hardware in my PC. The result is:
Solution 1 (using strftime) takes around 12 seconds.
Adding index of column t to solution 1 improves speed by around 30% and takes around 8 seconds. I didn't face any improvement for using index of time(t).
Solution 2 also has around 30% of speed improvement over Solution 1 and takes around 8 seconds
Finally, Solution 3 has around 50% improvement and takes around 5.5 seconds. Adding index of column t gives a little more improvement and takes around 4.8 seconds. Index of time(t) has no effect in this solution.
Note: I'm a simple programmer and this is a simple test in .NET code. A real performance test must consider more professional aspects, which i'm not aware of them. There was also some computations in my code, after querying and reading from database. Also, as #ypercubeᵀᴹ states, this result my not work for large amount of data.

SQL: Difference between "BETWEEN" vs "current_date - number"

I am wondering which of the following is the best way to implement and why.
select * from table1 where request_time between '01/18/2012' and '02/17/2012'
and
select * from table1 where request_time > current_date - 30
I ran the two queries through some of my date tables in my database and using EXPLAIN ANALYZE I found these results:
explain analyze
select * from capone.dim_date where date between '01/18/2012' and '02/17/2012'
Total runtime: 22.716 ms
explain analyze
select * from capone.dim_date where date > current_date - 30
Total runtime: 65.044 ms
So it looks like the 1st option is more optimal. Of course this is biased towards my DBMS but these are still the results I got.
The table has dates ranging from 1900 to 2099 so it is rather large, and not just some dinky little table.
Between has the inclusive ranges i.e when you issue a query like id between 2 and 10 the value of 2 and 10 will also be fetched.If you want to eliminate these values use > and <.
Also when indexes are applied say on date column > and < makes a good use of index than between.

Is it possible to write a query which returns a date for every day between two specified days?

Basically, the question says it all. I need a PL\SQL query that returns a list of dates between two dates such that for 01-JAN-2010 to 20-JAN-2010 I would get 20 rows returned:
the_date
--------
01-JAN-2010
02-JAN-2010
03-JAN-2010
04-JAN-2010
...
20-JAN-2010
The following query will return each day between 1/1 and 1/20 (inclusive).
select to_date('1/1/2010','mm/dd/yyyy')+level
from dual
connect by level <= to_date('1/20/2010','mm/dd/yyyy')
- to_date('1/1/2010','mm/dd/yyyy');
Here's an example from postgres, I hope the dialects are comparable in regards to recursive
WITH RECURSIVE t(n) AS (
VALUES (1)
UNION ALL
SELECT n+1 FROM t WHERE n < 20
)
SELECT n FROM t;
...will return 20 records, numbers from 1 to 20
Cast/convert these to dates and there you are
UPDATE:
Sorry, don't have ORA here, but according to this article
SELECT
SYS_CONNECT_BY_PATH(DUMMY, '/')
FROM
DUAL
CONNECT BY
LEVEL<4;
gives
SYS_CONNECT_BY_PATH(DUMMY,'/')
--------------------------------
/X
/X/X
/X/X/X
It is also stated that this is supposed to be very efficient way to generate rows.
If ROWNUM can be used in the above select and if variable can be used in LEVEL condition then solution can be worked out.
UPDATE2:
And indeed there are several options.
SELECT (CAST('01-JAN-2010' AS DATE) + (ROWNUM - 1)) n
FROM ( SELECT 1 just_a_column
FROM dual
CONNECT BY LEVEL <= 20
)
orafaq states that: 'It should be noted that in later versions of oracle, at least as far back as 10gR1, operations against dual are optimized such that they require no logical or physical I/O operations. This makes them quite fast.', so I would say this is not completely esoteric.
OK, so it might seem a little hacky, but here's what I've come up with:
SELECT (CAST('01-JAN-2010' AS DATE) + (ROWNUM - 1)) AS the_date
FROM all_objects
WHERE ROWNUM <= CAST('20-JAN-2010' AS DATE) - CAST('01-JAN-2010' AS DATE) + 1
The magic sauce is using ROWNUM as a seed for date arithmetic, I'm using all_objects but you could use any table that has enough rows in it to supply the required range. You can shuffle it around to make it work off SYSDATE instead of hard coding the value, but in principle I think that the idea is sound.
Here's an example that returns a list of dates from 10 days ago to 10 days time:
SELECT (SYSDATE -10 + (ROWNUM-1)) AS the_date
FROM all_objects
WHERE ROWNUM <= (SYSDATE +10) - (SYSDATE -10) + 1
No. Queries can only return existing data - and if you have no table of all days, you are out.
That said (I am no oracle specialist), a function or stored procedure should be able to do that. In SQL Server I would have a function returning a table (that I could then use in joins).
But a pure query - no. Not unless oracle has such a function already.

What Is The Optimal Way To Select Rows From Last 7 Days?

What's the best way to select only those rows from the table that have been created in last 7 days?
There are dozens of time and date functions in MySQL and I'm a little bit confused about what's the easiest way to do this.
For the sake of this question, assume that you have a table called "my_table" and it contains a row "created_at" which is a DATETIME.
SELECT * FROM my_table WHERE ...
What would you fill in the WHERE clause?
WHERE DATEDIFF(NOW(), created_at) <= 7;
I like it because it reads: "Where the Difference in Date between Now and when it was created is at most 7 (days)." in my own head
...WHERE created_at >= Date_Add(now(), INTERVAL -7 DAY)
This is my preferred way because it's so...clear. But ADDDATE is fine too (and you can use the INTERVAL form with that for clarity as well; its default is days so you see people leaving it off). You don't want to do a calculation on created_at and compare it to now() because that requires the computation on created_at on each row (assuming MySQL doesn't optimise it out), whereas modifying now() and comparing to an unmodified created_at means MySQL does that bit once and uses the result when comparing against rows, not to mention indexes.
...... WHERE created_at >= DATE_SUB(CURRENT_DATE, INTERVAL 7 DAY)
hopefully that will help
WHERE ADDDATE(datefield, 7) > NOW();
SELECT * FROM my_table
WHERE DATE(created_at) >= SUBDATE(DATE(NOW()), 7)
SELECT * FROM my_table WHERE my_table.datefield > sysdate - 7