Date range based on Column Date - sql-server

I am using the latest SQL Server. I have a table with a CreatedDate column. I need to write a Query that uses dates that are plus or minus 7 from the Date in CreatedDate. I have no clue how to go about this. My thought was this:
DECLARE #Date datetime
DECLARE #SevenBefore datetime
DECLARE #SevenAfter datetime
SET #Date = CreatedDate
SET #SevenBefore = DATEADD(day,-7,#Date)
SET #SevenAfter = DATEADD(day,7,#Date)
SELECT *
FROM <table>
WHERE <table> BETWEEN #SevenBefore AND #SevenAfter
The issue with this is that I cannot use "CreatedDate" as a SET #DATE because SQL gives an error "Invalid column name 'CreatedDate'"
Any help would be appreciated. I cannot list a date because every date in that column could be different.
Thanks

In this case, you need to stop thinking as a programmer would, and start thinking as a Database programmer would.
Lets work only with this central part of your query:
SELECT *
FROM <table>
WHERE <table> BETWEEN #SevenBefore AND #SevenAfter
Now, you say that the CreatedDate is a column in a table. For this example, I will assume that the CreatedDate is in a table other than the one in your example above. For this purpose, I will give two fake names to the tables. The table with the CreatedDate, I will call tblCreated, and the one from the query above I will call tblData.
Looking above, it's pretty obvious that you can't compare an entire table row to a date. There must be a field in that table that contains a date/time value. I will call this column TargetDate.
Given these assumptions, your query would look something like:
SELECT *
FROM tblCreated tc
INNER JOIN tblData td
ON td.TargetDate BETWEEN DATEADD(day, -7, tc.CreatedDate) and DATEADD(day, 7, tc.CreatedDate)
Looking at this, it is clear that you still need some other associations between the tables. Do you only want all data rows per customer based on the Created date, or perhaps only want Creations where some work was done on them as shown in the Data records, or ??. Without a fuller specification, we can't help with that, though.

Related

i can not understand why a query filtering on datetime field is not working on sql server 2016

This is a very basic query:
select * from [dbo].[TestTable] where year(start_date)>2021
it returns no records, start_date is datetime, the table contains many records with that field valorized and dates beyound 2021.
this query return all the records of the table:
SELECT year(start_date), * FROM [dbo].[TestTable] order by start_date desc
this the table structure:
another query with strange result:
SELECT year(start_date), case when year(start_date)>2021 then 1 else 0 end, * FROM [ADS].[dbo].[TestTable] order by start_date desc
what can i check?
You are missing the = part of the operator. All the rows seem to have 2021-01-01, so the YEAR is not greater than 2021, it IS 2021.
You'd need to either do
select * from [dbo].[TestTable] where year(start_date)>=2021
or
select * from [dbo].[TestTable] where year(start_date)=2021
As Dan Guzman points out, as an additional improvement, you should avoid using functions on your WHERE clauses because that will prevent the use of indexes, since it requires to execute the function against every single row on the table to be able to determine if it's a match.
If it's a small table in terms of record count, it's not a big deal, but if you're talking about tens of thousands or more, it will add up.
The alternatives would be to either filter by the original date value, or save the year as a separate field and add an index to it.
It's working fine. None of the results in the picture contains record where year(start_date)>2021.
So I think you might looking for the rows where start date is greater than 2020
select * from [dbo].[TestTable] where year(start_date)>2020
OR
select * from [dbo].[TestTable] where year(start_date)>=2021
Or as #Dan Guzman suggested it would be better to use:
select * from [dbo].[TestTable] where start_date>='2021-01-01'
Nothing in that table has a year > 2021. There dates greater then the start of the year, but when looking at just the years, they are equal to 2021, not greater.
To fix this, I'd remove the year() function completely. Calling a function on a column can be bad for performance, because it impacts the ability to use indexes on the column. This one is probably not awful (year() is deterministic, and so sometimes the index is still okay), but if there is a way to express a query without the function it's usually a good idea. In this case, we can do it like this:
select * from [dbo].[TestTable] where start_date >= '20210101'

Creating SQL views in VBA

