Expression to query whether date is within last month? - tsql

I'm struggling to think up the easiest way to get all rows/records that were create within the last month. I can build a sortof convoluted one below but is there a simplier way?
SELECT
*
FROM
MyTable
WHERE
MONTH( createdAt ) >= MONTH( GET_DATE() ) - 1
AND
YEAR( createdAt ) = YEAR( GET_DATE );
The above would work but not for December records. Any advice how to simplify this and handle December created records?

DECLARE #startOfMonth date = DATEFROMPARTS( YEAR( SYSUTCDATETIME() ), MONTH( SYSUTCDATETIME() ), 1 )
SELECT
*
FROM
myTable
WHERE
createdAt >= #startOfMonth
Or inline it (SQL Server should detect the RHS is constant so using a variable won't increase performance):
SELECT
*
FROM
myTable
WHERE
createdAt >= DATEFROMPARTS( YEAR( SYSUTCDATETIME() ), MONTH( SYSUTCDATETIME() ), 1 )

If you are looking for records WITHIN the last month I am assuming you mean the last 30 days this will work:
SELECT *
FROM myTable
where createdAt >= CAST(DATEADD(day,-30,GETDATE()) as date)
If you are actually looking for records that were in last month then this will work:
SELECT *
from myTable
WHERE createdAt >= CAST( DATEADD(month, DATEDIFF(month, -1, GETDATE()) - 2, 0) as date)

Related

Fetch records of current month using PostgreSQL query

Suppose I have following data in a table
id createdAt
1 2021-02-26T06:29:03.482Z
2 2021-02-27T06:29:03.482Z
3 2021-03-14T06:29:03.482Z
4 2021-03-17T06:29:03.482Z
I want data of current month. ie, if I generate report in march, I need to fetch results of march, so we need only current month data from table.
wanted output is
id createdAt
3 2021-03-14T06:29:03.482Z
4 2021-03-17T06:29:03.482Z
Anyone please help. Thank you.
You can use date_trunc():
select *
from the_table
where date_trunc('month', createdat) = date_trunc('month', current_timestamp);
date_trunc('month', ...) returns the first day of the month.
However, the above is not able to make use of an index on createdat. To improve performance, use a range query:
select *
from the_table
where createdat >= date_trunc('month', current_timestamp)
and createdat < date_trunc('month', current_timestamp) + interval '1 month'
The expression date_trunc('month', current_timestamp) + interval '1 month' returns the start of the next month (that's way this is compared with <)
You can compare the month and year of a date with the current one. But the index by field will not be used, you can build a separate index by year and month for this.
select *
from your_table
where extract(YEAR FROM createdAt) = extract(YEAR FROM now())
and extract(MONTH FROM createdAt) = extract(MONTH FROM now())

DATE ADD function in PostgreSQL

I currently have the following code in Microsoft SQL Server to get users that viewed on two days in a row.
WITH uservideoviewvideo (date, user_id) AS (
SELECT DISTINCT date, user_id
FROM clickstream_videos
WHERE event_name ='video_play'
and user_id IS NOT NULL
)
SELECT currentday.date AS date,
COUNT(currentday.user_id) AS users_view_videos,
COUNT(nextday.user_id) AS users_view_next_day
FROM userviewvideo currentday
LEFT JOIN userviewvideo nextday
ON currentday.user_id = nextday.user_id AND DATEADD(DAY, 1,
currentday.date) = nextday.date
GROUP BY currentday.date
I am trying to get the DATEADD function to work in PostgreSQL but I've been unable to figure out how to get this to work. Any suggestions?
I don't think PostgreSQL really has a DATEADD function. Instead, just do:
+ INTERVAL '1 day'
SQL Server:
Add 1 day to the current date November 21, 2012
SELECT DATEADD(day, 1, GETDATE()); # 2012-11-22 17:22:01.423
PostgreSQL:
Add 1 day to the current date November 21, 2012
SELECT CURRENT_DATE + INTERVAL '1 day'; # 2012-11-22 17:22:01
SELECT CURRENT_DATE + 1; # 2012-11-22 17:22:01
http://www.sqlines.com/postgresql/how-to/dateadd
EDIT:
It might be useful if you're using a dynamic length of time to create a string and then cast it as an interval like:
+ (col_days || ' days')::interval
You can use date + 1 to do the equivalent of dateadd(), but I do not think that your query does what you want to do.
You should use window functions, instead:
with plays as (
select distinct date, user_id
from clickstream_videos
where event_name = 'video_play'
and user_id is not null
), nextdaywatch as (
select date, user_id,
case
when lead(date) over (partition by user_id
order by date) = date + 1 then 1
else 0
end as user_view_next_day
from plays
)
select date,
count(*) as users_view_videos,
sum(user_view_next_day) as users_view_next_day
from nextdaywatch
group by date
order by date;

TSQL SELECT data within range of year and month

I'm trying to query data within a range of start year and month and end year and month. But SQL returnes onty the year and the month chosen. Can anyone identify the problem with my approach.
Thanks!
ALTER PROCEDURE xxx
(#JaarBegin AS int
, #JaarEind AS int
, #MaandBegin AS int
, #MaandEind AS int)
AS
BEGIN
WITH
CTE AS
(
SELECT [D_Medewerker_ID]
,[Gebruikersnaam]
,[Naam]
,[Afdelingscode]
,CONVERT(date, [Datum_uit_dienst]) AS DatumIn
,CONVERT(date, [Datum_in_dienst]) AS DatumUit
FROM [DM].[dm].[D_Medewerker] AS M
),
CTE2 AS(
SELECT F.[D_Functie_ID]
,[Generieke_Functie]
,[Specifieke_Functie]
,Fo.[D_Medewerker_ID]
FROM [DM].[dm].[D_Functie] AS F
JOIN dm.dm.F_FormatieBezetting AS Fo
ON F.D_Functie_ID = Fo.D_Functie_ID
)
SELECT DISTINCT CTE.[Gebruikersnaam]
, CTE.Naam
, CTE.Afdelingscode
, CTE.DatumIn
, CTE.DatumUit
, CTE2.Generieke_Functie
, CTE2.Specifieke_Functie
FROM CTE
JOIN CTE2
ON CTE.D_Medewerker_ID = CTE2.D_Medewerker_ID
WHERE DATEPART(year,CTE.DatumUit) BETWEEN #JaarBegin AND #JaarEind
AND DATEPART(MONTH, CTE.DatumUit) >= #MaandBegin AND DATEPART(MONTH, CTE.DatumUit) <= #MaandEind
ORDER BY CTE.DatumUit DESC;
END
You need to convert the int values you get to a date value.
In Sql server 2012 or later, you can use the built-in function DATEFROMPARTS to do this:
WHERE CTE.DatumUit >= DATEFROMPARTS ( #JaarBegin , #MaandBegin , 1 )
AND CTE.DatumUit < DATEADD(MONTH, 1, DATEFROMPARTS ( #JaarEind , #MaandBegin , 1 ))
If you are working with an earlier version of sql server, you need to build a string that represents the date (using iso format yyyy-mm-dd) and then cast it to date:
WHERE CTE.DatumUit >= CAST(RIGHT('0000' + CAST(#JaarBegin as varchar(4)), 4) + '-' + RIGHT('00' + CAST(#MaandBegin as varchar(2)), 2) +'-01' as datetime)
AND CTE.DatumUit < DATEADD(MONTH, 1, CAST(RIGHT('0000' +CAST(#JaarEind as varchar(4)), 4) + '-' + RIGHT('00' + CAST(#MaandBegin as varchar(2)), 2) +'-01' as datetime))

T-SQL Date Function

I have a T-SQL script that runs every weekday. The script does a lookup for new customers in the past 24 hours, with the exceptionof Monday it will do a lookup in the past 72 hours (Friday through Sunday)
Select FirstName, LastName, CustomerID, Date
FROM Customers
WHERE
(
(
DATEPART(WEEKDAY, GetDate())=2 AND
DATEDIFF(DAY, Customers.Date, GetDate()) <= 3 AND
DATEDIFF(DAY, Customers.Date, GetDate()) >= 1
)
OR DATEDIFF(DAY, Customers.Date, GetDate()) = 1
)
I need to change this to do a lookup 30 days prior instead.
ANy ideas? Thanks.
WHERE DATEDIFF(DAY, Customers.Date, GetDate()) <= 30

How do you get positive and negative rows based on date

I'm trying to get ordinance by the current date from a table. this query does what I want but it seems overkill:
WITH dates
AS (SELECT Month,
FQ,
FY,
MonthDisplay,
CAST (datepart(yyyy, [Month]) AS VARCHAR) + '-' + RIGHT(CAST ((datepart(MM, [Month]) + 100) AS VARCHAR), 2) AS YM,
fh,
LEFT(CONVERT (VARCHAR, [Month], 100), 3) + ' ' + RIGHT(fy, 4) AS MY,
LEFT(CONVERT (VARCHAR, [Month], 100), 3) AS ShortMonthName
FROM Pipeline.DimTime AS dt),
datesafter
AS (SELECT dt.FH,
dt.FQ,
dt.FY,
dt.MY,
dt.Month,
dt.MonthDisplay,
dt.ShortMonthName,
dt.YM,
ROW_NUMBER() OVER ( ORDER BY [Month]) AS RowNum
FROM dates AS dt
WHERE dt.[Month] >= (SELECT TOP 1 DATEADD(MONTH, DATEDIFF(MONTH, 0, ds.SnapshotDate), 0)
FROM dbo.vw_DimSnapshot AS ds
WHERE ds.SnapshotWeek = 'Current')),
datesbefore
AS (SELECT dt.FH,
dt.FQ,
dt.FY,
dt.MY,
dt.Month,
dt.MonthDisplay,
dt.ShortMonthName,
dt.YM,
(ROW_NUMBER() OVER ( ORDER BY [Month] DESC)) * -1 AS RowNum
FROM dates AS dt
WHERE dt.[Month] < (SELECT TOP 1 DATEADD(MONTH, DATEDIFF(MONTH, 0, ds.SnapshotDate), 0)
FROM dbo.vw_DimSnapshot AS ds
WHERE ds.SnapshotWeek = 'Current'))
SELECT *
FROM datesafter
UNION ALL
SELECT *
FROM datesbefore
ORDER BY [month];
I think you can do it in a single query by using datediff. Pass current date as one parameter and the table date as another. This will work if you are ok with skipping missing dates. For example if current date is Nov 21, then Nov 20 will show up as -1 and Nov 18 will show up as -3 even if Nov 19 is missing in the data. I am not sure what your business requirement is, so cannot comment beyond that.
And by the way if you are looking for ordinance based on months instead of day, you can use still use datediff but use the correct datepart (See: http://msdn.microsoft.com/en-us/library/ms189794.aspx).
HTH.
-Tabrez