TSQL retrieve all records in current month/year - sql-server

I have a datetime field called DateFinished. I need to be able to retrieve all records in which DateFinished is within the current month/year.

If you've only got a small number of rows, this will do to get all rows where DateFinished is in this month of this year.
SELECT *
FROM MyTable
WHERE Year(DateFinished) = Year(CURRENT_TIMESTAMP)
AND Month(DateFinished) = Month(CURRENT_TIMESTAMP)
This could get quite slow over a large number of rows though - in which case using DateAdd, DatePart and BETWEEN is probably more appropriate, and can take advantage of indexes (I don't have time to write an answer involving those right now!)

Just as an alternative - this should use an index on DateFinished.
SELECT *
FROM MyTable
WHERE DateFinished BETWEEN
DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)
AND
DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) + 1, 0)

So the problem with #Bridge's method is use of index.
#Moose & #PCurd's method has a problems depending on how the data is stored.
#PCurd's method would work fine if all data collected on a day is rounded down to that day. E.g. event at 5pm is recorded as 2021-11-30 00:00:00. But if time is kept (which is assumed as it is a datetime field in Ops situation) then this data will be lost.
So you need to use the <> operators.
SELECT *
FROM MyTable
WHERE DateFinished >=
DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)
AND DateFinished <
DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) + 1, 0)
For the method using datefromparts: SQL select records with current month

Related

Using Parameters to generate date range

So I have multiple reports I am trying to merge into one report. The big issue is that one report is run every two weeks and the other is run once a month.
The date range for the report was created using this sql
SELECT
CASE
WHEN DAY(GETDATE()) <= 15 THEN
DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) - 1, 0) + 15
ELSE
DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) , 0)
END AS LO_DATE
So I tried adding a parameter that I could use that would basically say, hey if this is checked, then always run it for the whole month not the last two weeks. That sql looks like this.
IF (#RUN_FOR_MONTH = 'true')
SELECT
CASE
WHEN DAY(GETDATE()) <= 15 THEN
DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) - 1, 0) + 15
ELSE
DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) , 0)
END AS LO_DATE
ELSE
SELECT DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) , 0) AS LO_DATE
However I keep getting this error:
The report parameter ‘LO_DATE’ has a DefaultValue or a ValidValue that depends on the report parameter “RUN_FOR_MONTH”. Forward dependencies are not valid.
I am new to using SQL Server Report Builder, so if you need more information, please ask and I'll provide it.
REQUESTED CHANGE - I still get the same error
SELECT
CASE
WHEN #RUN_FOR_MONTH = 'true' THEN
DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) , 0)
WHEN DAY(GETDATE()) <= 15 THEN
DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) - 1, 0) + 15
ELSE
DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) , 0)
END AS LO_DATE
Parameters in SSRS are derived sequentially. If you have a parameter that is based off another's value, you must list those parameters in in the correct sequential order. Take the below
In this example, #DateFrom would be evaluated first, and then #DateTo; thus #DateFrom cannot depend on #DateTo (however the reverse is fine).
If, for example, the value of #DateFrom was DateAdd("d", -2, #DateTo) you would receive the error you have above. You would need to select #DateTo and click the Up Arrow icon (Or select #DateFrom and the down arrow)

(mssql) How can i add extra columns in extracted data

i have this code below (running on sql server 2017):
WITH selection AS (
SELECT servertimestamp
FROM eventlog
WHERE servertimestamp BETWEEN '5/29/2018' AND DATEADD(dd, +1, '6/29/2019')
AND (attributes LIKE '%N<=>PeopleIn%'))
(SELECT DATEADD(HOUR, DATEDIFF(HOUR, 0, servertimestamp) - (DATEDIFF(HOUR, 0, servertimestamp) % 2), 0) as timestamp , COUNT(servertimestamp) AS GONE_OUT
FROM selection
WHERE DATEPART(hh, servertimestamp) BETWEEN 8 AND 20
GROUP BY DATEADD(HOUR, DATEDIFF(HOUR, 0, servertimestamp) - (DATEDIFF(HOUR, 0, servertimestamp) % 2), 0))
ORDER BY timestamp
Also the screenshot below shows the result of the executed code:
What this code does is showing how many people came in a building each day. The data is grouped in a 2 hour basis.
What i want to do, is adding a column that shows how many people have gone out of the building for the same time slots that i'm already using.
Below i'm giving you an example of what i want to do:
Notice that on the 6th line i'm using the LIKE operator (attributes LIKE '%N<=>PeopleIn%'). This means that for the additional column, i'll have to make similar selections, but with the difference of using attributes LIKE '%N<=>PeopleOut%'.
Can i make it by using the UNION operator? Is there any other more obvious or easier way to do it?
Your help will be appreciated,
thank you.
You could do it by sort of labeling the servertimestamp field in your CTE based on the activity, then sum up the labels.
WITH selection
AS (
SELECT
servertimestamp
,CASE WHEN attributes LIKE '%N<=>PeopleIn%' THEN 1 ELSE 0 END AS PPL_IN
,CASE WHEN attributes LIKE '%N<=>PeopleOut%' THEN 1 ELSE 0 END AS PPL_OUT
FROM eventlog
WHERE
servertimestamp BETWEEN '5/29/2018' AND DATEADD(dd, + 1, '6/29/2019')
AND
(attributes LIKE '%N<=>PeopleIn%'
OR
attributes LIKE '%N<=>PeopleOut%')
)
(
SELECT
DATEADD(HOUR, DATEDIFF(HOUR, 0, servertimestamp) - (DATEDIFF(HOUR, 0, servertimestamp) % 2), 0) AS TIMESTAMP
,SUM(PPL_OUT) AS GONE_OUT
,SUM(PPL_IN) AS CAME_IN
FROM selection
WHERE DATEPART(hh, servertimestamp) BETWEEN 8
AND 20
GROUP BY DATEADD(HOUR, DATEDIFF(HOUR, 0, servertimestamp) - (DATEDIFF(HOUR, 0, servertimestamp) % 2), 0)
)
ORDER BY TIMESTAMP
UNION appends result sets in the order of execution.
UNION will not be my first choice in solving this problem.
What I see in you screenshot is that GONE_OUT and CAME_IN are grouped on a datetime which is unique and a category on which aggregated values are grouped.
You may have two (sub)queries, one for GONE_OUT and one for CAME_IN and then build a relation.
SELECT *
FROM GONE_OUT AS go
LEFT JOIN CAME_IN AS ci ON go.timestamp = ci.timestamp

