TSQL SELECT data within range of year and month - tsql

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))

Related

SQL Server - WHERE Date Range & GROUP BY MonthName

I have 2 same queries (to return "MonthName Year" and count) as below, but only the date range in the WHERE condition is different. Query 1 gets only the June month count, while Query 2 gets count from Apr to Jul, where the Jun month count (in Query 2) is not same as June month count from Query 1. Please advise.
Query 1:
SELECT DATENAME(MONTH, SubmissionDate) + ' ' + DateName(Year, SubmissionDate) AS MonthNumber, COUNT(1) AS InquiryCount
, Cast(Datename(MONTH,SubmissionDate) + ' ' + Datename(YEAR,SubmissionDate) AS DATETIME) AS tmp
FROM [dbo].[InvestigationDetails] (nolock)
WHERE SubmissionDate>= '06/01/2016'
AND SubmissionDate <= '06/30/2016'
GROUP BY DATENAME(MONTH, SubmissionDate) + ' ' + DateName(Year, SubmissionDate), DateName(Year, SubmissionDate)
ORDER BY tmp ASC
Query 2:
SELECT DATENAME(MONTH, SubmissionDate) + ' ' + DateName(Year, SubmissionDate) AS MonthNumber, DateName(Year, SubmissionDate), COUNT(1) AS InquiryCount
, Cast(Datename(MONTH,SubmissionDate) + ' ' + Datename(YEAR,SubmissionDate) AS DATETIME) AS tmp
FROM [dbo].[InvestigationDetails] (nolock)
WHERE SubmissionDate>= '04/01/2016'
AND SubmissionDate <= '07/31/2016'
GROUP BY DATENAME(MONTH, SubmissionDate) + ' ' + DateName(Year, SubmissionDate), DateName(Year, SubmissionDate)
ORDER BY tmp ASC
Thanks,
Jay
SubmissionDate must be of type DATETIMEand thus, you are missing all values for your last day, 06/30/2016, since this equates to 06/30/2016 00:00:00. This means any records that have SubmissionDate with a time > 00:00:00 on 6/30/2016 will be excluded. For example, 6/30/2016 12:44:22 wouldn't be included in your results with your current logic.
Use one of these instead:
AND SubmissionDate < '07/01/2016'
AND SubmissionDate <= '06/30/2016 23:59:59.999'
The first method is preferred since you will get all records before 7/1/2016, which includes 6/30/2016 23:59:59.999. Of course, you should be aware of how precise DATETIME can be in SQL Server. Run the code below to see what I mean.
declare #dt datetime2 = getdate()
select #dt --more precise with datetime2
select getdate() --not as precise

SQL Server 2008 R2 - convert all datetime parts (as ints) into a datetime column

I have a table that has the datetime pieces (year, month, day, hour, minute, second, millisecond) stored as integers. I'd like to concatenate them into a single datetime column.
I've tried various approaches but none work - there seems to be no simple way to put these items together?
You can convert each part to a varchar and concatenate them together in the format of an ISO datetime string. Then use Convert to convert the string to a DateTime.
Here is an example. You would need to replace each hard coded integer with the name of the column from your table.
SELECT CONVERT(DATETIME, CAST(2016 AS VARCHAR(4)) -- year
+ '-' + CAST('0' + CAST(8 AS VARCHAR(2)) AS VARCHAR(2)) -- month
+ '-' + RIGHT('0' + CAST(13 AS VARCHAR(2)), 2) -- day of month
+ 'T' + RIGHT('0' + CAST(16 AS VARCHAR(2)), 2) -- hours (I assume its military time (24 hours))
+ ':' + RIGHT('0' + CAST(32 AS VARCHAR(2)), 2) -- minutes
+ ':' + RIGHT('0' + CAST(07 AS VARCHAR(2)), 2) -- seconds
+ '.' + RIGHT('000' + CAST(64 AS VARCHAR(3)), 3)) AS MyDate -- milliseconds
FROM yourTable
Or with column names (assumed)
SELECT CONVERT(DATETIME, CAST(yt.Year AS VARCHAR(4)) -- year
+ '-' + CAST('0' + CAST(yt.Month AS VARCHAR(2)) AS VARCHAR(2)) -- month
+ '-' + RIGHT('0' + CAST(yt.Day AS VARCHAR(2)), 2) -- day of month
+ 'T' + RIGHT('0' + CAST(yt.Hours AS VARCHAR(2)), 2) -- hours (I assume its military time (24 hours))
+ ':' + RIGHT('0' + CAST(yt.Minutes AS VARCHAR(2)), 2) -- minutes
+ ':' + RIGHT('0' + CAST(yt.Seconds AS VARCHAR(2)), 2) -- seconds
+ '.' + RIGHT('000' + CAST(yt.Milliseconds AS VARCHAR(3)), 3)) AS MyDate -- milliseconds
FROM yourTable yt
One more note. Microsoft recommends that you use DateTime2 instead of DateTime to persist date time values starting with Sql Server 2008 (which you tagged in your question).
Prior to sql server 2012, you can use a series of nested DATEADD() functions to mimic DATETIMEFROMPARTS() function
Create and populate sample data (In your next question, please save us this step)
DECLARE #T as table
(
cYear int,
cMonth int,
cDay int,
cHour int,
cMinute int,
cSecond int,
cMillisecond int
)
INSERT INTO #T VALUES(2016, 6, 22, 16, 34, 25, 3)
The query:
SELECT *,
DATEADD(MILLISECOND, cMillisecond,
DATEADD(SECOND, cSecond,
DATEADD(MINUTE, cMinute,
DATEADD(HOUR, cHour,
DATEADD(DAY, cDay -1,
DATEADD(MONTH, cMonth - 1,
DATEADD(YEAR, cYear - 2000, '2000-01-01')
)
)
)
)
)
) As TheDate
FROM #T
Results:
cYear cMonth cDay cHour cMinute cSecond cMillisecond TheDate
----- ------ ---- ----- ------- ------- ------------- -----------------------
2016 6 22 16 34 25 3 2016-06-22 16:34:25.003
Note that the base date I'm using is January 1st 2000, therefor you need to subtract 2000 from the year, 1 from the month and 1 from the days.

