How to use CTE with dynamic query pivot? - sql

I am using SQL Server 2008 R2
First I needed to break the dates (start date and end date) into every day from table1 which I did with recursive CTE.
DECLARE #maxdate DATETIME = (SELECT Max([EndDate]) FROM table1);
WITH CTE_DateToDays
AS (SELECT StartDate as Dates
FROM table1
UNION ALL
SELECT Dateadd(day, 1, Dates)
FROM CTE_DateToDays
WHERE Dates < #maxdate)
Select Dates from CTE_DateToDays;
Then I wanted to convert rows into columns from table2. Which I did with dynamic pivot, as I did not know the number of columns.
DECLARE #TimeBandColms AS NVARCHAR(MAX);
Select #TimeBandColms = STUFF((SELECT ',' + QUOTENAME(t.TimeBandName)
from table2 t
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'');
Select #TimeBandColms
from
(
SELECT t.TimeBandID,t.TimeBandName
FROM
table2 t
) x
pivot
(
MAX(TimeBandID)
for TimeBandName in (" + #TimeBandColms + N")
) piv;
Now here I am stuck whenever I combine these two things, sometimes the result set is not what I want or sometimes error with 'Invalid column name' or 'Multi-part identifier could not be bound'.
NOTE
Table1 and Table2 are different tables with nothing in common like key or id.
I have tried many things like union or different approach, but couldn't solve my problem.
Sorry if I am not more specific, but I am new to this pivot, stuff, and CTE.
I really need your help.
The result set which I want is something like this...
Here is my attempt.
DECLARE #TimeBandColms AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
select #TimeBandColms = STUFF((SELECT ',' + QUOTENAME(t.TimeBandName)
from table2 t
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'');
set #query = 'DECLARE #maxdate DATETIME = (SELECT Max([EndDate]) FROM
table1);
WITH CTE_DateToDays
AS (SELECT StartDate as Dates
FROM table1
UNION ALL
SELECT Dateadd(day, 1, Dates)
FROM CTE_DateToDays
WHERE Dates < #maxdate)'
Set #query += N'SELECT ' + #TimeBandColms + N' from
(
SELECT CTE_DateToDays.Dates, t.TimeBandID,t.TimeBandName
FROM CTE_DateToDays,
table2 t
) x
pivot
(
max(Dates)
for TimeBandName in (' + #TimeBandColms + N')
) piv;'
exec (#query);

You can try this.
DECLARE #TimeBandColms AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
select #TimeBandColms = STUFF((SELECT ',' + QUOTENAME(t.TimeBandName)
from table2 t
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'');
set #query = 'DECLARE #maxdate DATETIME = (SELECT Max([EndDate]) FROM
table1);
WITH CTE_DateToDays
AS (SELECT StartDate as Dates
FROM table1
UNION ALL
SELECT Dateadd(day, 1, Dates)
FROM CTE_DateToDays
WHERE Dates < #maxdate)'
Set #query += N'SELECT Dates, ' + #TimeBandColms + N' from
(
SELECT CTE_DateToDays.Dates, t.TimeBandID, t.TimeBandName
FROM CTE_DateToDays
CROSS JOIN table2 t
) x
pivot
(
count(TimeBandID)
for TimeBandName in (' + #TimeBandColms + N')
) piv;'
exec (#query);

Related

Convert Columns values into Rows in SQL 2008

It would be great if you can help me to convert Column into Rows in SQL Table.
Let say, I have 3 columns called:
Employee_ID
Shift_Date
Shift_ID
Currently it come up like this:
Table Like this
I want to appear like that as the result -
Result Table
But I want value in it, can you guys please help. Thanks.
This is a query I wrote but still error:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(shift_date)
from dbo.tbl_Multi_Shift_Employee WHERE Shift_Date BETWEEN CONVERT(DATE, '01/02/2018 00:00:00',103) AND CONVERT(DATE, '28/02/2018 00:00:00',103)
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT Employee_ID, total, Department_ID, shift_id, ' + #cols + ' from
(
select count(*) over(partition by t.Employee_ID) total,
s.Department_ID,
t.Employee_ID,
t.shift_id
from dbo.tbl_Multi_Shift_Employee t
inner join dbo.tbl_department s
on t.Department_ID = s.Department_ID
) x
pivot
(
count(shift_id)
for shift_id in (' + #cols + ')
) p '
PRINT #query
execute(#query)
First you must to remove shift_id from primary select because is used as pivot.
Second, change shift_id with shift_date that is the correct column you are using as pivot columns.
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(shift_date)
from dbo.tbl_Multi_Shift_Employee WHERE Shift_Date BETWEEN CONVERT(DATE, '01/02/2018 00:00:00',103) AND CONVERT(DATE, '28/02/2018 00:00:00',103)
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT Employee_ID, total, Department_ID, ' + #cols + ' from
(
select count(*) over(partition by t.Employee_ID) total,
s.Department_ID,
t.Employee_ID,
t.shift_id,
t.shift_date
from dbo.tbl_Multi_Shift_Employee t
inner join dbo.tbl_department s
on t.Department_ID = s.Department_ID
) x
pivot
(
count(shift_id)
for shift_date in (' + #cols + ')
) p '
PRINT #query
execute(#query)

SQL query Joining table itself

I have a following table:
TICKER DATE SHAREPRICE
--------------------------------
ABC 1.1.2015 50
XYZ 1.1.2015 100
etc.
I want to make a query, where the result is following:
DATE PRICE(TICKER ABC) PRICE(TICKER XYZ)
--------------------------------------------
1.1.2015 50 100
Use PIVOT in SQL SERVER.
DECLARE #test AS TABLE(TICKER VARCHAR(10), DATE DATETIME, SharePrice INT)
INSERT INTO #test
SELECT 'ABC', '1/1/2015', 50 UNION
SELECT 'XYZ', '1/1/2015', 100
SELECT Date, ABC AS [PRICE(TICKER ABC)], XYZ AS [PRICE(TICKER XYZ)] FROM #test
PIVOT(MAX(SharePrice) FOR Ticker IN(ABC, XYZ)) AS A
In TSQL you can write a query using dynamic pivot as:
DECLARE #cols AS NVARCHAR(MAX),#colsFinal AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ', ' + TICKER
from test1
group by TICKER, [DATE]
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #colsFinal = STUFF((SELECT distinct ', isnull( ' + TICKER +
' ,0) as [PRICE (TICKER ' + TICKER +' )]'
from test1
group by TICKER, [DATE]
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = N'SELECT [Date],' + #colsFinal + N' from
(
select [Date], TICKER , SharePrice
from test1
) x
pivot
(
max(SharePrice)
for TICKER in (' + #cols + N')
) p '
exec sp_executesql #query;
DEMO

operation not allowed when the object is closed when running more advanced query

When I try to run a more advanced SQL query on an ASP page I get this error:
operation not allowed when the object is closed
When I run this code it's working:
...
sql = "SELECT distinct team FROM tbl_teams"
rs.open sql, conndbs, 1, 1
...
But when I run this code (and this code is working if I run it in Microsoft SQL Server Management Studio), I get the error...
...
sql = "DECLARE #cols AS NVARCHAR(MAX), #query AS NVARCHAR(MAX), #orderby nvarchar(max), #currentYear varchar(4) select #currentYear = cast(year(getdate()) as varchar(4)) select #cols = STUFF((SELECT ',' + QUOTENAME(year([datefrom])) from tbl_teams group by year([datefrom]) order by year([datefrom]) desc FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)') ,1,1,'') select #orderby = 'ORDER BY ['+cast(year(getdate()) as varchar(4)) + '] desc' set #query = 'SELECT team, Won = [1], Lost=[2], Draw = [3]' + #cols + ', Total from ( select team, new_col, total from ( select team, dt = year([datefrom]), result, total = count(*) over(partition by team) from tbl_teams ) d cross apply ( select ''dt'', dt union all select ''result'', case when dt = '+#currentYear+' then result end ) c (old_col_name, new_col) ) x pivot ( count(new_col) for new_col in ([1], [2], [3],' + #cols + ') ) p '+ #orderby exec sp_executesql #query"
rs.open sql, conndbs, 1, 1
...
This is a better overview of the query:
DECLARE
#cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#orderby nvarchar(max),
#currentYear varchar(4)
select #currentYear = cast(year(getdate()) as varchar(4))
select #cols
= STUFF((SELECT ',' + QUOTENAME(year([datefrom]))
from tbl_teams
group by year([datefrom])
order by year([datefrom]) desc
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #orderby = 'ORDER BY ['+cast(year(getdate()) as varchar(4)) + '] desc'
set #query = 'SELECT team, Won = [1],
Lost=[2], Draw = [3]' + #cols + ', Total
from
(
select
team,
new_col,
total
from
(
select team,
dt = year([datefrom]),
result,
total = count(*) over(partition by team)
from tbl_teams
) d
cross apply
(
select ''dt'', dt union all
select ''result'', case when dt = '+#currentYear+' then result end
) c (old_col_name, new_col)
) x
pivot
(
count(new_col)
for new_col in ([1], [2], [3],' + #cols + ')
) p '+ #orderby
exec sp_executesql #query
Do I need to run the query on another way or what is wrong with this code?
This is a common problem caused by row counts being interpreted as output from a Stored Procedure when using ADODB with SQL Server.
To avoid this remember to set
SET NOCOUNT ON;
in your Stored Procedure this will stop ADODB returning a closed recordset, or if for whatever reason you don't want to do this (not sure why as you can always use ##ROWCOUNT to pass the row count back), you can use
'Return the next recordset, which will be the result of the Stored Procedure, not
'the row count generated when SET NOCOUNT OFF (default).
Set rs = rs.NextRecordset()
which returns the next ADODB.Recordset if ADODB has detected one being returned by the Stored Procedure (might be best to check rs.State <> adStateClosed when dealing with multiple ADODB.Recordset objects).

dynamic sql query not showing result on server

This query shows records when run on my local system, but when I deploy it to and run it on the server, the query does not show any records.
When I connect to the DB server through sql engine and execute (alt + x), it only displays messages command completed successfully, but displays no records.
Any idea how to fix this, where is the issue?
DECLARE #cols AS NVARCHAR(MAX)
, #query AS NVARCHAR(MAX)
select #cols = STUFF
(
(
SELECT ',' + QUOTENAME(StartDateTime)
from
(
select distinct StartDateTime
from tblEmployeeShift
inner join tblShift on tblShift.ShiftId = tblEmployeeShift.ShiftId
where EmployeeNewId = 3126
and IsDeleted = 0
and StartDateTime >= '06/07/2014 12:00:00'
and StartDateTime <= '07/07/2014 12:00:00'
) d
order by StartDateTime
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,''
)
set #query =
N'SELECT EmployeeNewId
,Full_Name
,' + #cols + N'
from
(
select *
from
(
select tblEmployeeShift.EmployeeNewId
,Full_Name
,StartDateTime
,dbo.GetAttendanceFlag(tblEmployeeShift.EmployeeNewId,StartDateTime) as PV
from tblEmployeeShift
inner join tblShift on tblShift.ShiftId = tblEmployeeShift.ShiftId
inner join employee on tblEmployeeShift.EmployeeNewId = SUBSTRING(employee.Employeeid,6,5)
where tblEmployeeShift.EmployeeNewId in
(
select top 20 employeenewid
from employee e
where e.EmployeeNewId = 3126
)
and IsDeleted = 0
) d
)
x pivot
(
max(PV) for StartDateTime in (' + #cols + N')
) c'
execute sp_executesql #query
Most likely the data on the server is such that the #cols variable is NULL, and the concatenation of the NULL #cols variable results in a NULL #query variable.

while converting column to row not able to fetch value from another table automatically

select *
from (
select vtid, convert(date, dtime) as Date from Transaction_tbl where locid = 5
) as vt
pivot (
count(vtid)
for vtid in (select vtid from VType_tbl)
) as pvt
while executing this query am getting error
Incorrect syntax near the keyword 'select'." and Incorrect syntax near
')'.
actually I have one more table,name= Vtype_table , How Can I load all vtid from vtype table in this query? I want to get output depend upon vtid.
Any help greatly appreciated.
Your PIVOT syntax is correct except you are using a SELECT statement inside your PIVOT.
You cannot use a SELECT statement inside the PIVOT IN clause to select column headers. It is required that the columns for the IN clause be known prior to executing the query.
If you are looking to generate a dynamic list of vtid values, then you will need to use dynamic SQL to get the result and the syntax will be similar to the following:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(vtid)
from VType_tbl
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT Date, ' + #cols + '
from
(
select vtid, convert(date, dtime) as Date
from Transaction_tbl
where locid = 5
) d
pivot
(
count(vtid)
for vtid in (' + #cols + ')
) p '
execute(#query);
Edit, if you want the type names to appear then you should be able to use the following:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(vt_name)
from VType_tbl
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT Date, ' + #cols + '
from
(
select v.vt_name, convert(date, dtime) as Date
from Transaction_tbl t
inner join VType_tbl v
on t.vtid = v.vtid
where locid = 5
) d
pivot
(
count(vt_name)
for vt_name in (' + #cols + ')
) p '
execute(#query)
Note: I am guessing on the column name for VType_tbl