What is the difference between date handling in my queries?

I need the number of records of last month. I used to use this approach so far:
select
count(ID)
from
table
where
col1 = 'somerule'
and
DateTimeOfInsert >= '20150901'
and
DateTimeOfInsert <= '20150930'
Now I'm about to atomate this task and therefore I have to pull the start and end dates of last month automatically. So here it is:
select
count(ID)
from
table
where
col1 = 'somerule'
and
DATEPART(m, DateTimeOfInsert) = DATEPART(m, DATEADD(m, -1, getdate()))
and
DATEPART(yyyy, DateTimeOfInsert) = DATEPART(yyyy, DATEADD(m, -1, getdate()))
My only issue is that at this very moment the first query returns 1073 and the second one 1124. So the question is obvious: what is the difference between them? Both should inlude the start and end date. I can't spot it.
This condition:
DateTimeOfInsert >= '20150901' and DateTimeOfInsert <= '20150930'
retrieves record that are between 2015-09-01 00:00:00.000 and 2015-09-30 00:00:00.000.
If DateTimeOfInsert is DATETIME, then this will return different result from your other condition.
The best way for this kind of queries is not to use BETWEEN but rather use
>= and <. In your case, you want to get records for the last month, so you want to use >= start of last month and < start of this month:
DateTimeOfInsert >= DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) - 1, 0) -- Beginning of previous month
AND DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0) -- Beginning of this month
The above condition also makes your query sargable.
For some common date routines, see this article.
The difference is in time component of datetime.
This:
DateTimeOfInsert >= '20150901' and DateTimeOfInsert <= '20150930'
will not select date like 20150930 15:30.
But this:
DATEPART(m, DateTimeOfInsert) = DATEPART(m, DATEADD(m, -1, getdate()))
will select it because you are checking for months and year part only. That`s why the second select returns more rows.
Both queries will return the same if you just change the first statement so that it will consider time component of last day of month:
DateTimeOfInsert >= '20150901' and DateTimeOfInsert < '20151001'

Query to get the first day of the month not working with DATEADD

I've been writing queries to truncate the time from a given datetime for years now, based on answers like this one and this one (and many other places), that groups a couple functions like
SELECT DATEADD(day, 0, DATEDIFF(day, 0, getdate()))
and it always gives the right answer.
I figured I could translate the same logic to finding the first of the current month by using month instead of day, but it's giving me a weird date for the result: 1903-10-17, instead of 2015-05-01.
My parameters have always been in the wrong order.
It turns out the format for DATEADD I've been using all these years is wrong, and it's only been working because it's using the day datepart. Casting an int to a date increments the day:
SELECT CAST(0 AS datetime) = '1900-01-01 00:00:00.000'
SELECT CAST(1 AS datetime) = '1900-01-02 00:00:00.000'
SELECT CAST(2 AS datetime) = '1900-01-03 00:00:00.000'
I should be using DATEADD(d, DATEDIFF(d, 0, getdate()), 0) - the parameters are (datepart, number, date), as laid out here at MSDN.
Writing it as SELECT DATEADD(month, DATEDIFF(month, 0, getdate()), 0) gives the expected result of 2015-05-01.

Select all rows from the previous date

I am trying to make a SQL query (to be converted into a SSRS report) that will grab everything opened in the previous day. This will have to be ran every day, automatically, so entering in the date manually will not be an option really.
Safest (in terms of changes to, or implicit conversion of, underlying data types) and most efficient (in terms of best chance at using an index to seek) is an open-ended range:
WHERE datetime_column >= DATEADD(DAY, DATEDIFF(DAY, 1, GETDATE()),0)
AND datetime_column < DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()),0);
For some details, see:
Bad habits to kick : mis-handling date / range queries
WHERE CAST(DATE_Column AS DATE) = CAST(DATEADD(DAY, - 1, GETDATE()) AS DATE)
select DATEADD(DD,-1,getDate()) as Yesterday
select * from <table> where date_in_question = DATEADD(DD,-1,getDate())
If you only need the date, do this
declare #yesterday as Date
set #yesterday = cast(DATEADD(DD,-1,getDate()) as Date)
select * from <table> where date_in_question = #yesterday

Resources