SQL Select command to ignore until a condition is met - sql

I've been writing a site (using ASP) that displays data from tables that have a time stamp from 6pm the previous day till the page is loaded.
This I've done.
But to improve on this, I want only the records that occur after a specific record, that has a certain condition. So ignoring everything before that specific record occurs in the select statement (which is ordered by time stamp).
I'm pretty much lost.
Here's my SQL select, any help would be appreciated.
SELECT M.ProductionID, M.FolderNo, M.SetDatetime, M.MessageNumber,
M.MessageText, M.MessageLocation, MD.GrossCopies, MD.NetCopies,
MD.Speed
FROM ST3ROTE_Message AS M
LEFT OUTER JOIN ST3ROTE_MessageData AS MD
ON M.MessageID = MD.MessageID
WHERE M.FolderNo = #DropSelect
AND (M.SetDatetime BETWEEN
CONVERT (DateTime, CONVERT (nchar(4), DATEPART(YYYY, GETDATE()))
+ '-' + CONVERT (nchar(2), DATEPART(MM, GETDATE()))
+ '-' + CONVERT (nchar(2), DATEPART(DD, GETDATE()) - 1)
+ ' 18:00:00') AND CURRENT_TIMESTAMP)
ORDER BY M.MessageID
Here is the data I currently get:
I'm looking to ignore everything before MessageNumber = 27

You could first select the time of the first record with the special condition, in a sub-select (I put it in a with clause). This would return exactly one record per Folder. And then select all records for the same folder that have a time stamp that is not less than that one:
WITH StartRec AS (
SELECT FolderNo, MIN(SetDatetime) SetDatetime
FROM ST3ROTE_Message
WHERE FolderNo = #DropSelect
AND MessageNumber = 27 -- your starting condition
AND SetDatetime BETWEEN
DATEADD(hour, 18, DATEDIFF(day, 1, GETDATE()))
AND CURRENT_TIMESTAMP
GROUP BY FolderNo)
SELECT M.ProductionID, M.FolderNo, M.SetDatetime,
M.MessageNumber, M.MessageText, M.MessageLocation,
MD.GrossCopies, MD.NetCopies, MD.Speed
FROM ST3ROTE_Message AS M
INNER JOIN StartRec
ON StartRec.FolderNo = M.FolderNo
AND StartRec.SetDatetime <= M.SetDatetime
LEFT JOIN ST3ROTE_MessageData AS MD
ON M.MessageID = MD.MessageID
WHERE M.FolderNo = #DropSelect
Here is a fiddle. Note that since the fiddle works with few data, it will not return any records if executed after today.
Also note that your way of calculating "yesterday at 18:00" can be done a lot more efficient, as I have included in the query above:
DATEADD(hour, 18, DATEDIFF(day, 1, GETDATE()))
This first calculates the number of whole days between day 1 (earliest date has value 0) and now. Then this is used as a date (= yesterday 0:00) to which 18 hours are added.
Since you said in comments that SetDateTime reflects the timestamp of an event that happened, and can never be a time in the future, you don't really need a BETWEEN condition for. You could replace:
SetDatetime BETWEEN
DATEADD(hour, 18, DATEDIFF(day, 1, GETDATE()))
AND CURRENT_TIMESTAMP
By:
SetDatetime >= DATEADD(hour, 18, DATEDIFF(day, 1, GETDATE()))

Related

How to go back two days from a date in sql?