I am trying to create a view on a table called petients in my database. The table has five columns. One of them is the column which I want to keep patient admitted date. It data type is datetime so I want to create a query that filters the data in this table based on current date. For example I want create a view that shows only details of petients who have been recorded on the current day.
Here is my code:
CREATE VIEW [dbo].[recent petients]
AS
SELECT petient_id, name, age, contact
FROM [petients]
WHERE [date] = 'date.Today'
I am getting an error saying that failed to convert date to string. Can you help me to solve it, or where is my code wrong?
Your code looks like SQL Server code. If so, I would recommend:
SELECT petient_id, name, age, contact
FROM [patients]
WHERE [date] = CONVERT(date, GETDATE());
As a note: This version is much better than DATEDIFF() because it allows the use of an index on patient([date]).
If the "date" column has a time component, you can use:
WHERE CONVERT(date, [date]) = CONVERT(date, GETDATE())
Note that this is also index-safe in SQL Server.
I'm assuming you are using Transact-SQL from Microsoft SQL Server, but you should specify the sql dialect you are using.
Since the datetime field type generally includes also a time, it is better to use the DATEDIFF function: https://learn.microsoft.com/it-it/sql/t-sql/functions/datediff-transact-sql?view=sql-server-ver15
In your case, to consider only the record where date=today, the difference in days must be zero:
--SQL QUERY
WHERE DATEDIFF(day, GETDATE(), [date]) = 0
day identifies the element you want to consider the difference. A list of names or abbreviations can be found in the link
GETDATE() returns now datetime
2nd and 3rd arguments are the dates you want to make the difference between

T-SQL Select where Subselect or Default

