I'm working with a dynamic query right now and I need values from a table.
My query so far:
DECLARE #query varchar(1500)
SET #query =
'SELECT Id,'
+ 'SUM(CASE WHEN ['+convert(varchar(50),CAST(myTable.myDate AS date),120)+'] = ['+convert(varchar(50), CAST(GETDATE() AS date), 120)+'] then [Counter] else 0 end) ''0'','
+ 'SUM(CASE WHEN ['+convert(varchar(50),CAST(DATEADD(day, -1, myTable.myDate)), 120)+'] = ['+convert(varchar(50),CAST(DATEADD(day, -1, GETDATE()) AS date), 120)+'] then [counter] else 0 end) ''1'','
+ 'SUM(CASE WHEN ['+convert(varchar(50),CAST(DATEADD(day, -2, myTable.myDate)), 120)+'] = ['+convert(varchar(50),CAST(DATEADD(day, -2, GETDATE()) AS date), 120)+'] then [counter] else 0 end) ''2'','
+ 'SUM(CASE WHEN ['+convert(varchar(50), CAST(DATEADD(day, -3, myTable.myDate)), 120)+'] = ['+convert(varchar(50),CAST(DATEADD(day, -3, GETDATE()) AS date),120)+'] then [counter] else 0 end) ''3'','
+ 'SUM(CASE WHEN ['+convert(varchar(50),CAST(DATEADD(day, -4, myTable.myDate)),120)+'] = ['+convert(varchar(50),CAST(DATEADD(day, -4, GETDATE()) AS date),120)+'] then [counter] else 0 end) ''4'''
+ 'FROM [myTable] GROUP BY Id'
PRINT(#query)
EXEC(#query)
This wont work because it says "Multi-part identifyer "myTable" could not be bound." on rows 4-8.
Ive seen people recomending something like this:
CREATE TABLE #tmp
(
id varchar(50),
counter int,
myDate smalldatetime
)
Insert Into #tmp (id, counter, myDate)
SELECT * FROM myTable
--GO --doesn't work either with or without 'go'
DECLARE #query varchar(1500)
SET #query =
'SELECT Id,'
+ 'SUM(CASE WHEN ['+convert(varchar(50),CAST(#tmp.myDate AS date),120)+'] = ['+convert(varchar(50), CAST(GETDATE() AS date), 120)+'] then [counter] else 0 end) ''0'','
+ 'SUM(CASE WHEN ['+convert(varchar(50),CAST(DATEADD(day, -1, #tmp.myDate)), 120)+'] = ['+convert(varchar(50),CAST(DATEADD(day, -1, GETDATE()) AS date), 120)+'] then [counter] else 0 end) ''1'','
+ 'SUM(CASE WHEN ['+convert(varchar(50),CAST(DATEADD(day, -2, #tmp.myDate)), 120)+'] = ['+convert(varchar(50),CAST(DATEADD(day, -2, GETDATE()) AS date), 120)+'] then [counter] else 0 end) ''2'','
+ 'SUM(CASE WHEN ['+convert(varchar(50),CAST(DATEADD(day, -3, #tmp.myDate)), 120)+'] = ['+convert(varchar(50),CAST(DATEADD(day, -3, GETDATE()) AS date),120)+'] then [counter] else 0 end) ''3'','
+ 'SUM(CASE WHEN [+'convert(varchar(50),CAST(DATEADD(day, -4, #tmp.myDate)), 120)+'] = ['+convert(varchar(50),CAST(DATEADD(day, -4, GETDATE()) AS date),120)+'] then [aounter] else 0 end) ''4'''
+ 'FROM [myTable] GROUP BY Id'
PRINT(#query)
EXEC(#query)
Still doesn't work. Please help!
SIMPLIFIED VERSION OF MY PROBLEM:
DECLARE #query varchar(1500)
SET #query = 'SELECT ['+myTable.value+'] FROM [myTable]'
EXEC(#query)
doesn't work
Try something like this:
CREATE TABLE #tmp
(
id varchar(50),
counter int,
myDate smalldatetime
)
Insert Into #tmp (id, counter, myDate)
SELECT * FROM myTable
DECLARE #query varchar(1500)
Select #query =
'SELECT Id,'
+ 'SUM(CASE WHEN ''' + convert(varchar(50), #tmp.myDate,120) + ''' = '''+convert(varchar(50), GETDATE(), 120)+''' then ''counter'' else 0 end) ''0'','
+ 'SUM(CASE WHEN '''+convert(varchar(50), DATEADD(day, -1, #tmp.myDate), 120)+''' = '''+convert(varchar(50),DATEADD(day, -1, GETDATE()), 120)+''' then ''counter'' else 0 end) ''1'','
+ 'SUM(CASE WHEN '''+convert(varchar(50), DATEADD(day, -2, #tmp.myDate), 120)+''' = '''+convert(varchar(50),DATEADD(day, -2, GETDATE()), 120)+''' then ''counter'' else 0 end) ''2'','
+ 'SUM(CASE WHEN '''+convert(varchar(50), DATEADD(day, -3, #tmp.myDate), 120)+''' = '''+convert(varchar(50),DATEADD(day, -3, GETDATE()), 120)+''' then ''counter'' else 0 end) ''3'','
+ 'SUM(CASE WHEN '''+convert(varchar(50), DATEADD(day, -4, #tmp.myDate), 120)+''' = '''+convert(varchar(50),DATEADD(day, -4, GETDATE()), 120)+''' then ''counter'' else 0 end) ''4'''
+ ' FROM ' from #tmp
Set #query = #query + ' #tmp GROUP BY Id'
PRINT(#query)
EXEC(#query)
Related
I have created a pivot table with hard coded column names. The pivot table simply keeps a rolling sum of sales by qty (current month + 11 months back).
It was my first time using the PIVOT function properly and the code works fine.
SELECT
Item_Code_Desc,
ISNULL([Current],0) AS [Current],
ISNULL([1],0) AS [1],
ISNULL([2],0) AS [2],
ISNULL([3],0) AS [3],
ISNULL([4],0) AS [4],
ISNULL([5],0) AS [5],
ISNULL([6],0) AS [6],
ISNULL([7],0) AS [7],
ISNULL([8],0) AS [8],
ISNULL([9],0) AS [9],
ISNULL([10],0) AS [10],
ISNULL([11],0) AS [11]
FROM
(SELECT
CONCAT(ST.Code,' - ', ST.Description_1) AS Item_Code_Desc,
STT.ActualQuantity AS Qty,
CASE
WHEN MONTH(STT.TxDate) = MONTH(GETDATE()) THEN 'Current'
WHEN MONTH(STT.TxDate) = MONTH(DATEADD(MONTH, -1, GETDATE())) THEN '1'
WHEN MONTH(STT.TxDate) = MONTH(DATEADD(MONTH, -2, GETDATE())) THEN '2'
WHEN MONTH(STT.TxDate) = MONTH(DATEADD(MONTH, -3, GETDATE())) THEN '3'
WHEN MONTH(STT.TxDate) = MONTH(DATEADD(MONTH, -4, GETDATE())) THEN '4'
WHEN MONTH(STT.TxDate) = MONTH(DATEADD(MONTH, -5, GETDATE())) THEN '5'
WHEN MONTH(STT.TxDate) = MONTH(DATEADD(MONTH, -6, GETDATE())) THEN '6'
WHEN MONTH(STT.TxDate) = MONTH(DATEADD(MONTH, -7, GETDATE())) THEN '7'
WHEN MONTH(STT.TxDate) = MONTH(DATEADD(MONTH, -8, GETDATE())) THEN '8'
WHEN MONTH(STT.TxDate) = MONTH(DATEADD(MONTH, -9, GETDATE())) THEN '9'
WHEN MONTH(STT.TxDate) = MONTH(DATEADD(MONTH, -10, GETDATE())) THEN '10'
WHEN MONTH(STT.TxDate) = MONTH(DATEADD(MONTH, -11, GETDATE())) THEN '11'
ELSE '0'
END AS [Period]
FROM
_bvSTTransactionsFull AS STT
INNER JOIN
StkItem AS ST ON STT.AccountLink = ST.StockLink
WHERE
STT.TxDate >= DATEADD(MONTH, -11, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0))
AND STT.Module = 'AR') AS P
PIVOT
(SUM(P.Qty)
FOR P.Period IN ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[Current])
) AS PVT
To make the output more dynamic, I wanted to rather show the month and year as the field heading, rather than just the 1,2,3 etc.
To attempt this, I first took out the original CASE, and used the CONCAT function to get the desired result
CONCAT(DATENAME(MONTH,STT.TxDate),' ',YEAR(STT.TxDate)) AS [Period],
Now that the sub-query was showing the transaction date in the format "mmmm yyyy", I wanted the table to pivot on this. I did start wondering how it was going to do this as I was reaching the end, as the column names are not hard coded anymore.
After trying
PIVOT (
SUM(P.Qty)
FOR CONCAT(DATENAME(MONTH,P.TxDate),' ',YEAR(P.TxDate))
) AS PVT
And many other variations I did do some research, and I see this process is slightly more complex than I thought.
I haven't used the STUFF and FOR XML PATH before. I have attempted to convert the above into the examples I have found on the net. But I'm trying in vein as I don't understand the core logic of what I am trying to do.
Please could I have assistance with not only how to get the pivot dynamic, but perhaps some notes to further understand what is happening. Really appreciate some help on this!
After Attempting
This is my attempt to get it right:
DECLARE
#Cols NVARCHAR(MAX),
#Query NVARCHAR(MAX),
#Module NVARCHAR = 'AR'
SELECT
#Cols = STUFF((SELECT DISTINCT ',' + 'CONCAT(DATENAME(MONTH, STT.TxDate),,YEAR(STT.TxDate))' + QUOTENAME(NAME)
FROM _bvSTTransactionsFull AS STT
WHERE STT.Module = 'AR'
FOR XML PATH (''), TYPE).VALUE('.','NVARCHAR(MAX)'),1,1,'')
SELECT
#Query = '
SELECT
Item_Code,
Item_Desc,
' +''''+ #Cols + '''''
FROM
(SELECT
ST.Code AS Item_Code,
ST.Description_1 AS Item_Desc,
STT.ActualQuantity AS Qty,
CONCAT(DATENAME(MONTH, STT.TxDate),,YEAR(STT.TxDate)) AS [Period]
FROM
_bvSTTransactionsFull AS STT
INNER JOIN
StkItem AS ST ON STT.AccountLink = ST.StockLink
WHERE
STT.TxDate >= DATEADD(MONTH, -13, DATEADD(MONTH, DATEDIFF(MONTH, 0,
GETDATE()), 0))
AND STT.Module = '+ #Module +') AS P
PIVOT
(SUM(P.Qty)
FOR P.Period IN ('+#cols+')
) AS PVT '
PRINT #Query
EXEC (#Query)
But I'm getting the following error:
Msg 207, Level 16, State 1, Line 7
Invalid column name 'NAME'.
Where am I off here?
Your result is correct above however, you will not have your columns sorted by the correct date...
The below would cater for that:
DECLARE
#Cols1 VARCHAR(MAX),
#Cols2 VARCHAR(MAX),
#Query VARCHAR(MAX),
#Period VARCHAR(MAX) = -13 ; --/ Select number of months to view back on (excluding current month) \--
declare #tmptbl table (PeriodDate datetime, col1 varchar(100), col2 varchar(100))
insert into #tmptbl (PeriodDate, col1, col2)
SELECT DISTINCT dPeriodDate,'ISNULL('+ QUOTENAME(CONCAT(DATENAME(MONTH, dPeriodDate),' ',YEAR(dPeriodDate)))+',0) AS' + QUOTENAME(CONCAT(DATENAME(MONTH, dPeriodDate),' ',YEAR(dPeriodDate))) col1
, QUOTENAME(CONCAT(DATENAME(MONTH, dPeriodDate),' ',YEAR(dPeriodDate))) col2
FROM _bvSTTransactionsFull AS S join _etblPeriod p on EOMONTH(s.TxDate) = p.dPeriodDate
WHERE S.Module = 'AR' AND S.TxDate > = DATEADD(MONTH, -13, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0))
SELECT
#Cols1 = STUFF((SELECT ',' + col1
FROM #tmptbl order by PeriodDate
FOR XML PATH (''), TYPE).value('.','NVARCHAR(MAX)'),1,1,'') --/ allows the first SELECT fields to have the ISNULL function and Alias \--
SELECT
#Cols2 = STUFF((SELECT ',' + col2
FROM #tmptbl order by PeriodDate
FOR XML PATH (''), TYPE).value('.','NVARCHAR(MAX)'),1,1,'') --/ becasue of the need for ISNULL above, second #Cols needed for the Pivot (pivot cannot have ISNULL in it) \--
SELECT
#Query =
'SELECT
Item_Code_Desc,
'+#Cols1+'
FROM
(SELECT
CONCAT(ST.Code,'' - '', ST.Description_1) AS Item_Code_Desc,
STT.ActualQuantity AS Qty,
CONCAT(DATENAME(MONTH, STT.TxDate),'' '',YEAR(STT.TxDate)) AS [Period]
FROM
_bvSTTransactionsFull AS STT
INNER JOIN
StkItem AS ST ON STT.AccountLink = ST.StockLink
WHERE
STT.TxDate >= DATEADD(MONTH, '+#Period+', DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0))
AND STT.Module = ''AR'') AS P
PIVOT
(SUM(P.Qty)
FOR P.Period IN ('+#cols2+')
) AS PVT '
PRINT #Query
EXEC (#Query)
I left the changes I made in small caps for you to see the changes...
Solved :)
DECLARE
#Cols1 VARCHAR(MAX),
#Cols2 VARCHAR(MAX),
#Query VARCHAR(MAX),
#Period VARCHAR(MAX) = -12 ; --/ Select number of months to view back on (excluding current month) \--
SELECT
#Cols1 = STUFF((SELECT DISTINCT ',' +'ISNULL('+ QUOTENAME(CONCAT(DATENAME(MONTH, S.TxDate),' ',YEAR(S.TxDate)))+',0) AS' + QUOTENAME(CONCAT(DATENAME(MONTH, S.TxDate),' ',YEAR(S.TxDate)))
FROM _bvSTTransactionsFull AS S
WHERE S.Module = 'AR' AND S.TxDate > = DATEADD(MONTH, -13, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0))
FOR XML PATH (''), TYPE).value('.','NVARCHAR(MAX)'),1,1,'') --/ allows the first SELECT fields to have the ISNULL function and Alias \--
SELECT
#Cols2 = STUFF((SELECT DISTINCT ',' + QUOTENAME(CONCAT(DATENAME(MONTH, S.TxDate),' ',YEAR(S.TxDate)))
FROM _bvSTTransactionsFull AS S
WHERE S.Module = 'AR' AND S.TxDate > = DATEADD(MONTH, -13, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0))
FOR XML PATH (''), TYPE).value('.','NVARCHAR(MAX)'),1,1,'') --/ becasue of the need for ISNULL above, second #Cols needed for the Pivot (pivot cannot have ISNULL in it) \--
SELECT
#Query =
'SELECT
Item_Code_Desc,
'+#Cols1+'
FROM
(SELECT
CONCAT(ST.Code,'' - '', ST.Description_1) AS Item_Code_Desc,
STT.ActualQuantity AS Qty,
CONCAT(DATENAME(MONTH, STT.TxDate),'' '',YEAR(STT.TxDate)) AS [Period]
FROM
_bvSTTransactionsFull AS STT
INNER JOIN
StkItem AS ST ON STT.AccountLink = ST.StockLink
WHERE
STT.TxDate >= DATEADD(MONTH, '+#Period+', DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0))
AND STT.Module = ''AR'') AS P
PIVOT
(SUM(P.Qty)
FOR P.Period IN ('+#cols2+')
) AS PVT '
PRINT #Query
EXEC (#Query)
We have a table showing amounts (CHGCNT) for 3 dates (5-9-2016, 5-10-2016, 5-11-2016) for each store & Depts.
I want to be able to see the records in a table like this:
I already applied the following query
declare #dt as datetime
declare #dt1 as varchar(10)
declare #dt2 as varchar(10)
declare #dt3 as varchar(10)
select distinct #dt = min(effdt) from [HQExtract].[dbo].[FSM_PRICE_TAGCOUNT]
-- print CONVERT(CHAR(10), #dt, 110) + ' ---- ' + CONVERT(CHAR(10), #dt+1 , 110)
set #dt1 = CONVERT(CHAR(10), #dt, 110)
set #dt2 = CONVERT(CHAR(10), #dt +1 , 110)
set #dt3 = CONVERT(CHAR(10), #dt + 2 , 110)
--print #dt1 + ' ---- ' + #dt2 + '-----' + #dt3
SELECT DEPTNM, DEPT, [#dt1] , [#dt2] , [#dt3]
FROM [HQExtract].[dbo].[FSM_PRICE_TAGCOUNT]
PIVOT
(
SUM(CHGCNT)
FOR effdt IN ( [#dt1] , [#dt2] , [#dt3])
) AS P
but it is returning dates
I like the SUM-CASE approach:
SELECT deptnm,
SUM(CASE WHEN effdt = '2016-05-09' THEN chgcnt ELSE 0 END) "2016-05-09",
SUM(CASE WHEN effdt = '2016-05-10' THEN chgcnt ELSE 0 END) "2016-05-10",
SUM(CASE WHEN effdt = '2016-05-11' THEN chgcnt ELSE 0 END) "2016-05-11",
SUM(effdt) Total
FROM [HQExtract].[dbo].[FSM_PRICE_TAGCOUNT]
GROUP BY deptnm;
Here's my query (it's a part of stored procedure):
declare #sql varchar(4000)
declare #tab1 table (ActionID int, ActionDate datetime, [Group] varchar(10), GroupUnicode int, GroupList varchar(100), Artist varchar(250), PlaceName varchar(250),
ActionType varchar(25), ActionTypeID smallint, ActionPlaceID int, Picture varchar(512), SearchWords varchar(250), ActionEndDate datetime, StrEndDate varchar(250),
NameForH1 nvarchar(1000), DatesAsPeriod tinyint, DateList varchar(4000))
set #Date2 = DATEADD(day, 1, #Date2)
insert into #tab1(ActionID, ActionDate, Artist, PlaceName, ActionTypeID, ActionPlaceID, SearchWords, ActionEndDate, StrEndDate, NameForH1, DatesAsPeriod, DateList)
select X.ID, convert(datetime, SUBSTRING(X.DateList, 1, 19), 120), X.Artist, PlaceName, X.ActionTypeID, X.ActionPlaceID, X.SearchWords, ActionEndDate,
case when ActionEndDate IS NOT NULL AND convert(datetime, SUBSTRING(X.DateList, 1, 19), 120) < ActionEndDate
then ' - ' + convert(varchar, ActionEndDate, 104) + ' ' + convert(varchar(5), ActionEndDate, 108)
else '' end as StrEndDate, X.NameFOrH1, X.DatesAsPeriod, X.DateList
from (
SELECT DISTINCT
TOP (100) PERCENT a.ID, a.Artist, a.DateBeg, a.DateEnd, ap.PlaceName, a.ProviderID, a.SubSiteID, a.ActionPlaceID,
a.CounterAgentID, a.ActionTypeID, a.GenreTypeID, a.ShowTypeID AS ActionShowTypeID, ad.ShowTypeID, ap.CityID, a.ActionPlaceGroupID,
a.ActionTopTypeID, a.Canceled, a.ETicketEnabled, st.ShowOnMainPage AS ActionShowOnMainPage, st.ShowInActionList AS ActionShowInActionList,
st.ShowInCashdesk AS ActionShowInCashdesk, st1.ShowOnMainPage, st1.ShowInActionList, st1.ShowInCashdesk, a.SearchWords, a.AutoGenerate,
ad.ActionEndDate, a.NameForH1, a.CommonActionId, tca.Name AS CommonActionName, a.AgeRestrictionsId, a.DatesAsPeriod,
dbo.fn_ConvertActionDatesToDateList(a.ID) AS DateList
FROM dbo.T_Action AS a INNER JOIN
dbo.T_ActionDates AS ad ON a.ID = ad.ActionID INNER JOIN
dbo.T_ActionPlace AS ap ON a.ActionPlaceID = ap.ID INNER JOIN
dbo.T_ShowType AS st ON a.ShowTypeID = st.ID LEFT OUTER JOIN
dbo.T_ShowType AS st1 ON ad.ShowTypeID = st1.ID LEFT OUTER JOIN
dbo.T_CommonAction AS tca ON tca.ID = a.CommonActionId
WHERE (a.Visible = 1)) AS X INNER JOIN dbo.T_Action AS a ON X.ID = a.ID
where (ActionShowInActionList = 1) and (ShowInActionList = 1)
and ((X.Artist like '%' + #Artist + '%') or (X.SearchWords like '%' + #Artist + '%'))
and X.ActionTypeID = case when #ActionTypeID > 0 then #ActionTypeID else X.ActionTypeID end
and X.ActionTopTypeID = case when #ActionTopTypeID > 0 then #ActionTopTypeID else X.ActionTopTypeID end
and X.GenreTypeID = case when #GenreTypeID > 0 then #GenreTypeID else X.GenreTypeID end
and X.ActionPlaceID = case when #ActionPlaceID > 0 then #ActionPlaceID else X.ActionPlaceID end
and CityID = case when #CityID > 0 then #CityID else CityID end
and X.ActionPlaceGroupID = case when #GroupPlaceID > 0 then #GroupPlaceID else X.ActionPlaceGroupID end
and ((convert(datetime, SUBSTRING(X.DateList, 1, 19), 120) = '1980-01-01')
or ((convert(datetime, SUBSTRING(X.DateList, 1, 19), 120) >= #Date1 OR ActionEndDate >= #Date1) AND convert(datetime, SUBSTRING(X.DateList, 1, 19), 120) < #Date2))
order by
case when #SortBy = 'byPlace' then PlaceName end,
case when #SortBy = 'byDate' or #SortBy = 'byPlace' then case when convert(datetime, SUBSTRING(X.DateList, 1, 19), 120) = '1980-01-01 00:00' then DATEADD(YY, 1000, convert(datetime, SUBSTRING(X.DateList, 1, 19), 120)) else convert(datetime, SUBSTRING(X.DateList, 1, 19), 120) end end, Artist,
case when #SortBy = 'byAlphabet' then convert(datetime, SUBSTRING(X.DateList, 1, 19), 120) end
As you can see, there is nested query and there is the following construction:
convert(datetime, SUBSTRING(X.DateList, 1, 19), 120)
that repeats several times.
Also, there is the function dbo.fn_ConvertActionDatesToDateList(a.ID):
ALTER FUNCTION [fn_ConvertActionDatesToDateList]
(
#actionId int
)
RETURNS varchar(4000)
AS
BEGIN
declare #dateList varchar(4000)
select distinct #dateList = STUFF(CAST((
SELECT [text()] = ', ' + convert(varchar, ActionDate, 120)
FROM T_ActionDates where ActionID = a.ID and (ActionDate = '1980-01-01' or ActionDate > GETDATE())
FOR XML PATH(''), TYPE) AS VARCHAR(8000)), 1, 2, '') from T_Action as a join T_ActionDates as ad on a.ID = ad.ActionID
where (ad.ActionDate = '1980-01-01' or ad.ActionDate > GETDATE()) and Visible = 1 and CloseForCorrect = 0 and a.ID = #actionId
return #dateList
END
How can I speed it up?
I really can't tell you exactly what to do to fix the issue, but I can point out the spots that are almost certainly causing slow down.
Ensure your columns in all the joins and WHERE clauses are indexed. There is no way for anyone here to know what is and is not indexed unless you tell us.
The sub-select has TOP (100) PERCENT. You should not need this.
You are generating a likely large sub-set of data by having the sub-select without the improving the WHERE clause in the sub-select. It looks like the WHERE in the main select should be moved into the subselect.
Get rid of the sub-select.
With those things said, try this:
declare #sql varchar(4000)
declare #tab1 table (ActionID int, ActionDate datetime, [Group] varchar(10), GroupUnicode int, GroupList varchar(100), Artist varchar(250), PlaceName varchar(250),
ActionType varchar(25), ActionTypeID smallint, ActionPlaceID int, Picture varchar(512), SearchWords varchar(250), ActionEndDate datetime, StrEndDate varchar(250),
NameForH1 nvarchar(1000), DatesAsPeriod tinyint, DateList varchar(4000))
set #Date2 = DATEADD(day, 1, #Date2)
insert into #tab1(ActionID, ActionDate, Artist, PlaceName, ActionTypeID, ActionPlaceID, SearchWords, ActionEndDate, StrEndDate, NameForH1, DatesAsPeriod, DateList)
select
X.ID, convert(datetime, SUBSTRING(X.DateList, 1, 19), 120), X.Artist, PlaceName, X.ActionTypeID, X.ActionPlaceID, X.SearchWords, ActionEndDate,
case
when ActionEndDate IS NOT NULL AND convert(datetime, SUBSTRING(X.DateList, 1, 19), 120) < ActionEndDate
then ' - ' + convert(varchar, ActionEndDate, 104) + ' ' + convert(varchar(5), ActionEndDate, 108)
else ''
end as StrEndDate
, X.NameFOrH1, X.DatesAsPeriod, X.DateList
from (
SELECT DISTINCT
a.ID, a.Artist, a.DateBeg, a.DateEnd, ap.PlaceName, a.ProviderID, a.SubSiteID, a.ActionPlaceID,
a.CounterAgentID, a.ActionTypeID, a.GenreTypeID, a.ShowTypeID AS ActionShowTypeID, ad.ShowTypeID, ap.CityID, a.ActionPlaceGroupID,
a.ActionTopTypeID, a.Canceled, a.ETicketEnabled, st.ShowOnMainPage AS ActionShowOnMainPage, st.ShowInActionList AS ActionShowInActionList,
st.ShowInCashdesk AS ActionShowInCashdesk, st1.ShowOnMainPage, st1.ShowInActionList, st1.ShowInCashdesk, a.SearchWords, a.AutoGenerate,
ad.ActionEndDate, a.NameForH1, a.CommonActionId, tca.Name AS CommonActionName, a.AgeRestrictionsId, a.DatesAsPeriod,
dbo.fn_ConvertActionDatesToDateList(a.ID) AS DateList
FROM dbo.T_Action AS a
INNER JOIN dbo.T_ActionDates AS ad ON a.ID = ad.ActionID
INNER JOIN dbo.T_ActionPlace AS ap ON a.ActionPlaceID = ap.ID
INNER JOIN dbo.T_ShowType AS st ON a.ShowTypeID = st.ID
LEFT OUTER JOIN dbo.T_ShowType AS st1 ON ad.ShowTypeID = st1.ID
LEFT OUTER JOIN dbo.T_CommonAction AS tca ON tca.ID = a.CommonActionId
WHERE a.Visible = 1
AND ActionShowInActionList = 1
and (ShowInActionList = 1)
and (
(Artist like '%' + #Artist + '%')
or (SearchWords like '%' + #Artist + '%')
)
and ActionTypeID = case when #ActionTypeID > 0 then #ActionTypeID else ActionTypeID end
and ActionTopTypeID = case when #ActionTopTypeID > 0 then #ActionTopTypeID else ActionTopTypeID end
and GenreTypeID = case when #GenreTypeID > 0 then #GenreTypeID else GenreTypeID end
and ActionPlaceID = case when #ActionPlaceID > 0 then #ActionPlaceID else ActionPlaceID end
and CityID = case when #CityID > 0 then #CityID else CityID end
and ActionPlaceGroupID = case when #GroupPlaceID > 0 then #GroupPlaceID else ActionPlaceGroupID end
and (
convert(datetime, SUBSTRING(DateList, 1, 19), 120) = '1980-01-01'
or (
(
convert(datetime, SUBSTRING(DateList, 1, 19), 120) >= #Date1
OR ActionEndDate >= #Date1
)
AND convert(datetime, SUBSTRING(DateList, 1, 19), 120) < #Date2
)
)
) AS X
order by
case when #SortBy = 'byPlace' then PlaceName end,
case when #SortBy = 'byDate' or #SortBy = 'byPlace' then case when convert(datetime, SUBSTRING(X.DateList, 1, 19), 120) = '1980-01-01 00:00' then DATEADD(YY, 1000, convert(datetime, SUBSTRING(X.DateList, 1, 19), 120)) else convert(datetime, SUBSTRING(X.DateList, 1, 19), 120) end end, Artist,
case when #SortBy = 'byAlphabet' then convert(datetime, SUBSTRING(X.DateList, 1, 19), 120) end
I have used a tool to convert PL/SQL to TSQL but I am getting weird errors for some cases.
CREATE PROC Dates
(
#PeriodType varchar(15),
#ReportStart varchar(15),
#ReportEnd varchar(15)
)
AS
BEGIN
SELECT CASE
WHEN #PeriodType = 'CUR_WEEK' THEN CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() + 1 - CONVERT(NUMERIC(8, 2), CONVERT(VARCHAR(23), GETDATE())), 112))
WHEN #PeriodType = 'NEXT_WEEK' THEN CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() + 8 - CONVERT(NUMERIC(8, 2), CONVERT(VARCHAR(23), GETDATE())), 112))
WHEN #PeriodType = 'PREV_DAY' THEN CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() - 1, 112))
WHEN #PeriodType = 'PREV_WEEK' THEN CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() - 6 - CONVERT(NUMERIC(8, 2), CONVERT(VARCHAR(23), GETDATE())), 112))
WHEN #PeriodType = 'PREV_2WEEK' THEN CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() - 13, 112))
WHEN #PeriodType = 'CUR_MONTH' THEN CONVERT(DATETIME, CAST(CONVERT(VARCHAR(23), GETDATE()) AS VARCHAR) + '01', 112)
WHEN #PeriodType = 'DATE_RANGE' THEN CONVERT(DATETIME, #ReportStart)
END AS "StartDate",
CASE
WHEN #PeriodType = 'CUR_WEEK' THEN CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() + 8 - CONVERT(NUMERIC(8, 2), CONVERT(VARCHAR(23), GETDATE())), 112)) - (1 / CONVERT(FLOAT, 86400))
WHEN #PeriodType = 'NEXT_WEEK' THEN CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() + 15 - CONVERT(NUMERIC(8, 2), CONVERT(VARCHAR(23), GETDATE())), 112)) - (1 / CONVERT(FLOAT, 86400))
WHEN #PeriodType = 'PREV_DAY' THEN CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE(), 112)) - (1 / CONVERT(FLOAT, 86400))
WHEN #PeriodType = 'PREV_WEEK' THEN CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() - CONVERT(NUMERIC(8, 2), CONVERT(VARCHAR(23), GETDATE())), 112)) + 1 - (1 / CONVERT(FLOAT, 86400))
WHEN #PeriodType = 'PREV_2WEEK' THEN CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() + 1, 112)) - (1 / CONVERT(FLOAT, 86400))
WHEN #PeriodType = 'CUR_MONTH' THEN DATEADD(M, 1, CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE(), 112)) - (CONVERT(NUMERIC(8, 2), DATEPART(DD, GETDATE())) - 1)) - 1
WHEN #PeriodType = 'DATE_RANGE' THEN CONVERT(DATETIME, #ReportEnd) + 1
END AS "EndDate"
END
My stored proc is executing for PREV_DAY and PREV_2WEEK for the remaining period type I am getting conversions errors.
exec proc Dates 'PREV_DAY','',''
exec proc Dates 'PREV_2WEEK','',''
My PL\SQL code is
SELECT CASE
WHEN :PeriodType = 'CUR_WEEK'
THEN TRUNC(SYSDATE + 1 - TO_NUMBER(TO_CHAR(SYSDATE, 'D')))
WHEN :PeriodType = 'NEXT_WEEK'
THEN TRUNC(SYSDATE + 8 - TO_NUMBER(TO_CHAR(SYSDATE, 'D')))
WHEN :PeriodType = 'PREV_DAY'
THEN TRUNC(SYSDATE - 1)
WHEN :PeriodType = 'PREV_WEEK'
THEN TRUNC(SYSDATE - 6 - TO_NUMBER(TO_CHAR(SYSDATE, 'D')))
WHEN :PeriodType = 'PREV_2WEEK'
THEN TRUNC(SYSDATE - 13)
WHEN :PeriodType = 'CUR_MONTH'
THEN to_date(to_char(sysdate,'YYYYMM') || '01','YYYYMMDD')
WHEN :PeriodType = 'DATE_RANGE'
THEN TO_DATE(:ReportStart)
END AS "StartDate",
CASE
WHEN :PeriodType = 'CUR_WEEK'
THEN TRUNC(SYSDATE + 8 - TO_NUMBER(TO_CHAR(SYSDATE, 'D'))) - (1/86400)
WHEN :PeriodType = 'NEXT_WEEK'
THEN TRUNC(SYSDATE + 15 - TO_NUMBER(TO_CHAR(SYSDATE, 'D'))) - (1/86400)
WHEN :PeriodType = 'PREV_DAY'
THEN TRUNC(SYSDATE)-(1/86400)
WHEN :PeriodType = 'PREV_WEEK'
THEN TRUNC(SYSDATE - TO_NUMBER(TO_CHAR(SYSDATE, 'D'))) + 1 - (1/86400)
WHEN :PeriodType = 'PREV_2WEEK'
THEN TRUNC ( SYSDATE+1) - (1/86400)
WHEN :PeriodType = 'CUR_MONTH'
THEN ADD_MONTHS(TRUNC(SYSDATE) - (TO_NUMBER(TO_CHAR(SYSDATE,'DD')) - 1), 1) -1
WHEN :PeriodType = 'DATE_RANGE'
THEN TO_DATE(:ReportEnd)+1
END AS "EndDate"
FROM DUAL
At least one problem is this expression in the first then clause:
CONVERT(NUMERIC(8, 2), CONVERT(VARCHAR(23), GETDATE()))
This expression:
select CONVERT(VARCHAR(23), GETDATE())
just returned:
May 23 2014 3:01AM
And that just won't convert to numeric.
I think you need to go through the code line by line to figure out the best way to do things. Also, whenever you use varchar or char, you should have a length associated with them. The default is sometimes (but not always) 1, and that can cause problems.
Oracle and SQLServer work with datetime in different manner.
The tool converted the script as well as a string parser can, like someone translating a quote word by word between two languages.
In SQLServer to work with that data type you have to use the functions DATEADD, DATEDIFF and other ones that can be found on the help page from MS.
Using the date function of SQLServer the original function translate to
CREATE PROC Dates(
#PeriodType varchar(15),
#ReportStart varchar(15),
#ReportEnd varchar(15)
)
AS
BEGIN
SELECT CASE WHEN #PeriodType = 'CUR_WEEK' THEN DATEADD(DAY, - DATEPART(dw, GETDATE()) + 1, cast(cast(GETDATE() AS date) AS datetime))
WHEN #PeriodType = 'NEXT_WEEK' THEN DATEADD(DAY, 8 - DATEPART(dw, GETDATE()), cast(cast(GETDATE() AS date) AS datetime))
WHEN #PeriodType = 'PREV_DAY' THEN DATEADD(DAY, -1, cast(cast(GETDATE() AS date) AS datetime))
WHEN #PeriodType = 'PREV_WEEK' THEN DATEADD(DAY, - DATEPART(dw, GETDATE()) - 6, cast(cast(GETDATE() AS date) AS datetime))
WHEN #PeriodType = 'PREV_2WEEK' THEN DATEADD(DAY, - 13, cast(cast(GETDATE() AS date) AS datetime))
WHEN #PeriodType = 'CUR_MONTH' THEN DATEADD(DAY, - DATEPART(DAY, GETDATE()) + 1, cast(cast(GETDATE() AS date) AS datetime))
WHEN #PeriodType = 'DATE_RANGE' THEN CONVERT(DATETIME, #ReportStart)
END AS StartDate,
, CASE WHEN #PeriodType = 'CUR_WEEK' THEN DATEADD(mi, -1, DATEADD(DAY, 8 - DATEPART(dw, GETDATE()), cast(cast(GETDATE() AS date) AS datetime)))
WHEN #PeriodType = 'NEXT_WEEK' THEN DATEADD(mi, -1, DATEADD(DAY, 15 - DATEPART(dw, GETDATE()), cast(cast(GETDATE() AS date) AS datetime)))
WHEN #PeriodType = 'PREV_DAY' THEN DATEADD(mi, -1, DATEADD(DAY, - DATEPART(dw, GETDATE()) + 1, cast(cast(GETDATE() AS date) AS datetime)))
WHEN #PeriodType = 'PREV_WEEK' THEN DATEADD(mi, -1, DATEADD(DAY, 8 - DATEPART(dw, GETDATE()), cast(cast(GETDATE() AS date) AS datetime)))
WHEN #PeriodType = 'PREV_2WEEK' THEN DATEADD(mi, -1, cast(cast(dateadd(DAY, 1, GETDATE()) AS date) AS datetime))
WHEN #PeriodType = 'CUR_MONTH' THEN DATEADD(DAY, -1, DATEADD(mm, DATEDIFF(mm, 0, cast(cast(GETDATE() AS date) AS datetime))+1,0))
WHEN #PeriodType = 'DATE_RANGE' THEN CONVERT(DATETIME, #ReportEnd) + 1
END AS EndDate
END
The double CAST in CAST(CAST(GETDATE() AS DATE) AS DATETIME) is a little hack to get midnight of today, as GETDATE() is of datetime type and returns the current date and time.
I have this SQL now:
CREATE PROCEDURE dbo.sel_Track_HitsLast30Days(
#projectID int
)
AS
BEGIN
DECLARE #FirstDay smalldatetime, #NumberOfMonths int, #priorMonth smalldatetime
set #priorMonth = (SELECT CAST(
(
STR( YEAR( dateadd(m,-1, getDate()) ) ) + '/' +
STR( MONTH( dateadd(m,-1, getDate()) ) ) + '/' +
STR( DAY( dateadd(m,-1, getDate()) ) )
)
AS DateTime
))
Select #FirstDay = #priorMonth, #NumberOfMonths = 1
;WITH Days AS (
SELECT #FirstDay as CalendarDay
UNION ALL
SELECT DATEADD(d, 1, CalendarDay) as CalendarDay
FROM Days
WHERE DATEADD(d, 1, CalendarDay) < DATEADD(m, #NumberOfMonths, #FirstDay+1)
)
SELECT calendarday,foundDate.TotalbyDate,foundDate.date FROM Days
LEFT OUTER JOIN (
SELECT
COUNT(LEFT(visitDateTime, 11)) AS TotalbyDate,substring(convert( char(10), CONVERT( char(10), visitDateTime, 121 ) ), 1, 11) AS date
FROM
dbo.TrackingData
WHERE
visitDateTime >= dateadd(d, datediff(d, 0, getdate()), -30) and projectID = #projectID
GROUP BY substring(convert( char(10), CONVERT( char(10), visitDateTime, 121 ) ), 1, 11)
) foundDate on foundDate.date = CalendarDay
order by
CalendarDay Desc
END
This works ok, but It is not taking into account months with 31 days and I am not getting back today's date for some reason.
Try this (using AdventureWorks as sample database)
DECLARE #today datetime, #NumberOfMonths int, #FirstDay smalldatetime
SELECT #today = '2004-03-09', -- getdate(), tests only
#NumberOfMonths = 1,
#FirstDay = CAST(FLOOR(CAST(
DATEADD(M, -1, #today) AS float)) AS datetime);
WITH Days AS
(
SELECT #FirstDay AS CalendarDay UNION ALL
SELECT DATEADD(d, 1, CalendarDay) AS CalendarDay FROM Days
WHERE DATEADD(d, 1, CalendarDay) < DATEADD(m, #NumberOfMonths, #FirstDay+1)
)
SELECT CONVERT(varchar(10), CalendarDay, 111) as [Date],
COUNT(TransactionDate) as [Count]
FROM Days LEFT JOIN Production.TransactionHistory
ON TransactionDate = Days.CalendarDay
GROUP BY CalendarDay
ORDER BY CalendarDay
Will output
Date Count
---------- -----------
2004/02/09 272
2004/02/10 308
2004/02/11 264
2004/02/12 265
2004/02/13 250
...
EDIT: Updated to include all interval dates
HEre is a modified version of Ruben's answer:
DECLARE #today DATETIME,
#firstDayLastMonth DATETIME,
#daysCount int
SET #today = getDate()
SET #firstDayLastMonth = Dateadd(m,-1,Dateadd(d,-Day(#today) + 1,#today))
Set #daysCount = (select datepart(dd,dateadd(dd,-1,dateadd(mm,1,cast(cast(year(#firstDayLastMonth) as varchar)+'-'+cast(month(#firstDayLastMonth) as varchar)+'-01' as datetime)))))
SELECT substring(convert( char(10), CONVERT( char(10), visitDateTime, 121 ) ), 1, 11) AS [Date], Count(* ) AS [Count]
FROM dbo.TrackingData
WHERE visitdatetime >= Dateadd(d,-#daysCount,#today)
GROUP BY substring(convert( char(10), CONVERT( char(10), visitDateTime, 121 ) ), 1, 11)
ORDER BY substring(convert( char(10), CONVERT( char(10), visitDateTime, 121 ) ), 1, 11)
OK, I got it. Rubens gave me an idea so I modified my SQL like so:
DECLARE #FirstDay SMALLDATETIME,
#NumberOfMonths INT,
#priorMonth SMALLDATETIME,
#firstDayLastMonth DateTime,
#daysCount int
set #firstDayLastMonth = dateadd(m, -1, dateadd(d, -day(getDate()) + 1, getDate()))
set #daysCount = (select datepart(dd,dateadd(dd,-1,dateadd(mm,1,cast(cast(year(#firstDayLastMonth) as varchar)+'-'+cast(month(#firstDayLastMonth) as varchar)+'-01' as datetime)))))
SET #priorMonth = (SELECT Cast((Str(Year(Dateadd(m,-1,Getdate()))) + '/' + Str(Month(Dateadd(m,-1,Getdate()))) + '/' + Str(Day(Dateadd(m,-1,Getdate())))) AS DATETIME))
Declare #before dateTime
Set #before = Dateadd(d,-#daysCount,getdate())
SELECT #FirstDay = #before,
#NumberOfMonths = 1;
WITH days
AS (SELECT #FirstDay AS calendarday
UNION ALL
SELECT Dateadd(d,1,calendarday) AS calendarday
FROM days
WHERE Dateadd(d,1,calendarday) <= Dateadd(m,#NumberOfMonths,#FirstDay))
SELECT Substring(Convert(CHAR(10),Convert(CHAR(10),calendarday,101)),
1,11) ,
founddate.totalbydate,
founddate.DATE
FROM days
LEFT OUTER JOIN (SELECT Count(Left(visitdatetime,11)) AS totalbydate,
Substring(Convert(CHAR(10),Convert(CHAR(10),visitdatetime,101)),
1,11) AS DATE
FROM dbo.trackingdata
WHERE visitdatetime >= Dateadd(d,Datediff(d,0,Getdate()),-29)
AND projectid = 131
GROUP BY Substring(Convert(CHAR(10),Convert(CHAR(10),visitdatetime,101)),
1,11)) founddate
ON founddate.DATE = Substring(Convert(CHAR(10),Convert(CHAR(10),calendarday,101)),
1,11)