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.
Related
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()))
I am not a SQL expert at all...we are trying to us the following to pull data from the previous week. I am fairly certain the 4 is incorrect, as we want data from Sunday through Saturday. The statement that was created was:
SELECT * FROM Table
Where [Date] Between DATEADD(wk,DATEDIFF(wk,7,GETDATE()),0) AND
DATEADD(wk,DATEDIFF(wk,7,GETDATE()),4)
Assuming you are working on Sql Server, you can use cte structure like below, set regarding data into cte and filter in your main query:
;with cte (ID) as ( --data from previous week only
Select Id from table
Where [Date] >= DATEADD(WEEK,-1,DATEADD(week,datediff(week,0,getdate()),0))
AND [Date] < DATEADD(week,datediff(week,0,getdate()),0)
)
select *
from table t
inner join cte on t.Id = cte.ID
where DATEPART(DW, [Date]) >= 0 --sunday
and DATEPART(DW, [Date]) <= 6 --saturday
In the filter, edit 0 and 6 to filter your data based on date as you wish.
If you use this, it returns previous Saturday and Sunday:
SELECT DATENAME(DW,(DATEADD(day, -6, getdate()))) ,DATENAME(DW,(DATEADD(day, -5,
getdate())))
[![Day Name][1]][1]
So, for example, you can use DATEADD(day, -6, getdate()) to get Saturday.
I have a problem that is I am unable to resolve as of now.
I need to get the data of
this day, this week and this month
I have a table reminder where I want to select reminders according to
following parameters.
1. Today
2. This Week
3. This Month
The column rdate having the date format in dd-mm-yyyy which is stored as nvarchar
For example
If I execute this weeks query I should get data starting from this week i.e.
If it is Friday I should get data from starting from Sunday to Saturday of that week
How can I get the data as mentioned above. I have searched a lot on internet but I didn't get the solution?
This is the query I have been trying
SELECT
*
FROM
reminder
WHERE
date > DATE_SUB(GETDATE(), INTERVAL 1 DAY)
ORDER BY
rdate DESC;
Where I'm converting nvarchar to date format.
If it's not possible to change the [date] column's data type to DATE, then you will incur a massive performance penalty when trying to filter by date.
Add computed column to table
We can add a computed column that will store the date in the correct format, and then index it for quick searchiing:
ALTER TABLE reminder
ADD Date_Value AS (CONVERT(DATE, '12-05-2016', 105)) PERSISTED;
-- This should yield superior performance
CREATE NONCLUSTERED INDEX IX_Date_Value ON reminder (Date_Value);
Table-valued function to calculate date range
Now, let's create an inline table-valued function to generate the date range for specific period types:
CREATE FUNCTION [dbo].[tvfn_Get_Date_Range](
#Period_Type VARCHAR(100)
)
RETURNS
TABLE
AS RETURN
(
WITH date_range AS(
SELECT CAST(GETDATE() AS DATE) d
-- This line works correctly if your week starts on Sunday
,CAST(DATEADD(WEEK, DATEDIFF(WEEK, '19050101', GETDATE()), '19050101') AS DATE) AS week_start
,CAST(DATEADD(DAY, - DAY(GETDATE()) + 1, GETDATE()) AS DATE) AS month_start
,CAST(DATEADD(MONTH, 1, DATEADD(DAY, - DAY(GETDATE()), GETDATE())) AS DATE) AS month_end
)
SELECT d AS From_Date
,d AS To_Date
FROM date_range
WHERE #Period_Type = 'DAY'
UNION ALL
SELECT week_start
,DATEADD(DAY, 7, week_start)
FROM date_range
WHERE #Period_Type = 'WEEK'
UNION ALL
SELECT month_start
,month_end
FROM date_range
WHERE #Period_Type = 'MONTH'
)
In the above function, week starts on Sunday. If you need this to be configurable, then take a look at the answer to SET DATEFIRST in FUNCTION.
Fast, simple querying now possible
You can now use the two together using a simple query:
SET #Range VARCHAR(100) = 'WEEK'
SELECT *
FROM reminder
CROSS APPLY [dbo].[tvfn_Get_Date_Range](#Range) dr
WHERE Date_Value BETWEEN dr.Date_From AND dr.Date_To
If you can't change the columns data type to Date (or DateTime), you must convert it to date in the query.
Here is one way to get the data for today, this week and this month:
Get records from today:
SELECT *
FROM reminder
WHERE CONVERT(Date, [date], 105) = CAST(GETDATE() as date)
ORDER BY rdate DESC;
Get records from this week:
SELECT *
FROM reminder
WHERE DATEPART(WEEK, CONVERT(Date, [date], 105)) = DATEPART(WEEK, GETDATE())
AND DATEPART(YEAR, CONVERT(Date, [date], 105)) = DATEPART(YEAR, GETDATE())
ORDER BY rdate DESC;
Get records from this Month:
SELECT *
FROM reminder
WHERE DATEPART(MONTH, CONVERT(Date, [date], 105)) = DATEPART(MONTH, GETDATE())
AND DATEPART(YEAR, CONVERT(Date, [date], 105)) = DATEPART(YEAR, GETDATE())
ORDER BY rdate DESC;
To my knowledge, SQL server internally deals with date format as MM/dd/yyyy.
Usually I prefer to save date as string in SQL table since it's easier for inserting and retrieving.
For example, suppose that the column rdate is defined as follows in your table reminder:
[rdate] nvarchar NULL
Then you can customize the select statement for a week as follows:
"Select R.* From reminder R Where CAST(R.rdate as datetime) between
'03/04/2011' AND '03/11/2011'"
And for 10 days as follows:
"Select R.* From reminder R Where CAST(R.rdate as datetime) between
'03/04/2011' AND '03/14/2011'"
And so on. If this is not what you want, please provide more details about your requirements.
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()))
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())