I have a SELECT that retrieves ROWS comparing a DATETIME field to the highest available value of another TABLE.
The Two Tables have the following structure
DeletedRecords
- Id (Guid)
- RecordId (Guid)
- TableName (varchar)
- DeletionDate (datetime)
And Another table which keep track of synchronizations using the following structure
SynchronizationLog
- Id (Guid)
- SynchronizationDate (datetime)
In order to get all the RECORDS that have been deleted since the last synchronization, I run the following SELECT:
SELECT
[Id],[RecordId],[TableName],[DeletionDate]
FROM
[DeletedRecords]
WHERE
[TableName] = '[dbo].[Person]'
AND [DeletionDate] >
(SELECT TOP 1 [SynchronizationDate]
FROM [dbo].[SynchronizationLog]
ORDER BY [SynchronizationDate] DESC)
The problem occurs if I do not have synchronizations available yet, the T-SQL SELECT does not return any row while it should returns all the rows cause there are no synchronization records available.
Is there a T-SQL function like COALESCE that I can use with DateTime?
Your subquery should look like something like this:
SELECT COALESCE(MAX([SynchronizationDate]), '0001-01-01')
FROM [dbo].[SynchronizationLog]
It says: Get the last date, but if there is no record (or all values are NULL), then use the '0001-01-01' date as start date.
NOTE '0001-01-01' is for DATETIME2, if you are using the old DATETIME data type, it should be '1753-01-01'.
Also please note (from https://msdn.microsoft.com/en-us/library/ms187819(v=sql.100).aspx)
Use the time, date, datetime2 and datetimeoffset data types for new work. These types align with the SQL Standard. They are more portable. time, datetime2 and datetimeoffset provide more seconds precision. datetimeoffset provides time zone support for globally deployed applications.
EDIT
An alternative solution is to use NOT EXISTS (you have to test it if its performance is better or not):
SELECT
[Id],[RecordId],[TableName],[DeletionDate]
FROM
[DeletedRecords] DR
WHERE
[TableName] = '[dbo].[Person]'
AND NOT EXISTS (
SELECT 1
FROM [dbo].[SynchronizationLog] SL
WHERE DR.[DeletionDate] <= SL.[SynchronizationDate]
)

Proper way to index date & time columns

I have a table with the following structure:
CREATE TABLE MyTable (
ID int identity,
Whatever varchar(100),
MyTime time(2) NOT NULL,
MyDate date NOT NULL,
MyDateTime AS (DATEADD(DAY, DATEDIFF(DAY, '19000101', [MyDate]),
CAST([MyDate] AS DATETIME2(2))))
)
The computed column adds date and time into a single datetime2 field.
Most queries against the table have one or more of the following clauses:
... WHERE MyDate < #filter1 and MyDate > #filter2
... ORDER BY MyDate, MyTime
... ORDER BY MyDateTime
In a nutshell, date is usually used for filtering, and full datetime is used for sorting.
Now for questions:
What is the best way to set indices on those 3 date-time columns? 2 separate on date and time or maybe 1 on date and 1 on composite datetime, or something else? Quite a lot of inserts and updates occur on this table, and I'd like to avoid over-indexing.
As I wrote this question, I noticed the long and kind of ugly computed column definition. I picked it up from somewhere a while ago and forgot to investigate if there's a simpler way of doing it. Is there any easier way of combining a date and time2 into a datetime2? Simple addition does not work, and I'm not sure if I should avoid casting to varchar, combining and casting back.
Unfortunately, you didn't mention what version of SQL Server you're using ....
But if you're on SQL Server 2008 or newer, you should turn this around:
your table should have
MyDateTime DATETIME
and then define the "only date" column as
MyDate AS CAST(MyDateTime AS DATE) PERSISTED
Since you make it persisted, it's stored along side the table data (and now calculated every time you query it), and you can easily index it now.
Same applies to the MyTime column.
Having date and time in two separate columns may seem peculiar but if you have queries that use only the date (and/or especially only the time part), I think it's a valid decision. You can create an index on date only or on time or on (date, whatever), etc.
What I don't understand is why you also have the computed datetime column as well. There s no reason to store this value, too. It can easily be calculated when needed.
And if you need to order by datetime, you can use ORDER BY MyDate, MyTime. With an index on (MyDate, MyTime) this should be ok. Range datetime queries would also be using that index.
The answer isn't in your indexing, it's in your querying.
A single DateTime field should be used, or even SmallDateTime if that provides the range of dates and time resolution required by your application.
Index that column, then use queries like this:
SELECT * FROM MyTable WHERE
MyDate >= #startfilterdate
AND MyDate < DATEADD(d, 1, #endfilterdate);
By using < on the end filter, it only includes results from sometime before midnight of that date, which is the day after the user-selected "end date". This is simpler and more accurate than adding 23:59:59, especially since stored times can include microseconds between 23:59:59 and 00:00:00.
Using persisted columns and indexes on them is a waste of server resources.

Return a Table of Payroll Dates from a SQL Stored Procedure

I'm working with SQL Server Reporting Services 2008, which is somewhat new to me, as most of my experience is with LAMP development. In addition, moving most of the logic to SQL as stored procedures is something I'm not very familiar with, but would like to do. Any help or direction would be greatly appreciated.
I need a list of acceptable payroll dates in the form of a table to use as the allowed values for a report parameter. Ideally, the person will be able to select this payroll date from the drop-down provided by the report parameter, which will then be used in the dataset to pull data from a table. I would like the logic to be stored on the SQL server if possible, as this is something that will most likely be used on a few other reports.
The logic to create the list of dates is rather simple. It starts with the oldest payroll date that is need by the system (sometime in 2007) and simply goes every two weeks from there. The procedure or function should return a table that contains all these dates up to and including the nearest upcoming payroll date.
It seems to me that the way to go about this would be a procedure or function that creates a temporary table, adds to it the list of dates, and then returns this table so that the report parameter can read it. Is this an acceptable way to go about it?
Any ideas, examples, or thoughts would be greatly appreciated.
I would use a CTE something like this one:
;WITH PayPeriod AS (
SELECT #DateIn2007 AS p UNION ALL
SELECT DATEADD(dd, 14, p) as P FROM PayPeriod WHERE p < GetDate() )
SELECT p FROM PayPeriod
OPTION ( MAXRECURSION 500 )
The MAXRECURSION and/or where parameter limits the number of dates it will generate.
You can use a parameter to figure out the correct limit to get the correct last date still, of course.
try something like this:
;with AllDates AS
(
SELECT CONVERT(datetime,'1/1/2007') AS DateOf
UNION ALL
SELECT DateOf+14
FROM AllDates
WHERE DateOf<GETDATE()+14
)
SELECT * FROM AllDates
OPTION (MAXRECURSION 500)
you can put this in a view or function.
However, I would suggest that instead of presenting a select box of this many values, why not just have two text box fields: start date and end date and default them to reasonable values, just my 2 cents

Resources