This executes correctly: (It is weird that I needed to use '' by the date for it to actually execute)
DECLARE
#cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.statcolumnname) FROM [85137_PHY_Long_PG] c FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')
set #query = 'SELECT statdate, ' + #cols + ' from
(
select statdate, statcolumnname, statcolumnvalue
from [85137_PHY_Long_PG]
) x
pivot
(
min(statcolumnvalue)
for statcolumnname in (' + #cols + ')
) p WHERE statdate BETWEEN ''2012-04-01 12:15:00'' AND ''2012-04-01 12:45:00'' ORDER BY statdate'
execute(#query)
Now I want to replace the dates with variables:
DECLARE
#cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#from AS NVARCHAR(MAX),
#to AS NVARCHAR(MAX);
set #from = '2012-04-01 12:15:00'
set #to = '2012-04-01 12:45:00'
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.statcolumnname) FROM [85137_PHY_Long_PG] c FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')
set #query = 'SELECT statdate, ' + #cols + ' from
(
select statdate, statcolumnname, statcolumnvalue
from [85137_PHY_Long_PG]
) x
pivot
(
min(statcolumnvalue)
for statcolumnname in (' + #cols + ')
) p WHERE statdate BETWEEN ''+#from+'' AND ''+#to+'' ORDER BY statdate'
execute(#query)
I get the following error:Conversion failed when converting character string to smalldatetime data type
Changing the where statement to the following:
WHERE statdate BETWEEN ''+convert(smalldatetime,#from)+'' AND ''+convert(smalldatetime,#to)+'' ORDER BY statdate'
Still gives me the same error, just can't seem to replace the dates as variables
'' is not weird; it is a notation that enables apostrophes inside varchars.
When concatenating make sure that you are not trying to concatenate anything other than (n)varchars and (n)chars because Sql Server will attempt to convert them to other datatypes; in your case, in smalldatetime. You might avoid this trouble by explicitly converting your parameter dates to nvarchars before/during concatenation, but better solution is to use sp_executesql and parameters.
If you leave parameters inside query:
set #query = 'SELECT statdate, ' + #cols + ' from
(
select statdate, statcolumnname, statcolumnvalue
from [85137_PHY_Long_PG]
) x
pivot
(
min(statcolumnvalue)
for statcolumnname in (' + #cols + ')
) p WHERE statdate BETWEEN #from AND #to ORDER BY statdate'
You can execute it with parameters:
exec sp_executesql #query, N'#from datetime, #to datetime', #from=#from_variable, #to=#to_variable
Where #from_variable and #to_variable are datetime variables defined earlier in batch.
UPDATE:
If your ultimate goal is to wrap this code in stored procedure, here is a template:
create proc MyProc (#dateFrom smalldatetime, #dateTo smalldatetime)
as
DECLARE
#cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.statcolumnname)
FROM [85137_PHY_Long_PG] c
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')
set #query = 'SELECT statdate, ' + #cols + ' from
(
select statdate, statcolumnname, statcolumnvalue
from [85137_PHY_Long_PG]
) x
pivot
(
min(statcolumnvalue)
for statcolumnname in (' + #cols + ')
) p WHERE statdate BETWEEN #from AND #to ORDER BY statdate'
exec sp_executesql #query, N'#from smalldatetime, #to smalldatetime', #from=#dateFrom, #to=#dateTo
Herewith the solution:
DECLARE
#cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#internal_fromdate AS SMALLDATETIME,
#internal_todate AS SMALLDATETIME;
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.statcolumnname) FROM [85137_PHY_Long_PG] c FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')
set #internal_fromdate = '2012-04-01 12:15:00';
set #internal_todate = '2012-04-01 12:45:00';
set #query = 'SELECT statdate, ' + #cols + ' from
(
select statdate, statcolumnname, statcolumnvalue
from [85137_PHY_Long_PG]
) x
pivot
(
min(statcolumnvalue)
for statcolumnname in (' + #cols + ')
) p WHERE statdate BETWEEN #FromDate AND #ToDate ORDER BY statdate'
exec sp_executesql #query, N'#FromDate SMALLDATETIME, #ToDate SMALLDATETIME', #FromDate=#internal_fromdate, #ToDate=#internal_todate
UPDATE
Ok, I have tried the following variations:
create proc MyProc9 (#tableName varchar,#dateFrom smalldatetime, #dateTo smalldatetime)
AS
DECLARE
#cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.statcolumnname)
FROM [85137_PHY_Long_MP] c
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')
set #query = 'SELECT statdate, ' + #cols + ' from
(
SELECT statdate, statcolumnname, statcolumnvalue
from #table
) x
pivot
(
min(statcolumnvalue)
for statcolumnname in (' + #cols + ')
) p WHERE statdate BETWEEN #from AND #to ORDER BY statdate'
exec sp_executesql #query, N'#table varchar,#from smalldatetime, #to smalldatetime', #table=#tableName,#from=#dateFrom, #to=#dateTo
Error: Must declare the table variable "#table".
Tried '+#tableName+' in the #query string: Incorrect syntax near '8'.
Tried '+QUOTENAME(#tableName)+' in the #query string: Invalid object name '8'.
Tried ['+#tableName+'] in the #query string: Invalid object name '8'.
Tried QUOTENAME(#table) in the #query string: Invalid object name '8'.
Tried [85137_PHY_Long_MP] in the #query string: Works correctly, just want to replace this.
Tried [#tableName] in the #query string: Invalid object name '#tableName'.
Tried #tableName in the #query string: Must declare the table variable "#tableName".
I don't understand how to resolve the problem
Related
I'm trying to use the results from this dynamic SQL statement, to create a new table
DECLARE #cols NVARCHAR(MAX), #query NVARCHAR(MAX);
SET #cols = STUFF((SELECT DISTINCT
',' + QUOTENAME(c.[ClassCode])
FROM [Sandbox].[dbo].Test2 c
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, '');
SET #query = 'SELECT [Name_ID], ' + #cols +
'FROM (SELECT [Name_ID],
[ClassCodeYN] AS [amount],
[ClassCode] AS [category]
FROM [Sandbox].[dbo].[Test2]) x
PIVOT (COUNT(amount) FOR category IN (' + #cols + ')) p';
EXECUTE #query
I've tried to use INSERT INTO and CREATE TABLE and get either
Incorrect syntax near the keyword 'EXECUTE'
or
Must DECLARE #query
errors.
You should be able to just add into <table> to your existing query:
DECLARE #cols NVARCHAR(MAX), #query NVARCHAR(MAX);
SET #cols = STUFF((SELECT DISTINCT
',' + QUOTENAME(c.[ClassCode])
FROM [Sandbox].[dbo].Test2 c
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, '');
SET #query = 'SELECT [Name_ID], ' + #cols +
' INTO MyTable' +
' FROM (SELECT [Name_ID],
[ClassCodeYN] AS [amount],
[ClassCode] AS [category]
FROM [Sandbox].[dbo].[Test2]) x
PIVOT (COUNT(amount) FOR category IN (' + #cols + ')) p';
Exec sp_executesql #query
I have a dynamic stored procedure which runs in SSMS. Is it possible to convert this proc into a function so when ever I do
exec function stored.proc
I can run this from my ETL?
My query as below -
create procedure dbo.bear_load
as
set nocount on;
Declare #cols as NVARCHAR(MAX), #query as NVARCHAR(MAX), #Result as NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(FIELD_NAME)
from bear_crossjoin
group by Field_Name, FIELDNUMBER
order by FIELDNUMBER
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = N'SELECT ' + #cols + N'
from
(
select substring, Field_Name,
rn = row_number() over(partition by field_name order by fieldnumber)
from bear_crossjoin
) x
pivot
(
max(substring)
for Field_Name in (' + #cols + N')
) p '
set #Result= ' select ' + #query
EXEC (#query)
GO
exec dbo.bear_load
Any help very much appreciated.
Arun
SELECT *
FROM (
SELECT [TM_UserID],
[FullName],
[Worked_dte],
[Worked_Hours]
FROM #Reporting_User_Timesheet
WHERE [worked_dte] BETWEEN '2014-04-04'
AND '2014-04-06'
) AS sourceTable
Pivot(sum([Worked_Hours]) FOR [Worked_dte] IN ([2014-04-04], [2014-04-05], [2014-04-06])) AS PivotTable
A shot in the dark, obviously, but here's how I understood your question.
First, you need a calendar table to get the dates for the range:
http://www.dbdelta.com/calendar-table-and-datetime-functions/
After that, construct the needed PIVOT query and execute it dynamically:
declare #range_start date, #range_end date;
select #range_start = '20140404', #range_end = '20140406';
declare #collist nvarchar(max);
SET #collist = stuff((select distinct ',' + QUOTENAME(convert(varchar,date,112))
FROM calendar
WHERE Datue BETWEEN #range_start AND #range_end
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'');
declare #q nvarchar(max);
set #q = '
SELECT *
FROM (
SELECT [TM_UserID],
[FullName],
[Worked_dte],
[Worked_Hours]
FROM #Reporting_User_Timesheet
WHERE [worked_dte] BETWEEN ''' + CONVERT(varchar, #range_start, 112) + '''
AND ''' + CONVERT(varchar, #range_end, 112) + '''
) AS sourceTable
Pivot (
sum([Worked_Hours]) FOR [Worked_dte] IN (' + #collist + ')
) AS PivotTable
';
exec (#q);
Is it possible to exclude some vaules from the PIVOT results.
Referencing this question i would like to know if it is posible to exclude the columns in the Pivot table that has 0 value.
Imagine there is a count of 0 for EventType Meeting, is it possible not to show it at all?
i hope you have implemented following solution from the question
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(EventType)
from dbo.testTable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT year,' + #cols + '
from
(
select EventType,
year = year(date)
from dbo.testTable
) x
pivot
(
count(EventType)
for EventType in (' + #cols + ')
) p '
execute(#query)
if so then you can do following
DECLARE #cols AS NVARCHAR(MAX),
#where AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(EventType)
from dbo.testTable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #where = ' where ' + STUFF((SELECT distinct ' Or ' + QUOTENAME(EventType) + ' <> 0 '
from dbo.testTable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,2,3,'')
set #query = 'SELECT year,' + #cols + '
from
(
select EventType,
year = year(date)
from dbo.testTable
) x
pivot
(
count(EventType)
for EventType in (' + #cols + ')
) p ' + #where
execute(#query)
alter procedure [dbo].[ParkingDeatailsReport]
#locid INTEGER, #startdate nvarchar(100),#enddate nvarchar(100)
as
begin
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(Vtype)
from VType_tbl FOR XML PATH(''),
TYPE).value('.', 'NVARCHAR(MAX)') ,1,1,'')
set #query = 'SELECT Date, ' + #cols + '
from ( select v.Vtype, convert(date, dtime) as Date
from Transaction_tbl t inner join VType_tbl v
on t.vtid = v.vtid
where dtime between #startdate and #enddate
and locid = ' + CAST(#locid as varchar(max))
+ ' ) d pivot ( count(Vtype) for Vtype in (' + #cols + ') ) p '
execute(#query)
end
I am trying to execute like this:
exec ParkingDeatailsReport 5, '2013-01-01 00:00:00','2013-06-18 23:59:59'
but, I'm getting an error:Must declare the scalar variable "#startdate".
The problem is that you are building SQL in the proc, but you are not using the values in #startdate and #enddate, instead you are passing the string
You need to grab the values of these variables when you build the string - something like:
ALTER PROCEDURE [dbo].[ParkingDeatailsReport]
#locid INTEGER,
#startdate nvarchar(100),
#enddate nvarchar(100)
as
BEGIN
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SELECT #cols = STUFF((SELECT distinct ',' + QUOTENAME(Vtype)
from VType_tbl FOR XML PATH(''),
TYPE).value('.', 'NVARCHAR(MAX)') ,1,1,'')
SET #query = 'SELECT Date, ' + #cols + '
FROM (
SELECT
v.Vtype,
convert(date, dtime) as Date
FROM Transaction_tbl t
INNER JOIN VType_tbl v
ON t.vtid = v.vtid
WHERE
dtime between ''' + #startdate + ''' and ''' + #enddate + '''
AND locid = ' + CAST(#locid as varchar(max)) + '
) d
PIVOT ( count(Vtype)
FOR Vtype in (' + #cols + ') ) p '
EXECUTE(#query)
END