Pivot Rows to Columns Dynamically - SQL - sql

/****** Script for SelectTopNRows command from SSMS ******/
declare #ActivityYear int = 2014
declare #ActivityYear1 int = 2015
declare #ActivityMonth int = 1
declare #ActivityMonth1 int = 3
Select FinancialCategory, ID, (CONVERT(varchar(5), ActivityMonth) + '-'
+ CONVERT(varchar(5), ActivityYear)) As [Month-Year], Sum(HoursCharged) As [Hours]
FROM Forecast
where (ActivityMonth between #ActivityMonth and #ActivityMonth1)
AND (ActivityYear between #ActivityYear and #ActivityYear1)
AND FinancialCategory = 'Forecast'
Group By FinancialCategory, ID,ActivityMonth, ActivityYear
This Outputs a table that looks like this:
And I would like to transpose it to have the hours for each ID broken out by the dates in the range. Note: this range of dates will be dynamic, I set initial dates for testing purposes.

I learnt a bit about dynamic pivot recently, this post helped a lot. As a practice I converted yours, which I think would look like this, but isn't tested as I haven't time tcreate tables etc at the moment. HTH.
declare #ActivityYear int = 2014
declare #ActivityYear1 int = 2015
declare #ActivityMonth int = 1
declare #ActivityMonth1 int = 3
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME((CONVERT(varchar(5), ActivityMonth) + '-'
+ CONVERT(varchar(5), ActivityYear)))
FROM Forecast
WHERE (ActivityMonth between #ActivityMonth and #ActivityMonth1)
AND (ActivityYear between #ActivityYear and #ActivityYear1)
AND FinancialCategory = 'Forecast'
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT FinancialCategory, ID, ' + #cols + ' FROM
(
SELECT FinancialCategory, ID, (CONVERT(varchar(5), ActivityMonth) + ''-''
+ CONVERT(varchar(5), ActivityYear)) As [Month-Year],HoursCharged
FROM Forecast
WHERE (ActivityMonth between ' + #ActivityMonth + ' and ' + #ActivityMonth1 + ')
AND (ActivityYear between ' + #ActivityYear + ' and ' +
#ActivityYear1 + ')
AND FinancialCategory = ''Forecast''
) x
PIVOT
(
Sum(HoursCharged)
for (CONVERT(varchar(5), ActivityMonth) + ''-''
+ CONVERT(varchar(5), ActivityYear)) in (' + #cols + ')
) p '
execute(#query)

Related

Conversion failed when converting date and/or time from character string SQL Server 2012

Pivoting a table using a stored procedure in SQL Server 2012, I get the error. I have provided the stored procedure code:
CREATE PROCEDURE [dbo].[sp_Report_SalesJournal]
(#fromDate DATETIME,
#toDate DATETIME,
#locationId INT)
AS
BEGIN
DECLARE #cols AS NVARCHAR(MAX) = '';
DECLARE #query AS NVARCHAR(MAX) = '';
SELECT #cols = #cols + QUOTENAME(AccountName) + ','
FROM
(SELECT DISTCINT AccountName
FROM vw_SalesJournal
) AS tmp
SELECT #cols = SUBSTRING(#cols, 0, LEN(#cols))
SET #query =
'SELECT * from
(
select InvoiceDate, TransactionNumber, CustomerName, Amount, AccountName from vw_SalesJournal Where (InvoiceDate BETWEEN convert(date,' + #fromDate + ',105) AND convert(date,' + #toDate + ',105)) OR LocationId=' + #locationId + '
) src
pivot
(
max(Amount) for AccountName in (' + #cols + ')
) piv'
I have already gone through and also tried some of the answers provided on similar post.
you need to convert your date to string (with format YYYYMMDD) and enclose the date string in single quote before concatenate
BETWEEN ''' + convert(varchar(10), #fromDate, 121) + ''' AND

Conversion failed when converting date and/or time from character string while Pivot

I have the following SQL query:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#OID AS NVARCHAR(MAX) = '(105, 106)',
#startDate DATETIME = DATETIMEFROMPARTS(2017, 11, 01, 17, 0, 0, 0),
#endDate DATETIME = DATETIMEFROMPARTS(2017, 11, 25, 17, 0, 0, 0)
SELECT #cols = STUFF((SELECT ',' + QUOTENAME(Point)
FROM Value
GROUP BY Point
ORDER BY Point
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
SET #query = 'SELECT timestamp,' + #cols + ' from
(
select timestamp, point, valuenumeric
from value where point in ' + #OID + ' and Timestamp between ' +
#startDate + ' and ' + #endDate + '
) x
pivot
(
avg(valuenumeric)
for point in (' + #cols + ')
) p '
execute(#query);
But I am getting this error:
Msg 241, Level 16, State 1, Line 16
Conversion failed when converting date and/or time from character string.
The issue is not in these lines, the issue in the dynamic sql part where you are appending the datetime data types #startdate and #enddate to strings. It should be:
....
Timestamp between ''' +
CONVERT(NVARCHAR(50), #startDate, 121)+ ''' and ''' + CONVERT(NVARCHAR(50),#endDate, 121) + '''
) x
...
You need also to add more ' so that the query is composed correctly as a dynamic sql query.
So your full query will be:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#OID as NVARCHAR(MAX) = '(105, 106)',
#startDate datetime = convert(datetime,'01-11-2017 6:10:00 PM',105),
#endDate datetime = convert(datetime,'30-11-2017 6:10:00 PM',105);
select #cols = STUFF((SELECT ',' + QUOTENAME(Point)
from Value
group by Point
order by Point
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'');
set #query = 'SELECT timestamp,' + #cols + ' from
(
select timestamp, point, valuenumeric
from value where point in ' + #OID + ' and Timestamp between ''' +
CONVERT(NVARCHAR(50), #startDate, 121)+ ''' and ''' + CONVERT(NVARCHAR(50),#endDate, 121) + '''
) x
pivot
(
avg(valuenumeric)
for point in (' + #cols + ')
) p ';
execute(#query);
Demo.
You need to explicitly cast the datetime to varchar before concatenating with string
Also you need to append two more single quotes around the datetime parameter to enclose the date with single quotes.
To avoid all these hassle, I would suggest to use parameterised sql.
set #query = 'SELECT timestamp,' + #cols + ' from
(
select timestamp, point, valuenumeric
from value where point in ' + #OID + ' and Timestamp between
#startDate and #endDate
) x
pivot
(
avg(valuenumeric)
for point in (' + #cols + ')
) p '
exec sp_executesql #query,N'#startDate datetime, #endDate Datetime',#startDate,#endDate;

PIVOT and TEMP TABLE

please can you help me put this script into a temp table. i have been working on this for hours and it keeps giving me errors.
DECLARE #PivotColumnHeaders VARCHAR(MAX)
SELECT #PivotColumnHeaders =
COALESCE(#PivotColumnHeaders + ',[' + CAST(expansion as varchar(max)) + ']',
'[' + CAST(expansio
n as varchar(max))+ ']')
INTO #temp
FROM (Select distinct expansion from #CD4_VL2) results
DECLARE #PivotTableSQL NVARCHAR(MAX)
SET #PivotTableSQL = N'
select * from
(
select subjectID,expansion,printableValue1
from #CD4_VL2) as results
PIVOT
(MAX([printableValue1])
FOR [expansion] IN (
' + #PivotColumnHeaders + '
)
) as PivotTable
--order by Performed_Date_And_Time desc
'
Execute(#PivotTableSQL )
Because you've pivoted on the expansion columns, the respective values of MAX(printableValue1) will now be in columns with the names of the data in the Expansion column. Change this like so:
DECLARE #PivotColumnHeaders NVARCHAR(MAX) = 'Expansion1, Expansion2, Expansion3';
DECLARE #PivotTableSQL NVARCHAR(MAX);
SET #PivotTableSQL =
N'select subjectID, ' + #PivotColumnHeaders
+' from #CD4_VL2
PIVOT
(
MAX([printableValue1])
FOR [expansion] IN (' + #PivotColumnHeaders + ')) x';
Execute(#PivotTableSQL);
SqlFiddle here

Create Table from Select with rows as Columns

I need to create a table with columns based on my paramaters. The parameter is string variable and it consists of month and year combinations of multiple values seperated by comma. Based on this values i need to create temp table. I tried like below
DECLARE #compareMonths VARCHAR(2000)
DECLARE #compareCount INT
DECLARE #cols VARCHAR(2000)
DECLARE #query AS NVARCHAR(MAX);
SET #compareMonths = '2014-01,2014-02'
select #cols = STUFF((SELECT distinct ',' +
CONVERT(CHAR(3), DATENAME(MONTH, CAST(
CAST(SUBSTRING(Data, 0, 5) AS VARCHAR(4)) +
RIGHT('0' + CAST(SUBSTRING(Data, 6, 2) AS VARCHAR(2)), 2) +
RIGHT('0' + CAST(1 AS VARCHAR(2)), 2)
AS DATETIME))) + ' ' + CAST(SUBSTRING(Data, 0, 5) AS VARCHAR(4))
FROM dbo.Split(#compareMonths, ',')
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
, 1, 1, '');
Here i got the column name as monthname and year but how to create table dynamically based on this. I don't have any value column to use pivot.
My outout table must have 2 columns named Jan 2014, Feb 2014
If you want to a SQL database table, you can build Dynamic SQL script which forms a CREATE TABLE script as follows
DECLARE #compareMonths VARCHAR(2000)
SET #compareMonths = '2014-01,2014-02'
declare #sql nvarchar(max)
SELECT #sql = isnull(#sql + ',','') + ( '[' + val + ']') + ' varchar(100)' from dbo.Split(#compareMonths, ',')
SET #sql = N'CREATE Table OutputTable (' + #sql + ')'
exec sp_executeSql #sql
select * from OutputTable
In above script, I also used a sql string split function where you can find the source codes at the referenced tutorial
At the end you will have a table named OutputTable in your database with two columns

Conversion failed when converting date and/or time from character string

I am struggling with this query which returns the error: Conversion failed when converting date and/or time from character string.
This is a common error judging from my google searches, but nothing I've tried so far works. I've tried casting #startdate as datetime and varchar and leaving it alone, as in the below example.
I've also tried using convert against the fieldname and the parameter name, although admittedly, I may just be getting the syntax wrong.
ALTER PROCEDURE [dbo].[customFormReport]
(
#formid int,
#startdate DATETIME
)
AS
BEGIN
SET NOCOUNT ON
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(fieldname) from FormResponse WHERE FormID = #formid AND value IS NOT NULL FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT FormID, FormSubmissionID,' + #cols + ' from
(
SELECT FormID, FormSubmissionID, fieldname, value
FROM FormResponse WHERE FormID = ' + CAST(#formid AS VARCHAR(25)) + ' AND createDate > ' + #startdate + '
) x
pivot
(
max(value)
for fieldname in (' + #cols + ')
) p '
execute(#query)
edit: the query works except when I add the bit causing the error:
' AND createDate > ' + #startdate + '
The problem is you are attempting to concatenate a datetime to your varchar sql string. You need to convert it:
convert(varchar(10), #startdate, 120)
So the full code will be:
ALTER PROCEDURE [dbo].[customFormReport]
(
#formid int,
#startdate DATETIME
)
AS
BEGIN
SET NOCOUNT ON
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(fieldname) from FormResponse WHERE FormID = #formid AND value IS NOT NULL FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT FormID, FormSubmissionID,' + #cols + ' from
(
SELECT FormID, FormSubmissionID, fieldname, value
FROM FormResponse
WHERE FormID = ' + CAST(#formid AS VARCHAR(25)) + '
AND createDate > ''' + convert(varchar(10), #startdate, 120) + '''
) x
pivot
(
max(value)
for fieldname in (' + #cols + ')
) p '
execute(#query)
When you dynamically build the SQL Statement, the date value needs to be wrapped in single quotes. Whenever building a dynamic statement, do a SELECT #query and make sure the results look correct.
For your example, you would need to have 'WHERE createdate > ''' + covert(varchar(10), #startdate, 111) + '''
That would output: WHERE createdate > '2013/05/29'
Without the single quotes you would have: WHERE createdate > 2013/05/29