Yearly total for items over multiple years

I am trying to find the total per year
For example
Start date End Date Total Value
1 07/01/14 01/01/15 $10,000
2 08/01/13 12/01/14 $10,000
3 03/01/13 05/01/15 $10,000
As you can see, Some items are over multiple years. Is there a way to find out what the total value is per year.
Solution should be:
item 3
2013- $3600
2014-$4800
2015-1600
Then a summation would be down for all three items to give a yearly total.
What I have so far:
I have a rolling summation code which is shown below.
case when
(
[begin date] >= dateadd(mm,0,DATEADD(mm,DATEDIFF(mm,0,getdate()),0))
and [end date] >= dateadd(mm,0,DATEADD(mm,DATEDIFF(mm,0,getdate()),0))
)
OR
(
[Begin Date] < dateadd(mm,0,DATEADD(mm,DATEDIFF(mm,0,getdate()),0))
and [End Date] >= dateadd(mm,0,DATEADD(mm,DATEDIFF(mm,0,getdate()),0))
)
then [Totalvalue]/nullif(DATEDIFF(mm,[begin date],[end date]),0)
else 0
end [Current Month]
I dono how you got that total values for item 3
but for item 3 i hope it should be
2013 = 3704
2014 = 4444
2015 = 1852
Dono how efficient this code is just have a try
CREATE TABLE #tblName
(
itemid INT,
startdate DATETIME,
endate DATETIME,
value int
)
INSERT INTO #tblName
VALUES (1,'2014/07/01','2015/01/01',10000),
(2,'2013/08/01','2014/12/01',10000),
(3,'2013/03/01','2015/05/01',10000)
DECLARE #mindate DATETIME,
#maxdate DATETIME
SELECT #mindate = Min(startdate),
#maxdate = Max(endate)
FROM #tblName
SELECT *
FROM #tblName;
WITH cte
AS (SELECT #mindate startdate
UNION ALL
SELECT Dateadd(mm, 1, startdate) startdate
FROM cte
WHERE startdate <= Dateadd(mm, -1, #maxdate))
SELECT a.value * ( ( convert(numeric(22,6),a.cnt) / convert(numeric(22,6),c.total) ) * 100 ) / 100,a.itemid,a.startdate
FROM (SELECT Avg(value) value,
Count(1) cnt,
itemid,
Year(a.startdate) startdate
FROM cte a
JOIN #tblName b
ON a.startdate BETWEEN b.startdate AND b.endate
GROUP BY itemid,
Year(a.startdate)) a
JOIN(SELECT Sum(cnt) total,
itemid
FROM (SELECT Avg(value) value,
Count(1) cnt,
itemid,
Year(a.startdate) startdate
FROM cte a
JOIN #tblName b
ON a.startdate BETWEEN b.startdate AND b.endate
GROUP BY itemid,
Year(a.startdate)) B
GROUP BY itemid) C
ON a.itemid = c.itemid
WHERE a.itemid = 3

Getting the start date and end date of all weeks by giving the year

I have a query which displays a set of 52 numbers along with the respective dates of that week
SELECT kkk, TO_CHAR (start_date, 'DD-MON-YYYY'),
TO_CHAR (start_date + 6, 'DD-MON-YYYY') AS end_day
FROM (SELECT TRUNC (TRUNC (TO_DATE ('2014', 'YYYY'), 'YYYY') + 1 * 7,
'IW'
)
- 1 start_date,
ROWNUM AS kkk
FROM DUAL
CONNECT BY ROWNUM <= 52);
but the problem with this query is that I am only getting the first week dates but not for the next consecutive weeks.Please help
Try like this,
SELECT kkk,
TO_CHAR(start_date, 'DD-MON-YYYY') start_date,
TO_CHAR(start_date + 6, 'DD-MON-YYYY') end_day
FROM(
SELECT TRUNC(Trunc(to_date('2014', 'YYYY'),'YYYY')+ LEVEL * 7,'IW')-1 start_date ,
ROWNUM kkk
FROM duaL
CONNECT BY LEVEL <= 52
);
Instead of ROWNUM you can also use LEVEL, Like,
SELECT TRUNC(Trunc(to_date('2014', 'YYYY'),'YYYY')+ LEVEL * 7,'IW')-1 start_date ,
level kkk
FROM duaL
CONNECT BY LEVEL <= 52

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