SQL Efficiencies - sql

Say I had the following table
-----------------------------
-- ID | DATE --
-- 01 | 1577836799998 --
-- 02 | 1577836799999 --
-- 03 | 1577836800000 --
-- 04 | 1577836800001 --
-----------------------------
I wish to select all data IDs relative to a timestamp. Is it more efficient to convert the timestamp (1) before or (2) after the operator? How does this impact efficiency?
(1)
SELECT ID
FROM TABLE
WHERE DATEADD(MS, DATE, '1970-01-01') > '2020-01-01'
(2)
SELECT ID
FROM TABLE
WHERE DATE > DATE_PART('EPOCH_MILLISECOND', TO_TIMESTAMP('2020-01-01'))
Would it be the latter (2)? Because it only has to convert the comparison timestamp once without converting every single date in the table to compare?

You are asking which of these is more efficient:
WHERE DATEADD(MS, DATE, '1970-01-01') > '2020-01-01'
WHERE DATE > DATE_PART('EPOCH_MILLISECOND', TO_TIMESTAMP('2020-01-01'))
First, they may result in the same execution plan, so there might be no difference.
That said, the second is much, much preferable. Why? The data has information about columns, such as:
Available indexes
Available partitions
Statistics
These can be used to choose the best query plan. So, you have more options with the second method, because the "bare" column is better understood than the column that is the argument to a function.

Related

Indexing an SQL table by datetime that is scaling

I have a large table that gets anywhere from 1-3 new entries per minute. I need to be able to find records at specific times which I can do by using a SELECT statement but it's incredibly slow. Lets say the table looks like this:
Device | Date-Time | Data |
-----------------------------------
1 | 2020-01-01 08:00 | 325
2 | 2020-01-01 08:01 | 384
1 | 2020-01-01 08:01 | 175
3 | 2020-01-01 08:01 | 8435
7 | 2020-01-01 08:02 | 784
.
.
.
I'm trying to get data like this:
SELECT *
FROM table
WHERE Date-Time = '2020-01-01 08:00' AND Device = '1'
I also need to get data like this:
SELECT *
FROM table
WHERE Date-Time > '2020-01-01 08:00' Date-Time < '2020-01-10 08:00' AND Device = '1'
But I don't know what the Date-Time will be until requested. In this case, I will have to search the entire table for these times. Can I index the start of the day so I know where dates are?
Is there a way to index this table in order to dramatically decrease the queries? Or is there a better way to achieve this?
I have tried indexing the Date-Time column but I did not decrease the query time at all.
For this query:
SELECT *
FROM mytable
WHERE date_time = '2020-01-01 08:00' AND device = 1
You want an index on mytable(date_time, device). This matches the columns that come into play in the WHERE clause, so the database should be able to lookup the matching rows efficiently.
Note that I removed the single quotes around the literal value given to device: if this is an integer, as it looks like, then it should be treated as such.
The ordering of the column in the index matters; generally, you want the most restrictive column first - from the description of your question, this would probably be date_time, hence the above suggestion. You might want to try the other way around as well (so: mytable(device, date_time)).
Another thing to keep in mind from performance perspective: you should probably enumerate the columns you want in the SELECT clause; if you just want a few additional columns, then it can be useful to add them to the index as well; this gives you a covering index, that the database can use to execute the whole query without even looking back at the data.
Say:
SELECT date_time, device, col1, col2
FROM mytable
WHERE date_time = '2020-01-01 08:00' AND device = 1
Then consider:
mytable(date_time, device, col1, col2)
Or:
mytable(device, date_time, col1, col2)
You can use TimeInMilliseconds as new column and populate it with milliseconds from the year 1970 and create Index on this column. TimeInMilliseconds will always be unique number and it will help the index to search queries faster.

traversing the records in sql

I would like to get the output for the over lapping date records
> Data: Id Open_date Closed_Date
> 1 2016-01-01 2017-01-01
**> 1 2016-12-31 2018-21-01
> 1 2016-01-01 2018-01-01**
> 2 2017-01-01 2018-02-02
Here, you see the second & 3rd records are starting with date than the closed_Date of their previous records. Here i need to identify those type of records
As you question is not much clear, I am assuming that you are looking for min of open date and max of close date.
If this is not the requirement edit the question to provide more details.
select id, min(Open_date), max(Closed_Date)
from table
group by id
Looks like you want to normalize a Slowly Changing Dimension Type 2. Of course the best way to handle them would be using Temporal tables using either Teradata or ANSI syntax.
There's a nice syntax in Teradata to get your expected result based on the Period data type, but it's imple to cast your begin/end dates to a period:
SELECT id,
-- split the period back into seperate dates
Begin(pd) AS Open_date,
End(pd) AS Closed_Date
FROM
(
SELECT NORMALIZE -- magic keyword :-)
id, PERIOD(Open_date, Closed_Date) AS pd
FROM tab
) AS dt

How to rearrange the value of column

