How can I construct native date data type values in SQL (T-SQL)?
I've added some examples, but please provide your own. My examples assume that the month and year are being stored (or are readily available) as integer values, but maybe your example will assume that the day and the month (or whatever) are stored as text. I can't see the future; surprise me.
SELECT DATEFROMPARTS(#Year, #Month, #Day)
(From SQL Server 2012)
Why, with input data as strings one of the most obvious (and therefore hardly surprising, sorry) solutions would be:
SELECT
mydate = CAST([year] + RIGHT('0' + [month], 2) + '01' AS datetime)
/* or 'AS date' in SQL Server 2008+ */
FROM (
SELECT [month] = '2', [year] = '2011' UNION ALL
SELECT [month] = '03', [year] = '2011' UNION ALL
SELECT [month] = '5', [year] = '2011' UNION ALL
SELECT [month] = '12', [year] = '2011' UNION ALL
SELECT [month] = '8', [year] = '2084' UNION ALL
SELECT [month] = '1', [year] = '1940'
) x;
The following code shows how to create date values from year and month (integer) values:
SELECT DATEADD(
month,
DATEDIFF( month, 0, GETDATE() )
+ x.[month]
- MONTH( GETDATE() ),
DATEADD(
year,
DATEDIFF( year, 0, GETDATE() )
+ x.[year]
- YEAR( GETDATE() ),
0 ) )
FROM ( SELECT [month] = 2, [year] = 2011
UNION ALL
SELECT [month] = 3, [year] = 2011
) x;
Date values from year, month, AND day (integer) values, though maybe the inputs should be sanitized first:
SELECT DATEADD(
day,
x.[day] - DAY(0),
DATEADD(
month,
x.[month] - MONTH(0),
DATEADD(
year,
x.[year] - YEAR(0),
0 ) ) )
FROM ( SELECT [month] = 2, [year] = 2011, [day] = 14
UNION ALL
SELECT [month] = 3, [year] = 2011, [day] = 2
UNION ALL
SELECT [month] = 5, [year] = 2011, [day] = 1
UNION ALL
SELECT [month] = 7, [year] = 2011, [day] = 0
UNION ALL
SELECT [month] = 8, [year] = 2084, [day] = 40
UNION ALL
SELECT [month] = 1, [year] = 1940, [day] = -6
) x;
More example code to create date values from year and month (integer) values, but even simpler than some other example code:
SELECT DATEADD(
month,
x.[month] - MONTH(0),
DATEADD(
year,
x.[year] - YEAR(0),
0 ) )
FROM ( SELECT [month] = 2, [year] = 2011
UNION ALL
SELECT [month] = 3, [year] = 2011
UNION ALL
SELECT [month] = 5, [year] = 2011
UNION ALL
SELECT [month] = 7, [year] = 2011
UNION ALL
SELECT [month] = 8, [year] = 2084
UNION ALL
SELECT [month] = 1, [year] = 1940
) x;
Related
I have a month number and year: month 2 and year 2022.
How can I get the first day of that month like 2022-02-01 and last day of month 2022-02-28?
I have seen many posts on getting first and last date of month based on given date or the current date, but I need it based on given month and year.
Thanks in advance
Here is my stored procedure:
ALTER PROCEDURE [dbo].[Rpt_ItemsSales_DayMonthYear_year]-- 2022
#year int = NULL
AS
;WITH months(MonthNumber) AS
(
SELECT 1
UNION ALL
SELECT MonthNumber + 1
FROM months
WHERE MonthNumber < 12
)
SELECT
SalesPos_Dtls.ItemName,
SUM(SalesPos_Dtls.Qty) AS SumQty,
SUM(SalesPos_Dtls.TotalPrice) AS SumTotal,
SalesPos_Dtls.ItemCode,
DATENAME(month, DATEADD(month, m.MonthNumber, 0) - 1) AS MonthName,
m.MonthNumber
FROM
months AS m
LEFT JOIN
SalesPos ON MONTH(SalesPos.StartDate) = m.MonthNumber
AND (status = 'IsPosted')
AND (#year = YEAR(salespos.startdate) OR #year IS NULL)
LEFT JOIN
[dbo].SalesPos_Dtls ON SalesPos.ID = SalesPos_Dtls.OrderId
GROUP BY
m.MonthNumber, dbo.SalesPos_Dtls.ItemName, dbo.SalesPos_Dtls.ItemCode
And this is as far as I got
ALTER PROCEDURE [dbo].[Rpt_ItemsSales_DayMonthYear_year] --2022,1
#year int = NULL,
#month int = NULL
AS
DECLARE #yearr int = #year
DECLARE #monthh int = #month
;WITH months(MonthNumber) AS
(
SELECT 1
UNION ALL
SELECT MonthNumber + 1
FROM months
WHERE MonthNumber < 12
)
SELECT
SalesPos_Dtls.ItemName,
SUM(SalesPos_Dtls.Qty) AS SumQty,
SUM(SalesPos_Dtls.TotalPrice) AS SumTotal,
SalesPos_Dtls.ItemCode,
DATENAME(month, DATEADD(month, m.MonthNumber, 0) - 1) AS MonthName,
m.MonthNumber,
DATEFROMPARTS (#yearr, #monthh, 1) AS MonthStart,
EOMONTH (DATEFROMPARTS (#yearr, #monthh, 1)) AS MonthEnd
FROM
months AS m
LEFT JOIN
SalesPos ON MONTH(SalesPos.StartDate) = m.MonthNumber
AND (status = 'IsPosted')
AND (#year = YEAR(salespos.startdate) OR #year IS NULL)
LEFT JOIN
[dbo].SalesPos_Dtls ON SalesPos.ID = SalesPos_Dtls.OrderId
WHERE
(MONTH(SalesPos.StartDate) = #month OR #month IS NULL)
GROUP BY
m.MonthNumber, dbo.SalesPos_Dtls.ItemName, dbo.SalesPos_Dtls.ItemCode
Screenshot with the sample data:
But I want my data this way :
هوت دوج لارج 3.0000 75.0000
76 January 1 2022-1-01 2022-1-31
هوت دوج ميديم 1.0000 20.0000 77 January 1 2022-1-01 2022-1-31
NULL NULL NULL NULL February 2 2022-2-01 2022-2-28
NULL NULL NULL NULL March 3 NULL 2022-3-01 2022-3-31
SET DATEFIRST 1
DECLARE #Month smallint= 3, #Year smallint = 2022;
/*First and Last day of month as DATE */
select DATEFROMPARTS(#Year, #MONTH, 1)FirstDayOfMonth , EOMONTH(DATEFROMPARTS(#Year, #MONTH, 1)) LastDayofMonth
/*First and Last Weekday of Month */
select DATEPART( dw, DATEFROMPARTS(#Year, #MONTH, 1) ) FirstWeekDayOfMonth , DATEPART(dw, (EOMONTH(DATEFROMPARTS(#Year, #MONTH, 1)))) LastWeekDayofMonth
i dont know if this is the right way to update the question but here is the solution that worked for me.
SELECT DATEADD(month, DATEDIFF(month, 0, #mydate), 0) AS StartOfMonth
SELECT EOMONTH(#mydate) as LastOFMonth
And thanks
edit:
this is the stored procedure. all i wanted is to have 2 columns infront of each item that have the firstday of the month and the last day witch this item was purchased.
i hope this and the stored procedure explain what i mean.
ALTER proc [dbo].[Rpt_ItemsSales_DayMonthYear_year]--Rpt_ItemsSales_DayMonthYear_year 2022
#year int=null
as
;WITH months(MonthNumber) AS
(
SELECT 1
UNION ALL
SELECT MonthNumber+1
FROM months
WHERE MonthNumber < 12
)
select SalesPos_Dtls.ItemName,sum(SalesPos_Dtls.Qty) as SumQty,sum(SalesPos_Dtls.TotalPrice) as SumTotal,SalesPos_Dtls.ItemCode,DateName( month , DateAdd( month , m.MonthNumber , 0 ) - 1 ) as MonthName,
m.MonthNumber, cast(DATEADD(month, DATEDIFF(month, 0, SalesPos.StartDate), 0) as date) AS StartOfMonth,EOMONTH(SalesPos.StartDate) as LastOFMonth
from months as m
left join SalesPos on month(SalesPos.StartDate) = m.MonthNumber and (status = 'IsPosted') and (#year = year(salespos.startdate) or #year is null)
left JOIN [dbo].SalesPos_Dtls on SalesPos.ID=SalesPos_Dtls.OrderId
group by m.MonthNumber,dbo.SalesPos_Dtls.ItemName,dbo.SalesPos_Dtls.ItemCode,cast(DATEADD(month, DATEDIFF(month, 0, SalesPos.StartDate), 0) as date),EOMONTH(SalesPos.StartDate)
I have a table where 2 columns are called Month and Year and are both INT. I need to return all the records that are less than the date provided.
So if I pass the following parameters #Month = 8 and #Year = 2017, I would like to return all records before August 2017. What is the best way to achieve this?
SELECT * FROM testTable
WHERE year <= #Year AND
month < #Month
is my current SQL. This won't work if I need to display the record that is November 2014
Compare them as dates. Like this:
SELECT * FROM testTable
WHERE DATEFROMPARTS(year, month, 1) <= DATEFROMPARTS(#Year, #Month, 1)
Pass The Parameter as Date. Like
DECLARE #MyDate DATE = '08-01-2014'
Now you can go for either of the below
SELECT
*
FROM YourTable
WHERE CAST(ConCAT([Monnth],'-01-',[Year]) AS DATE) = #MyDate
Or
SELECT
*
FROM YourTable
WHERE [Year] = YEAR(#MyDate)
AND [Month] = MONTH(#MyDate)
You can use DATEPART function of SQL Server
SELECT * FROM testTable
WHERE YEAR<= DATEPART(yy,yourdate) AND
MONTH < DATEPART(mm,yourdate)
It would be better to convert data types and query further.
DECLARE #testtable TABLE (id INT identity(1, 1), name VARCHAR(100), year INT, month INT)
INSERT INTO #testtable (name, year, month)
SELECT 'me', '2014', 10
UNION
SELECT 'you', '2017', 08
UNION
SELECT 'us', '2015', 10
UNION
SELECT 'Him', '2017', 10
UNION
SELECT 'Her', '2018', 1
SELECT *
FROM #testtable
WHERE CONCAT (year, '-', right('00' + cast(Month AS VARCHAR(2)), 2), '-', '01')
< = '2017-08-01'
I am trying to get the remaining number of working units for each month, of a sum between a bought number of working unit, and a consumed number of working unit.
I tried two possibilities, but both have flaws :
In the first test, I created a "Months" table that contains every month and every year, in order to show all months in the final matrix I wish to create with these data. With this one, I get the closing whenever there is a consumed working unit, but when there is not, the column is "empty", because it does not get the last closing.
USE OTRS_Revised
SELECT [Customer], CASE WHEN [Year] < 2016 THEN 1 ELSE [Year] END AS [Year], CASE WHEN [Year] < 2016 THEN 0 ELSE [Month] END AS [Month], [Closing] AS Total, SUM([Closing])
OVER (PARTITION BY [Customer] ORDER BY [Year], [Month] ROWS UNBOUNDED PRECEDING) AS Closing
FROM [dbo].[WU_Closing_View]
WHERE [Customer] IN ('CustomerList')
GROUP BY [Customer], [Year], [Month], [Closing]
UNION ALL
SELECT '' AS Customer, CASE WHEN [Year] < 2016 THEN 1 ELSE [Year] END AS [Year], CASE WHEN [Year] < 2016 THEN 0 ELSE [Month] END AS [Month], '' AS Total, '' AS Sum_bought
FROM [dbo].Months
WHERE [Year] <= 2016
GROUP BY Year, Month
ORDER BY Customer, Year, Month
I also tried to do it "month by month", with the below query. It works for one month, but I can't find any way to use this to get the results for each month of the year 2016.
SELECT
(SELECT SUM(Closing) AS Expr1
FROM OTRS_Revised.dbo.WU_Bought_View
WHERE (Customer LIKE 'SomeCustomer') AND (DATEADD(Year, Year - 1900, DATEADD(Month, Month - 1, DATEADD(day, 0, 0))) <= DATEADD(Year, 2016 - 1900, DATEADD(Month, 5 - 1, DATEADD(day, 0, 0))))
GROUP BY Customer)
+
(SELECT SUM(Closing) AS Expr1
FROM OTRS_Revised.dbo.WU_Consumed_View
WHERE (Customer LIKE 'SomeCustomer') AND (DATEADD(Year, Year - 1900, DATEADD(Month, Month - 1, DATEADD(day, 0, 0))) <= DATEADD(Year, 2016 - 1900, DATEADD(Month, 5 - 1, DATEADD(day, 0, 0))))
GROUP BY Customer) AS Expr1,
[Month]
FROM OTRS_Revised.dbo.Months
GROUP BY [Month]
SELECT b.*
FROM
( SELECT CASE WHEN [Year] < 2016 THEN 1 ELSE [Year] END AS [Year], CASE WHEN [Year] < 2016 THEN 0 ELSE [Month] END AS [Month]
FROM [dbo].Months
WHERE [Year] <= 2016
GROUP BY Year, Month
ORDER BY Customer, Year, Month ) AS a
LEFT OUTER JOIN
(SELECT [Customer], CASE WHEN [Year] < 2016 THEN 1 ELSE [Year] END AS [Year], CASE WHEN [Year] < 2016 THEN 0 ELSE [Month] END AS [Month], [Closing] AS Total, SUM([Closing])
OVER (PARTITION BY [Customer] ORDER BY [Year], [Month] ROWS UNBOUNDED PRECEDING) AS Closing
FROM [dbo].[WU_Closing_View]
WHERE [Customer] IN ('CustomerList')
GROUP BY [Customer], [Year], [Month], [Closing]) AS b
ON a.Month = b.Month )
In your approach when you do union the rows that don't have matching months is getting removed. Since you want the months that does not have closing match as well, you need to use the left outer join
Something like this perhaps
DECLARE #T TABLE (ID INT, ProductID INT, TrDate DATE,InOut VARCHAR(10),Amount INT)
INSERT INTO #T VALUES
(1 ,1, '2016-01-01', 'I', 100),
(2 ,2, '2016-01-01', 'I', 100),
(3 ,3, '2016-02-01', 'I', 100),
(4 ,4, '2016-03-01', 'I', 100),
(5 ,1, '2016-03-01', 'I', 100),
(6 ,2, '2016-04-01', 'O', 10),
(7 ,3, '2016-05-01', 'I', 100),
(8 ,5, '2016-05-01', 'I', 100),
(9 ,5, '2016-05-01', 'O', 100),
(10 ,6, '2016-05-01', 'I', 100)
declare #m table (id int, menddate date)
insert #m values
(1,'2015-12-31'),(2,'2016-01-31'),(3,'2016-02-29'),(4,'2016-03-31'),
(5,'2016-04-30'),(6,'2016-05-31'),(7,'2016-06-30'),(4,'2016-07-31')
Select *
from
(
select -- t.*
x.xproductid , x.xyyyymm,
SUM(t.total) OVER (partition by x.xproductid
ORDER BY x.xyyyymm
ROWS UNBOUNDED PRECEDING) AS CumulativeTotal
from
(
SELECT t.ProductID tproductid, year(t.trdate) * 100 + month(t.trdate) tyyyymm,
sum(case when t.Inout = 'I' then t.Amount else t.amount * -1 end) as total
FROM #T t
group by ProductID, year(t.trdate) * 100 + month(t.trdate)
) t
right outer join
(select distinct productid as xproductid,year(m.menddate) * 100 + month(m.menddate) xyyyymm from #t t, #m m) x on x.xproductid = t.tproductid and x.xyyyymm = t.tyyyymm
) z
where z.xyyyymm >= 201601
order by z.xProductID,z.xyyyymm
Note the use of a right outer join to get all the month ends for all products
I'm in the process of writing a stored procedure (for SQL Server 2012) that is supposed to calculate the number of hours for our employee from 16-15th of every month.
I have the following database structure
I have written a stored procedure to calculate the hours but I think I can only get the week start date to filter my condition. The stored procedure is returning me the wrong result because the weekly start date is not always the 16th.
CREATE PROCEDURE [dbo].[spGetTotalHoursBetween16to15EveryMonth]
AS
BEGIN
SET NOCOUNT ON
BEGIN TRY
DECLARE #SixteenthDate datetime2(7) = DATEADD(DAY, 15, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0))
DECLARE #currentDate datetime2(7) = getDate()
DECLARE #LastSixteenthDate datetime2(7) = DATEADD(DAY, 15, DATEADD(MONTH, DATEDIFF(MONTH, 0, DATEADD(mm, DATEDIFF(mm, 0, GETDATE()) - 1, 0)), 0))
IF(#currentDate >= #SixteenthDate)
BEGIN
SELECT
(Sum(Day1Hours) + sum(Day2Hours) + Sum(Day3Hours) +
sum(Day4Hours) + Sum(Day5Hours) + sum(Day6Hours) + Sum(Day7Hours)) AS Total
FROM
dbo.TimeSheets
WHERE
WeekStartDate BETWEEN DATEADD(wk, DATEDIFF(wk, 0, #SixteenthDate), -1) AND #currentDate
END
ELSE
BEGIN
SELECT
(Sum(Day1Hours) + sum(Day2Hours) + Sum(Day3Hours) +
sum(Day4Hours) + Sum(Day5Hours) + sum(Day6Hours) + Sum(Day7Hours)) AS Total
FROM
dbo.TimeSheets
WHERE
WeekStartDate BETWEEN DATEADD(wk, DATEDIFF(wk, 0, #LastSixteenthDate), -1) AND #currentDate
END
END TRY
BEGIN CATCH
THROW
END CATCH
END
I'd probably just do it the simple way:
declare #today date = convert(date,current_timestamp)
declare #prev_month_end date = dateadd( day , -day(#today) , #today )
declare #period_start date = dateadd( day , 16 , #prev_month_end ) -- 16th of THIS month
declare #period_end date = dateadd( month , 1 , #period_start ) -- 16th of NEXT month
select #period_start = dateadd(month, -1 , #period_start ) ,
#period_end = dateadd(month, -1 , #period_end )
where day(#today) < 16
select total_hours = coalesce(sum(t.hours),0)
from ( select id = t.id , report_date = dateadd(day,0,t.WeekStartDate) , hours = t.Day1Hours from dbo.TimeSheets t
union all select id = t.id , report_date = dateadd(day,1,t.WeekStartDate) , hours = t.Day2Hours from dbo.TimeSheets t
union all select id = t.id , report_date = dateadd(day,2,t.WeekStartDate) , hours = t.Day3Hours from dbo.TimeSheets t
union all select id = t.id , report_date = dateadd(day,3,t.WeekStartDate) , hours = t.Day4Hours from dbo.TimeSheets t
union all select id = t.id , report_date = dateadd(day,4,t.WeekStartDate) , hours = t.Day5Hours from dbo.TimeSheets t
union all select id = t.id , report_date = dateadd(day,5,t.WeekStartDate) , hours = t.Day6Hours from dbo.TimeSheets t
union all select id = t.id , report_date = dateadd(day,6,t.WeekStartDate) , hours = t.Day7Hours from dbo.TimeSheets t
) t
where t.report_date >= #period_start
and t.report_date < #period_end
Always start with start or an end of a month.
E.g. Here's some logic
Start Date = Start date of previous month + 16
End Date = Start date of current month + 15
Following might help you figure out the dates
-- First Day of the month
select DATEADD(mm, DATEDIFF(mm,0,getdate()), 0)
-- Last Day of previous month
select dateadd(ms,-3,DATEADD(mm, DATEDIFF(mm,0,getdate() ), 0))
More examples are here
Life is easier with a little data normalization. Don't work from the spreadsheet-style table
CREATE VIEW Timesheets_Normalized AS
SELECT
[id]
,[Date] = DATEADD(day,[Date_Offset],[WeekStartDate])
,[Hours]
FROM MyTable a
UNPIVOT([Hours] FOR [Date_Column] IN (Day1Hours,Day2Hours,Day3Hours,Day4Hours,Day5Hours,Day6Hours,Day7Hours)) b
INNER JOIN (VALUES (0,'Day1Hours'),(1,'Day2Hours'),(2,'Day3Hours'),(3,'Day4Hours'),(4,'Day5Hours'),(5,'Day6Hours'),(6,'Day7Hours')) c([Date_Offset],[Date_Column])
ON (b.[Date_Column] = c.[Date_Column])
Then you can get your answers very simply:
SELECT
MIN([Date]) AS [PayrollMonthStart]
,MAX([Date]) AS [PayrollMonthEnd]
,SUM([Hours]) AS [TotalHours]
FROM Timesheets_Normalized
GROUP BY YEAR(DATEADD(day,-15,[Date])),MONTH(DATEADD(day,-15,[Date]))
HAVING CAST(GETDATE() AS date) BETWEEN MIN([Date]) AND MAX([Date])
I want to display the month names available in the Quarters.
Means like we have four quarters 1,2,3,4 in a year. I have following query.
select datename(month,(DATEADD(QUARTER, DATEDIFF(QUARTER, 0, GETDATE()), 0)) )
Output is :October
But How should I modify this query so that I should get the output as:
October
November
December
declare #quarter datetime
set #quarter = DATEADD(QUARTER, DATEDIFF(QUARTER, 0, GETDATE()), 0)
select datename(month, #quarter)
union all
select datename(month, (DATEADD(month, 1, #quarter) ) )
union all
select datename(month, (DATEADD(month, 2, #quarter) ) )
Try this
DECLARE #d datetime = Dateadd(mm,0,getdate())
-- set #d = Dateadd(mm,-3,getdate())
;With Dates
AS
(
SELECT DATEADD(qq,DATEDIFF(qq,0,#d),0) AS StartDt,DATEPART(qq,#d) AS Qr
UNION ALL
SELECT DATEADD(mm,1,StartDt),DATEPART(qq,DATEADD(mm,1,StartDt+1)-1)
FROM Dates
WHERE DATEPART(qq,DATEADD(mm,1,StartDt+1)-1) = DATEPART(qq,#d)
)
SELECT
datename(month,StartDt) Mnth, Qr,StartDt
FROM Dates
SELECT DATENAME(m,DATEADD(qq, DATEDIFF(qq,0,getdate()), 0)) AS MonthsInQuarter
UNION ALL
SELECT DATENAME(m,DATEADD(mm,1,DATEADD(qq,DATEDIFF(qq,0,getdate()),0)))
UNION ALL
SELECT DATENAME(m,DATEADD(mm,2,DATEADD(qq,DATEDIFF(qq,0,getdate()),0)))