I wrote an SQL query that allows me to get the sales of certain stores.
My query runs every mornings and I would like to get the sales from 2 days ago at runtime.
For example if my query runs tomorrow morning, on 08/12, I would like to have the sales whose value in the column "GP_HEURECREATION" starts with "20200612", to have all the sales of the whole day.
The GP_HEURECREATION column has a format like this: "20200612 00:00:00" and is of the DATE type.
I tried with NOW() and DATEADD() but I have 2018 values that stand out for example.
How can I get the values only two days before the query is executed?
SELECT
T_ETABLISSEMENT, ET1.ET_LIBELLE AS C1, GL_ETABLISSEMENT,
GP_HEURECREATION, GP_REFINTERNE, GL_CODEARTICLE,
LIBDIM2, LIBDIM1, GL_QTEFACT, GL_PUTTC,
(GL_TOTALHT * GP_COTATIONDOS) AS TOTALHTDEV, GL_DPR, GL_DEVISE,
GL_NATUREPIECEG, GA_LIBELLE
FROM
GCLIGNEARTDIM
LEFT OUTER JOIN
PGI_LOOKUP(TTETABLISSEMENT) ET1 ON GL_ETABLISSEMENT = ET1.ET_ETABLISSEMENT
WHERE
(GP_HEURECREATION <= DATEADD(day, -2, GETDATE())
AND (GL_NATUREPIECEG = "FFO")
AND GL_ETABLISSEMENT = "20897", "10519", "20267", "26451", "20269", "26078", "28047", "20900", "28085", "24984", "27113", "20268", "19994", "28450", "26876", "24063", "18066", "3220"
ORDER BY
GP_REFINTERNE
The syntax of your existing query suggests SQL Server. If you want records that belong to day -2, you can do:
where gp_heurecreation >= dateadd(day, -2, convert(date, getdate()))
and gp_heurecreation < dateadd(day, -1, convert(date, getdate()))
If gp_heurecreation has no time component (in SQL Server, that's a date datatype), this is simpler:
where gp_heurecreation = dateadd(day, -2, convert(date, getdate()))

How to get data of specific time period through SQL Server

I have multiple device IMEIs and they're sending data continuously. There's a table where the time can be seen when a device has sent the last data in the following format: 12/17/2020 4:05:02 PM. Now I want to get those devices which have sent data within last 4 months. I have got the joins but cannot understand the condition I need to make in the Where clause.
SQL Server is really flexible about converting strings to date, so you should be able to just convert() or cast(), and do direct filtering.
So:
where convert(datetime, mycol) >= dateadd(month, -4, getdate())
This filters on the last 4 months of data, starting from the current date/time. If you want entire months (the current month and the three preceding months)
where convert(datetime, mycol) >= dateadd(month, -3, datefromparts(year(getdate()), month(getdate()), 1)
Now I want to get those devices which have sent data within last 4 months.
This sounds like an exists. If you mean 4 months to the day and the datetime column is stored correctly as a datetime, then:
select d.*
from devices d
where exists (select 1
from table2 t2
where t2.imei = t.imei and
t2.datetime >= dateadd(month, -4, getdate())
);
If you mean in the current calendar month or the previous three, then:
select d.*
from devices d
where exists (select 1
from table2 t2
where t2.imei = t.imei and
t2.datetime >= dateadd(month, -3, datefromparts(year(getdate(), month(getdate()), 1))
);
If the "datetime" column is stored as a string, then fix the data. Use correct types in the table. You can convert to a datetime, because SQL Server will recognize the format:
select d.*
from devices d
where exists (select 1
from table2 t2
where t2.imei = t.imei and
try_convert(datetime, t2.datetime) >= dateadd(month, -4, getdate())
);
However, you should be storing such values using the correct database type.

get the first n characters of getdate()

I have a case compare date, hour of datetime column and current date,hour
select * from tbl where LEFT(EVENT_TIME_column,13) !=LEFT(GETDATE(),13)
EVENT_TIME_column format is '2019-08-15 12:32:40.0000000'
when i perform LEFT(GETDATE(),13) result is 'Aug 15 2019'
can you suggest how to get GETDate() in '2019-08-15 12' (date and hour)
If you want the format yyyy-MM-dd hh then can do this:
SELECT CONVERT(varchar(13),GETDATE(),120);
db<>fiddle
You can find a full list of all the style codes for CONVERT in the documentation: Date and Time Styles
However, it looks like you want to check if the date is within the current hour. That would be:
WHERE EVENT_TIME_column >= DATEADD(HOUR, DATEDIFF(HOUR, 0,GETDATE()),0)
AND EVENT_TIME_column < DATEADD(HOUR, DATEDIFF(HOUR, 0,GETDATE())+1, 0)
This explicitly avoids any functions on the column EVENT_TIME_column; which would make the query non-SARGable.
Don't use string functions on date/time values! There are perfectly good built-in functions:
where convert(date, event_time_column) = convert(date, getdate()) and
datepart(hour, event_time_column) = datepart(hour, getdate())
If you don't care about index usage, then use datediff():
where datediff(hour, event_time_column, getdate()) = 0
You can check this with 2 separate comparison as below. This is for checking Date and Hour part is same as date and hour part if GETDATE() or not.
WHERE CAST(EVENT_TIME_column AS DATE) = CAST(GETDATE() AS DATE)
AND DATEPART(HH,EVENT_TIME_column) = DATEPART(HH,GETDATE())
To check NOT EQUAL TO, Just replace = sign with != sign.
In addition, If I guess correct you are only trying to avoid records from running hour of to date. If this is the case, you can also filter your data with below logic-
WHERE EVENT_TIME_column < DATEADD(hh, DATEDIFF(hh, 0, getdate()), 0)

Get current and last month data if year and month are separate columns,

I'm trying to import current and last month data into a table. Before I import the data I want to delete all the current month data as well as last month data. The problem I'm having is that the year and month are separate columns. Most of the time I could use the following statement to delete the old data before I import the new data:
DELETE FROM MyTable
WHERE YearColumn = YEAR(GETDATE()) AND MonthColumn >= MONTH(DATEADD(MM, - 1, (GETDATE())))
However, the problem with this statement is what happens when January comes along. Say, in January next year, this statement will delete all the records with YearColumn = 2016 and MonthColumn >= 12 while I'd want to delete all the records where YearColumn = 2015 and MonthColumn >= 12 as well as YearColumn = 2016 and MonthColumn >= 1.
What would be the best way to do this?
I have some ideas with case statement in the where clause but it seems it would be pretty complicated and probably slow as well.
Thanks,
You can just apply the same logic to year that you apply to month:
DELETE FROM MyTable
WHERE YearColumn = YEAR(DATEADD(month, - 1, GETDATE())) AND
MonthColumn >= MONTH(DATEADD(month, - 1, GETDATE()))
As a note: I much prefer spelling out the date part names rather than using abbreviations. That way, no one has to think twice about whether MM means months or minutes.
A case expression would be fine too. I doubt you have much to worry about.
DELETE FROM MyTable
WHERE
YearColumn = YEAR(DATEADD(month, -1, GETDATE()))
AND MonthColumn = MONTH(DATEADD(month, -1, GETDATE()))
OR YearColumn = YEAR(GETDATE())
AND MonthColumn = MONTH(GETDATE());
If performance is really an issue you could try adding an extra sargable condition:
DELETE FROM MyTable
WHERE
(
YearColumn = YEAR(DATEADD(month, -1, GETDATE()))
AND MonthColumn = MONTH(DATEADD(month, -1, GETDATE()))
OR YearColumn = YEAR(GETDATE())
AND MonthColumn = MONTH(GETDATE())
)
/* this might help with performance issues */
AND YearColumn >= YEAR(DATEADD(month, -1, GETDATE());

Select dates inside current month SQL

I have a table similar to one below. I'm trying to select only the rows where the Start Date is in the current month. Here is what I have so far, but it's not working.
SELECT *
FROM TABLE1
WHERE StartDate = MONTH(getdate())
How can I select only the values where the start date is in the current month?
Use this construct to avoid functions on the StartDate columns (like MONTH or YEAR). These functions will prevent any index or statistics being used/
SELECT *
FROM TABLE1
WHERE
StartDate >= DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)
AND StartDate < DATEADD(month, 1+DATEDIFF(month, 0, GETDATE()), 0)
Any answer that puts a function on StartDate will not scale as expected. See error number 2 here. The filter is now non-sargable, and index/statistics can't be used. Every row will be looked at for a table scan.
You need to check the month of both fields
WHERE MONTH(startdate) = MONTH(getdate())