I have a table (tblDates). In this table I have two column (Date,Age) . Now I want If I add new date in this table then Age column rearranged there values.
Table - tblDates
Date Age
--------------------
12/01/14 5
12/02/14 4
12/03/14 3
12/04/14 2
12/05/14 1
If I add New date i.e., 12/06/14 then I want result like this
Table - tblDates
Date Age
--------------------
12/01/14 6
12/02/14 5
12/03/14 4
12/04/14 3
12/05/14 2
12/06/14 1
I may be reading too much into your question, but if your goal is to compute the age (in days) from a given date (today?) to the date stored in your tables, then you'll be better off using the DATEDIFF function and computing the value when you query it each time.
For example:
-- Option 1: Compute when you query it each time in the query you require it
SELECT d.[Date], DATEDIFF(dd, d.[Date], CONVERT(DATE, GETDATE())) as [Age]
FROM tblDates AS d
You can also define the Age column on your table as a Computed Column if it will be used frequently enough, or wrap the table in a View to embed this computation:
-- Option 2: Compute at query time, but build the computation into the table definition
CREATE TABLE [dbo].[tblDates] (
[Date] DATE NOT NULL,
[AgeInDaysComputed] AS (DATEDIFF(dd, [Date], CONVERT(DATE, GETDATE())) )
)
GO
-- Option 3: Compute at query time, but require caller interact with a different object
-- (view) to get the computation
CREATE VIEW [dbo].[vwDates]
AS
SELECT d.[Date], DATEDIFF(dd, d.[Date], CONVERT(DATE, GETDATE())) as [AgeInDays]
FROM dbo.tblDates AS D
GO
One note regarding the GETDATE function: you need to be aware of your server timezone, as GETDATE returns the date according to your server's local timezone. As long as your server configuration and user's configurations are all in the same timezone, this should provide the correct result.
(If the age in days is what you're trying to compute, you may want to edit your question to better reflect this intent for the benefit of future readers, as it is quite different from "rearranging the value of columns")
Pull the values that you want out when you query, not when you insert data. You seem to want:
select d.*, row_number() over (order by date desc) as age
from tblDates d;
Otherwise, your insert operation will become very cumbersome, requiring changes to all the rows in the table.

Sort by / Order by time stored in database "00:00 - 23:00"

I'm trying to figure out an sql query that would allow me to sort data ascending order depending on what time is sorted in appointment_time column, it has values like "00:00" - "23:00"
In my head it looks like this:
SELECT * FROM myTable ORDER BY appointment_time ASC
But I don't know how to make it understand that 00:00 is lower value than 00:01 for example and so on.
They will sort fine as your query is written, easiest thing is to just give it a whirl and see what happens:
SELECT *
FROM myTable
ORDER BY appointment_time ASC
Demo: SQL Fiddle
Alphanumeric ordering has no problem with numbers stored in strings so long as they are zero padded, as is the case with your times.
But I don't know how to make it understand that 00:00 is lower value than 00:01
If all you have is a time then an alphabetical sort should work just fine. If you want to convert to a DateTime you can use CONVERT:
select CONVERT(DATETIME, appointment_time , 108)
If you store from_time and to_time as DATETIME (in two separate columns), the sorting will be done correctly by the DB.
It will also take into consideration the date part as well, i.e. sort 1 Jan 2014 23:00 before 31 Dec 2013 23:30. If you really aren't interested in the date, use a dummy date for all entries and just use the time part of the column.

Select query with date condition

I would like to retrieve the records in certain dates after d/mm/yyyy, or after d/mm/yyyy and before d/mm/yyyy, how can I do it ?
SELECT date
FROM table
WHERE date > 1/09/2008;
and
SELECT date
FROM table
WHERE date > 1/09/2008;
AND date < 1/09/2010
It doesn't work.
Be careful, you're unwittingly asking "where the date is greater than one divided by nine, divided by two thousand and eight".
Put # signs around the date, like this #1/09/2008#
The semicolon character is used to terminate the SQL statement.
You can either use # signs around a date value or use Access's (ACE, Jet, whatever) cast to DATETIME function CDATE(). As its name suggests, DATETIME always includes a time element so your literal values should reflect this fact. The ISO date format is understood perfectly by the SQL engine.
Best not to use BETWEEN for DATETIME in Access: it's modelled using a floating point type and anyhow time is a continuum ;)
DATE and TABLE are reserved words in the SQL Standards, ODBC and Jet 4.0 (and probably beyond) so are best avoided for a data element names:
Your predicates suggest open-open representation of periods (where neither its start date or the end date is included in the period), which is arguably the least popular choice. It makes me wonder if you meant to use closed-open representation (where neither its start date is included but the period ends immediately prior to the end date):
SELECT my_date
FROM MyTable
WHERE my_date >= #2008-09-01 00:00:00#
AND my_date < #2010-09-01 00:00:00#;
Alternatively:
SELECT my_date
FROM MyTable
WHERE my_date >= CDate('2008-09-01 00:00:00')
AND my_date < CDate('2010-09-01 00:00:00');
select Qty, vajan, Rate,Amt,nhamali,ncommission,ntolai from SalesDtl,SalesMSt where SalesDtl.PurEntryNo=1 and SalesMST.SaleDate= (22/03/2014) and SalesMST.SaleNo= SalesDtl.SaleNo;
That should work.
hey guys i think what you are looking for is this one using select command.
With this you can specify a RANGE GREATER THAN(>) OR LESSER THAN(<) IN MySQL WITH THIS:::::
select* from <**TABLE NAME**> where year(**COLUMN NAME**) > **DATE** OR YEAR(COLUMN NAME )< **DATE**;
FOR EXAMPLE:
select name, BIRTH from pet1 where year(birth)> 1996 OR YEAR(BIRTH)< 1989;
+----------+------------+
| name | BIRTH |
+----------+------------+
| bowser | 1979-09-11 |
| chirpy | 1998-09-11 |
| whistler | 1999-09-09 |
+----------+------------+
FOR SIMPLE RANGE LIKE USE ONLY GREATER THAN / LESSER THAN
mysql>
select COLUMN NAME from <TABLE NAME> where year(COLUMN NAME)> 1996;
FOR EXAMPLE
mysql>
select name from pet1 where year(birth)> 1996 OR YEAR(BIRTH)< 1989;
+----------+
| name |
+----------+
| bowser |
| chirpy |
| whistler |
+----------+
3 rows in set (0.00 sec)