calculate the month difference between two dates
Its working fine with dateDiff(m, datestart , dateend ) but i have the scenario of calculate the month based on day.like if 01/01/2012 to 20/01/2012 must show as the result of 1 month.
and another scenario is 02/01/2012 to 03/02/102 must show the as the result of 2 months.
how can i do that.
Try This,
Declare #sDate date = '1/15/2014'
Declare #eDate date = '3/10/2014'
Select DATEDIFF(mm,#sDate,#eDate) - Case When datepart(DD,#sDate) > DATEPART(dd,#eDate) Then 1 else 0 end
SQL Fiddle DEMO
How about this,
SELECT CASE
WHEN
DATEPART(MONTH,'STARTDATE') = DATEPART (MONTH,'ENDDATE')
THEN
DATEPART(MONTH,'STARTDATE')
ELSE
DATEDIFF(MONTH,'STARTDATE','ENDDATE')
END
AS 'MONTH-DIFFERENCE'
FROM TABLE_NAME
I resolved it.
SELECT
BadgeNo AS [Badge No],
JB.GHRSBadgeNo AS [GHRS No],
(ISNULL(Emp.FirstName,'') + ' ' + ISNULL(Emp.MiddleName,'') + ' '+ ISNULL(Emp.LastName,'')) AS [Name],
JB.Department AS [Department],
JB.ServiceCompany AS [Service Company],
REPLACE(CONVERT(VARCHAR(11), Emp.BirthDate, 106), ' ', '-') AS [Birth Date]
FROM
Employee AS Emp
LEFT JOIN
jobdata AS JB
ON
EMP.BadgeNo = JB.BadgeNo
WHERE
1 = (FLOOR(DATEDIFF(dd,EMP.BirthDate,DATEADD(month, 1,GETDATE())) / 365.25))
-
(FLOOR(DATEDIFF(dd,EMP.BirthDate,GETDATE()) / 365.25))
Use the same function and Add 1 to the result
e.g.
(dateDiff(m, datestart , dateend )+1) as Month
Related
If a user selects a range such as:
Start: November 2016
End: September 2017,
I want to include all results that fall within the range of 2016-11-01 to 2017-09-30.
I tried concatenating together the year, month, and day, however the issue comes that not all months have the same last day. While I know all months start on day 01, a month's end day can be 28, 29, 30, or 31.
Is there a way to do this without constructing the date? SqlServer 2008 doesn't have the EOMONTH function, and I feel like anything more complex than that is not the right solution. I would like to avoid this:
WHERE
DateCol >= '2016' + '-' + '11' + '-01' AND
DateCol <= '2017' + '-' + '09' + '-30'
It really seems to me that the easiest and best answer is to go from the first of the beginning month to the first of the month after the ending month, and make the second comparison not inclusive.
In other words, instead of this:
WHERE
DateCol >= '2016' + '-' + '11' + '-01' AND
DateCol <= '2017' + '-' + '09' + '-30'
simply this:
WHERE
DateCol >= '2016' + '-' + '11' + '-01' AND
DateCol < '2017' + '-' + '10' + '-01'
There is a faster way to do so :
DECLARE #minDate DATE
DECLARE #maxDate DATE
SET #minDate = XXXXX
SET #maxDate = YYYYY
-- Get the first day of the month minDate.
SET #minDate = CONVERT(datetime,CONVERT(varchar(6),#minDate,112)+'01',112)
-- Get the last day of the month minDate.
SET #maxDate = CONVERT(datetime,CONVERT(varchar(6),#maxDate,112)+'01',112)
SET #maxDate = DATEADD(day, -1, DATEADD(month, 1, #maxDate))
SELECT * FROM myTABLE WHERE DateCol >= #minDate AND DateCol <= #maxDate
Or :
SELECT * FROM myTABLE
WHERE DateCol >= CONVERT(datetime,CONVERT(varchar(6),XXXXX,112)+'01',112)
AND DateCol <= DATEADD(day, -1, DATEADD(month, 1, CONVERT(datetime,CONVERT(varchar(6),YYYYY,112)+'01',112)))
Use syntax like CONVERT(datetime,'20170930',112) or CONVERT(datetime,'09-30-2017',110) for XXXXX and YYYYY rather than '2017-09-30' that use SQL Server implicit convertion from char to datetime (rely on the server configuration : can be hazardous!!!)).
Using this syntax is faster because #minDate and #maxDate do not need any evaluation. So that indexes can be used directly...
Otherwise a scalar function that will simulate the eomonth() behaviour could be usefull...
You could use following select statement to get last date of any month (and any year) by passing a field or date to it:
DECLARE #dtDate DATE
SET #dtDate = '09/25/2016'
SELECT CAST(DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,#dtDate)+1,0)) AS DATE) AS LastDay_AnyMonth
Please provide some example data and desired result and I will update my answer further.
Here you go:
DECLARE #YourTable TABLE (YourData DATE);
INSERT INTO #YourTable VALUES
('2016-11-01'),
('2016-09-05'),
('2017-03-03'),
('2017-11-11'),
('2017-12-14'),
('2017-09-30');
WITH CTE AS (
SELECT YourData
FROM #YourTable
WHERE YEAR(YourData) =2016 AND MONTH (YourData) >= 11
)
SELECT YourData
FROM #YourTable
WHERE YEAR(YourData) =2017 AND MONTH (YourData) <= 9
UNION ALL
SELECT YourData
FROM CTE;
There is no need to know the end of the month (28 or 30 or 31).
For 2008, you can simply convert the string
Example
Select Date1=convert(date,'November 2016')
,Date2=dateadd(DAY,-1,dateadd(MONTH,1,convert(date,'September 2017')))
Returns
Date1 Date2
2016-11-01 2017-09-30
So the WHERE would be somthing like this
...
Where DateCol between convert(date,'November 2016')
and dateadd(DAY,-1,dateadd(MONTH,1,convert(date,'September 2017')))
A useful construct for performing date-based operations is to make use of a Date Dimension table. You are creating a lookup table that is populated with a lot of information about dates over a large span of time. You can then query the table based on the information that you do have. The table is small enough so that it does not impose significant performance concerns.
In your particular case, you have the month and year. You would plug that into the date dimension table to get the first of the month from the beginning month and the last of the month from the ending month. You now have a time range to search over without any complex logic or calculations on the fly.
Aaron Bertrand explains it in depth here: https://www.mssqltips.com/sqlservertip/4054/creating-a-date-dimension-or-calendar-table-in-sql-server/
I have the following table structure:
Table: tbl_CustomerPromos:
COLUMN DATATYPE
PromoCodeID int (IDENTITY)
CustomerID int
PromoCode nvarchar(50)
AddedDate DateTime
IsPromoUsed smallint
I want to send email notification to all customers AFTER EVERY 7 days from the DAY of JOINING (AddedDate) until the next 30 days.
select
pc.[CustomerID]
, pc.[PromoCode]
, pc.[DiscountAmount]
, ISNULL(pc.[IsPromoUsed], 0) IsPromoUsed
, pc.[AddedBy]
, pc.[AddedDate]
, (c.FirstName + ' ' + c.LastName) FullName
, c.Email
from
tbl_PromoCodesNewCustomer pc
Left join
tbl_Customers c on pc.CustomerID = c.CustomerID
Where
isnull(pc.IsPromoUsed, 0) <> 1
AND pc.AddedDate = ?
NOTE: The 30days is to be counted from the day of joining (AddedDate) to next 30 days and not from joining month.
So, how to get rows with a date that is less than 30 days (AddedDate is not greater than 30 days from today's date)
To get the 'every 7 days' filter, I would suggest you MODULO the date diff (after checking that its within the 30 day period). A CTE will help DRY this up. Also, I'm assuming here that you'll only be running this exactly once per day.
WITH EligiblePromoCodes AS
(
SELECT
CustomerId,
PromoCode,
IsPromoUsed,
DiscountAmount,
AddedDate,
AddedBy,
DATEDIFF(dd, AddedDate, CURRENT_TIMESTAMP) AS DaysSinceAdded
FROM
tbl_PromoCodesNewCustomer
)
SELECT
pc.[CustomerID]
, pc.[PromoCode]
, pc.[DiscountAmount]
, ISNULL(pc.[IsPromoUsed], 0) IsPromoUsed
, pc.[AddedBy]
, pc.[AddedDate]
, (c.FirstName + ' ' + c.LastName) FullName
, c.Email
from
EligiblePromoCodes pc
Left join
tbl_Customers c on pc.CustomerID = c.CustomerID
Where
isnull(pc.IsPromoUsed, 0) <> 1
AND DaysSinceAdded <= 30
AND DaysSinceAdded % 7 = 0;
SqlFiddle here
Try lyk this
select ..
from table
where datediff(dd,AddedDate,getdate())<30 and ..
select pc.[CustomerID]
,pc.[PromoCode]
,pc.[DiscountAmount]
,isnull(pc.[IsPromoUsed],0)IsPromoUsed
,pc.[AddedBy]
,pc.[AddedDate]
,(c.FirstName +' '+ c.LastName)FullName
,c.Email
from tbl_PromoCodesNewCustomer pc
Left join tbl_Customers c
on pc.CustomerID=c.CustomerID
Where isnull(pc.IsPromoUsed,0)<>1
AND datediff(dd,pc.AddedDate,getdate())<30 order by pc.AddedDate desc
I am currently working on a query that needs to calculate the difference in days between two different dates. I've had issues with our DATE columns before, because they are all being stored as numeric columns which is a complete pain.
I tried using CONVERT as I had done in the past to try and get the different pieces of the DATETIME string built, but I am not having any luck.
The commented line --convert(datetime,) is where I am having the issue. Basically, I need to convert PO_DATE and LINE_DOCK_DATE to a format that is usable, so I can calculate the difference between the two in days.
USE BWDW
GO
SELECT
[ITEM_NO]
,[ITEM_DESC]
,[HEADER_DUE_DATE]
,[BWDW].[dbo].[DS_tblDimWhs].WHS_SHORT_NAME AS 'Warehouse'
,[BWDW].[dbo].[DS_tblFactPODtl].[PO_NO] AS 'PO NUMBER'
,[BWDW].[dbo].[DS_tblFactPODtl].[PO_DATE] AS 'Start'
,[BWDW].[dbo].[DS_tblFactPODtl].[PO_STATUS] AS 'Status'
,[BWDW].[dbo].[DS_tblFactPODtl].[LINE_DOCK_DATE] AS 'End'
--,(SELECT CONVERT(DATETIME, CONVERT(CHAR(8), [BWDW].[dbo].[DS_tblFactPODtl].[PO_DATE])) FROM dbo.DS_tblFactPODtl)
FROM [BWDW].[dbo].[DS_tblFactPODtl]
INNER JOIN [BWDW].[dbo].[DS_tblDimWhs] ON [BWDW].[dbo].[DS_tblFactPODtl].WAREHOUSE = [BWDW].[dbo].[DS_tblDimWhs].WAREHOUSE
INNER JOIN [BWDW].[dbo].[DS_tblFactPO] ON [BWDW].[dbo].[DS_tblFactPODtl].PO_NO = [BWDW]. [dbo].[DS_tblFactPO].PO_NO
WHERE [BWDW].[dbo].[DS_tblFactPODtl].[PO_STATUS] = 'Closed'
AND [BWDW].[dbo].[DS_tblFactPODtl].[LINE_DOCK_DATE] <> 0
I have a snippet I saved from a previous project I worked on that needed to only display results from today through another year. That had a bunch of CAST and CONVERTS in it, but I tried the same methodology with no success.
In the long run, I want to add a column to each database table to contain a proper datetime column that is usable in the future... but that is another story. I have read numerous posts on stackoverflow that talk about converting to NUMERIC and such, but nothing out of a NUMERIC back to DATETIME.
Example data:
Start | End | Difference
--------------------------------
20110501 | 20111019 | 171
20120109 | 20120116 | 7
20120404 | 20120911 | 160
Just trying to calculate the difference..
MODIFIED PER AARON:
SELECT
FPODtl.[ITEM_NO] AS [Item]
,FPODtl.[ITEM_DESC] AS [Description]
,D.WHS_SHORT_NAME AS [Warehouse]
,FPODtl.[PO_NO] AS [PO NUMBER]
,FPODtl.[PO_DATE] AS [Start]
,FPODtl.[PO_STATUS] AS [Status]
,FPODtl.[LINE_DOCK_DATE] AS [End]
,DATEDIFF
(
DAY,
CASE WHEN ISDATE(CONVERT(CHAR(8), FPODtl.PO_DATE)) = 1
THEN CONVERT(DATETIME, CONVERT(CHAR(8), FPODtl.PO_DATE)) END,
CASE WHEN ISDATE(CONVERT(CHAR(8), FPODtl.[LINE_DOCK_DATE])) = 1
THEN CONVERT(DATETIME, CONVERT(CHAR(8), FPODtl.[LINE_DOCK_DATE])) END
)
FROM [dbo].[DS_tblFactPODtl] AS FPODtl
INNER JOIN [dbo].[DS_tblDimWhs] AS D
ON FPODtl.WAREHOUSE = D.WAREHOUSE
INNER JOIN [dbo].[DS_tblFactPO] AS FPO
ON FPODtl.PO_NO = FPO.PO_NO
WHERE FPODtl.[PO_STATUS] = 'Closed'
AND FPODtl.[LINE_DOCK_DATE] <> 0;
DECLARE #x NUMERIC(10,0);
SET #x = 20110501;
SELECT CONVERT(DATETIME, CONVERT(CHAR(8), #x));
Result:
2011-05-01 00:00:00.000
To compare two:
DECLARE #x NUMERIC(10,0), #y NUMERIC(10,0);
SELECT #x = 20110501, #y = 20111019;
SELECT DATEDIFF
(
DAY,
CONVERT(DATETIME, CONVERT(CHAR(8), #x)),
CONVERT(DATETIME, CONVERT(CHAR(8), #y))
);
Result:
171
More importantly, fix the table. Stop storing dates as numbers. Store them as dates. If you get errors with this conversion, it's because your poor data choice has allowed bad data into the table. You can get around that - potentially - by writing the old version of TRY_CONVERT():
SELECT DATEDIFF
(
DAY,
CASE WHEN ISDATE(col1)=1 THEN CONVERT(DATETIME, col1) END,
CASE WHEN ISDATE(col2)=1 THEN CONVERT(DATETIME, col2) END
)
FROM
(
SELECT
col1 = CONVERT(CHAR(8), col1),
col2 = CONVERT(CHAR(8), col2)
FROM dbo.table
) AS x;
This will produce nulls for any row where there is garbage in either column. Here is a modification to your original query:
SELECT
[ITEM_NO] -- what table does this come from?
,[ITEM_DESC] -- what table does this come from?
,[HEADER_DUE_DATE] -- what table does this come from?
,D.WHS_SHORT_NAME AS [Warehouse] -- don't use single quotes for aliases!
,FPODtl.[PO_NO] AS [PO NUMBER]
,FPODtl.[PO_DATE] AS [Start]
,FPODtl.[PO_STATUS] AS [Status]
,FPODtl.[LINE_DOCK_DATE] AS [End]
,DATEDIFF
(
DAY,
CASE WHEN ISDATE(CONVERT(CHAR(8), FPODtl.PO_DATE)) = 1
THEN CONVERT(DATETIME, CONVERT(CHAR(8), FPODtl.PO_DATE)) END,
CASE WHEN ISDATE(CONVERT(CHAR(8), FPODtl.[LINE_DOCK_DATE])) = 1
THEN CONVERT(DATETIME, CONVERT(CHAR(8), FPODtl.[LINE_DOCK_DATE])) END
)
FROM [dbo].[DS_tblFactPODtl] AS FPODtl
INNER JOIN [dbo].[DS_tblDimWhs] AS D
ON FPODtl.WAREHOUSE = D.WAREHOUSE
INNER JOIN [dbo].[DS_tblFactPO] AS FPO
ON FPODtl.PO_NO = FPO.PO_NO
WHERE FPODtl.[PO_STATUS] = 'Closed'
AND FPODtl.[LINE_DOCK_DATE] <> 0;
If the date stored as a number is like this: 20130226 for today, then the simpler way to convert to DATE or DATETIME would be:
SELECT CONVERT(DATETIME,CONVERT(VARCHAR(8),NumberDate),112)
Here is a quick formula to create a date from parts :
DateAdd( Month, (( #Year - 1900 ) * 12 ) + #Month - 1, #Day - 1 )
Simply use substrings from your original field to extract #Year, #Month and #Day. For instance, if you have a numeric like 19531231 for december 31th, 1953, you could do :
DateAdd( Month, (( SubString(Cast(DateField As Varchar(8)), 1, 4) - 1900 ) * 12 ) +
SubString(Cast(DateField As Varchar(8)), 5, 2) - 1,
SubString(Cast(DateField As Varchar(8)), 7, 2) - 1 )
I have a legacy table, which I can't change.
The values in it can be modified from legacy application (application also can't be changed).
Due to a lot of access to the table from new application (new requirement), I'd like to create a temporary table, which would hopefully speed up the queries.
The actual requirement, is to calculate number of business days from X to Y. For example, give me all business days from Jan 1'st 2001 until Dec 24'th 2004. The table is used to mark which days are off, as different companies may have different days off - it isn't just Saturday + Sunday)
The temporary table would be created from a .NET program, each time user enters the screen for this query (user may run query multiple times, with different values, table is created once), so I'd like it to be as fast as possible. Approach below runs in under a second, but I only tested it with a small dataset, and still it takes probably close to half a second, which isn't great for UI - even though it's just the overhead for first query.
The legacy table looks like this:
CREATE TABLE [business_days](
[country_code] [char](3) ,
[state_code] [varchar](4) ,
[calendar_year] [int] ,
[calendar_month] [varchar](31) ,
[calendar_month2] [varchar](31) ,
[calendar_month3] [varchar](31) ,
[calendar_month4] [varchar](31) ,
[calendar_month5] [varchar](31) ,
[calendar_month6] [varchar](31) ,
[calendar_month7] [varchar](31) ,
[calendar_month8] [varchar](31) ,
[calendar_month9] [varchar](31) ,
[calendar_month10] [varchar](31) ,
[calendar_month11] [varchar](31) ,
[calendar_month12] [varchar](31) ,
misc.
)
Each month has 31 characters, and any day off (Saturday + Sunday + holiday) is marked with X. Each half day is marked with an 'H'. For example, if a month starts on a Thursday, than it will look like (Thursday+Friday workdays, Saturday+Sunday marked with X):
' XX XX ..'
I'd like the new table to look like so:
create table #Temp (country varchar(3), state varchar(4), date datetime, hours int)
And I'd like to only have rows for days which are off (marked with X or H from previous query)
What I ended up doing, so far is this:
Create a temporary-intermediate table, that looks like this:
create table #Temp_2 (country_code varchar(3), state_code varchar(4), calendar_year int, calendar_month varchar(31), month_code int)
To populate it, I have a union which basically unions calendar_month, calendar_month2, calendar_month3, etc.
Than I have a loop which loops through all the rows in #Temp_2, after each row is processed, it is removed from #Temp_2.
To process the row there is a loop from 1 to 31, and substring(calendar_month, counter, 1) is checked for either X or H, in which case there is an insert into #Temp table.
[edit added code]
Declare #country_code char(3)
Declare #state_code varchar(4)
Declare #calendar_year int
Declare #calendar_month varchar(31)
Declare #month_code int
Declare #calendar_date datetime
Declare #day_code int
WHILE EXISTS(SELECT * From #Temp_2) -- where processed = 0)
BEGIN
Select Top 1 #country_code = t2.country_code, #state_code = t2.state_code, #calendar_year = t2.calendar_year, #calendar_month = t2.calendar_month, #month_code = t2.month_code From #Temp_2 t2 -- where processed = 0
set #day_code = 1
while #day_code <= 31
begin
if substring(#calendar_month, #day_code, 1) = 'X'
begin
set #calendar_date = convert(datetime, (cast(#month_code as varchar) + '/' + cast(#day_code as varchar) + '/' + cast(#calendar_year as varchar)))
insert into #Temp (country, state, date, hours) values (#country_code, #state_code, #calendar_date, 8)
end
if substring(#calendar_month, #day_code, 1) = 'H'
begin
set #calendar_date = convert(datetime, (cast(#month_code as varchar) + '/' + cast(#day_code as varchar) + '/' + cast(#calendar_year as varchar)))
insert into #Temp (country, state, date, hours) values (#country_code, #state_code, #calendar_date, 4)
end
set #day_code = #day_code + 1
end
delete from #Temp_2 where #country_code = country_code AND #state_code = state_code AND #calendar_year = calendar_year AND #calendar_month = calendar_month AND #month_code = month_code
--update #Temp_2 set processed = 1 where #country_code = country_code AND #state_code = state_code AND #calendar_year = calendar_year AND #calendar_month = calendar_month AND #month_code = month_code
END
I am not an expert in SQL, so I'd like to get some input on my approach, and maybe even a much better approach suggestion.
After having the temp table, I'm planning to do (dates would be coming from a table):
select cast(convert(datetime, ('01/31/2012'), 101) -convert(datetime, ('01/17/2012'), 101) as int) - ((select sum(hours) from #Temp where date between convert(datetime, ('01/17/2012'), 101) and convert(datetime, ('01/31/2012'), 101)) / 8)
Besides the solution of normalizing the table, the other solution I implemented for now, is a function which does all this logic of getting the business days by scanning the current table. It runs pretty fast, but I'm hesitant to call a function, if I can instead add a simpler query to get result.
(I'm currently trying this on MSSQL, but I would need to do same for Sybase ASE and Oracle)
This should fulfill the requirement, "...calculate number of business days from X to Y."
It counts each space as a business day and anything other than an X or a space as a half day (should just be H, according to the OP).
I pulled this off in SQL Server 2008 R2:
-- Calculate number of business days from X to Y
declare #start date = '20120101' -- X
declare #end date = '20120101' -- Y
-- Outer query sums the length of the full_year text minus non-work days
-- Spaces are doubled to help account for half-days...then divide by two
select sum(datalength(replace(replace(substring(full_year, first_day, last_day - first_day + 1), ' ', ' '), 'X', '')) / 2.0) as number_of_business_days
from (
select
-- Get substring start value for each year
case
when calendar_year = datepart(yyyy, #start) then datepart(dayofyear, #start)
else 1
end as first_day
-- Get substring end value for each year
, case
when calendar_year = datepart(yyyy, #end) then datepart(dayofyear, #end)
when calendar_year > datepart(yyyy, #end) then 0
when calendar_year < datepart(yyyy, #start) then 0
else datalength(full_year)
end as last_day
, full_year
from (
select calendar_year
-- Get text representation of full year
, calendar_month
+ calendar_month2
+ calendar_month3
+ calendar_month4
+ calendar_month5
+ calendar_month6
+ calendar_month7
+ calendar_month8
+ calendar_month9
+ calendar_month10
+ calendar_month11
+ calendar_month12 as full_year
from business_days
-- where country_code = 'USA' etc.
) as get_year
) as get_days
A where clause can go on the inner-most query.
It is not an un-pivot of the legacy format, which the OP spends much time on and which will probably take more (and possibly unnecessary) computing cycles. I'm assuming such a thing was "nice to see" rather than part of the requirements. Jeff Moden has great articles on how a tally table could help in that case (for SQL Server, anyway).
It might be necessary to watch trailing spaces depending upon how a particular DBMS is set (notice that I'm using datalength and not len).
UPDATE: Added the OP's requested temp table:
select country_code
, state_code
, dateadd(d, t.N - 1, cast(cast(a.calendar_year as varchar(8)) as date)) as calendar_date
, case substring(full_year, t.N, 1) when 'X' then 0 when 'H' then 4 else 8 end as business_hours
from (
select country_code
, state_code
, calendar_year
, calendar_month
+ calendar_month2
+ calendar_month3
+ calendar_month4
+ calendar_month5
+ calendar_month6
+ calendar_month7
+ calendar_month8
+ calendar_month9
+ calendar_month10
+ calendar_month11
+ calendar_month12
as full_year
from business_days
) as a, (
select a.N + b.N * 10 + c.N * 100 + 1 as N
from (select 0 as N union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) a
, (select 0 as N union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) b
, (select 0 as N union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) c
) as t -- cross join with Tally table built on the fly
where t.N <= datalength(a.full_year)
Given your temp table is slow to create, are you able to pre-calculate it?
If you're able to put a trigger on the existing table, perhaps you could fire a proc which will drop and create the temp table. Or have an agent job which checks to see if the existing table has been updated (raise a flag somewhere) and then recomputes the temp table.
The existing table's structure is so woeful that I wouldn't be surprised if it will always be expensive to normalize it. Pre-calculating is an easy and simple way around that problem.
I wrote a query
WITH sample AS (
SELECT CAST('2010-01-01' AS DATETIME) AS d
UNION ALL
SELECT DATEADD(dd, 1, i.vrp_notificationdate) as deneme
FROM Incident i
WHERE DATEADD(dd, 1, i.vrp_notificationdate) <= CAST('2011-11-01' AS DATETIME))
SELECT count(DATENAME(mm,l.vrp_notificationdate) +' '+DATENAME(yy,l.vrp_notificationdate)) as Toplam,DATENAME(mm,l.vrp_notificationdate) +' '+DATENAME(yy,l.vrp_notificationdate)
FROM Incident as l
group by
DATENAME(mm,l.vrp_notificationdate) +' '+DATENAME(yy,l.vrp_notificationdate)
the query show
10 November 2011
101 October 2011
4 September 2011
but i want to show this .
0 january 2010
0 february 2010
-
-
-
10 November 2011
101 October 2011
4 september 2011
0 december 2011
0 february 2011
i tried case when statement,but query show same result
How to solve what i use
Best regards.
You are trying to show data that doesn't exist. The idea of this solution is to
Add dummy dates
Assign a count of 0 to each dummy date
Union your original results with this dummy dates
Group into a final result
SQL Statement
DECLARE #StartDate DATE = '01-01-2010'
;WITH Dates(d) AS (
SELECT #StartDate
UNION ALL
SELECT DATEADD(mm, 1, d) AS Date
FROM Dates
WHERE d < '12-01-2012'
)
,WITH sample AS (
SELECT CAST('2010-01-01' AS DATETIME) AS d
UNION ALL
SELECT DATEADD(dd, 1, i.vrp_notificationdate) as deneme
FROM Incident i
WHERE DATEADD(dd, 1, i.vrp_notificationdate) <= CAST('2011-11-01' AS DATETIME)
)
SELECT SUM(Toplam) AS Toplam
, DateFormat
FROM (
SELECT COUNT(DATENAME(mm,l.vrp_notificationdate) + ' ' + DATENAME(yy,l.vrp_notificationdate)) AS Toplam
, DATENAME(mm,l.vrp_notificationdate) + ' ' + DATENAME(yy,l.vrp_notificationdate) AS DateFormat
, CONVERT(VARCHAR(6), l.vrp_notificationdate, 112) as orderDate
FROM Incident as l
GROUP BY
DATENAME(mm,l.vrp_notificationdate) + ' ' + DATENAME(yy,l.vrp_notificationdate)
, CONVERT(VARCHAR(6), l.vrp_notificationdate, 112)
UNION ALL
SELECT 0 AS Toplam
, DATENAME(mm, d) + ' ' + DATENAME(yy, d)
, CONVERT(VARCHAR(6), d.d, 112) as orderDate
FROM Dates d
) g
GROUP BY
DateFormat
ORDER BY
g.orderDate
Well, if the date doesn't appear, it means that there isn't any value present for that date. So, it's impossible to get that date to appear in the result.
To pass this the simplest solution is to:
Create a table with all the possible dates and another column that will start with zero.
Update that table with the results of the query that you made (update the column that start with zero to have the count values).
Display the end results from the new table:
select countValues + ' ' + dateValues from newTable
If you have any doubt, just ask :)
Why do you provide "WITH sample AS" when you do not use sample?
I'ld use this recursive query to build all dates for your result table.
WITH sample (d) AS (
SELECT CAST('2010-01-01' AS DATETIME)
UNION ALL
SELECT DATEADD(mm, 1, d) FROM sample WHERE DATEADD(mm, 1, d) <= CAST('2011-11-01' AS DATETIME)
)
select * from sample
You could then outer join this table with your Incident table to get the count of incidents for each month.
If you want to see a lot of months or even days, you might get an MSG 530 because of too much recursion. In this case you need the add OPTION (MAXRECURSION ) after "select * from sample".