I am having an issue with a dynamic query to pivot on an unknown number of columns in MS SQL server 2014. I've based my query on the article SQL Server 2005 Pivot on Unknown Number of Columns and other similar articles. However, I am having two issues that I can't decipher.
When executing the dynamic SQL, I get this error:
The name 'SELECT Code, LastName, FirstName, [03-30-2021],[06-30-2021],[08-00-2021],[10-30-2021],[12-30-2021],[17-30-2021],[18-30-2021],[19-30-2021],[20-30-2021],[21-30-2021],[22-30-2021],[24-30-2021],[25-30-2021],[26-30-2021],[29-30-2021] FROM (
SELECT i.Code, aa.LastName, aa.FirstName, FORMAT(StartDate, 'dd-mm-yyyy') AS StartDate, FORMAT(s.SignOut-s.SignIn, 'hh:mm') AS AttendanceTime
FROM ActualSession AS a INNER JOIN ActualAttendee aa ON( a.id = aa.ActualSessionId)
INNER JOIN Attendee att ON (att.Id = aa.AttendeeId)
LEFT JOIN SignIn s ON (a.Id = s.ActualSessionId) LEFT JOIN Identification i ON (i.AttendeeId = aa.AttendeeId
AND i.Id' is not a valid identifier.
However, if I copy and paste the query into a separate window in SQL Server Management Studio, it runs... I can't see what is wrong, except that the error message is only returning the first xxx characters of the query... Any suggestions as to what I have done wrong would be appreciated. Is it the joins, or the way I've selected columns?
BUT... that takes me to the second issue. When I do run the copied query text separately, it works but it is showing the same values (time in hours/minutes) for all users, rather than the user-specific values (though users who did not sign in are correctly coming up NULL). The pivot seems to need a min/max/other aggregate, but where it should be keeping it to each user (according to what I can see, by some SQL voodoo), it's not... The column names also appear to be coming up in US date format, even though I've specified the format as Australian (dd-mm-yyyy). If anyone knows how to correct these issues, that would also be appreciated.
Code LastName FirstName 03-30-2021 06-30-2021 08-00-2021 10-30-2021
abc123 Simpson Homer 01:07 01:15 NULL 01:01
abc456 Griffen Peter 01:07 01:15 NULL 01:01
abc789 Flintsone Fred 01:07 01:15 NULL 01:01
xyz123 Heffernan Doug 01:07 01:15 NULL 01:01
xyz456 Gergich Jerry NULL NULL NULL NULL
xyz789 Kramden Ralph 01:07 01:15 NULL 01:01
The full query I am running is:
@Query AS NVARCHAR(MAX)
SELECT @cols = STUFF((SELECT DISTINCT '],[' + FORMAT(StartDate, 'dd-mm-yyyy') FROM ActualSession
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,2,'') + ']'
SET @Query = 'SELECT Code, LastName, FirstName, ' + @cols + ' FROM (
SELECT i.Code, aa.LastName, aa.FirstName, FORMAT(StartDate, ''dd-mm-yyyy'') AS StartDate, FORMAT(s.SignOut-s.SignIn, ''hh:mm'') AS AttendanceTime
FROM ActualSession AS a INNER JOIN ActualAttendee aa ON( a.id = aa.ActualSessionId)
INNER JOIN Attendee att ON (att.Id = aa.AttendeeId)
LEFT JOIN SignIn s ON (a.Id = s.ActualSessionId) LEFT JOIN Identification i ON (i.AttendeeId = aa.AttendeeId
AND i.IdentificationTypeId = (SELECT Id FROM IdentificationType WHERE [Name] = ''Student Code''))
) x PIVOT ( max(AttendanceTime)
FOR StartDate in (' + @cols + ') ) p '
PRINT @Query --for debugging
execute @Query
Relevant Table definitions are:
CREATE TABLE [dbo].[ActualSession](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[EventId] [bigint] NOT NULL,
[EventName] [nvarchar](50) NOT NULL,
[EventSessionId] [bigint] NOT NULL,
[StartDate] [datetime] NOT NULL,
[EndDate] [datetime] NOT NULL,
[Active] [bit] NULL,
[SignInRequired] [bit] NULL,
[SignOutRequired] [bit] NULL,
[SignInAllowed] [bit] NULL,
[SignOutAllowed] [bit] NULL,
[EarlySignInAllowed] [bit] NULL,
[EarlySignOutAllowed] [bit] NULL,
[LateSignInAllowed] [bit] NULL,
[LateSignOutAllowed] [bit] NULL,
[ExpiredIdAllowed] [bit] NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Attendee](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[FirstName] [nvarchar](50) NOT NULL,
[LastName] [nvarchar](50) NOT NULL,
[PreferredName] [nvarchar](50) NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[SignIn](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[EventId] [bigint] NOT NULL,
[ActualSessionId] [bigint] NOT NULL,
[AttendeeId] [bigint] NOT NULL,
[SignIn] [datetime] NOT NULL,
[SignOut] [datetime] NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Identification](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[AttendeeId] [bigint] NOT NULL,
[IdentificationTypeId] [bigint] NOT NULL,
[Code] [nvarchar](50) NOT NULL,
[ExpiryDate] [date] NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[IdentificationType](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NOT NULL,
[RevHex] [bit] NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[ActualAttendee](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[EventId] [bigint] NOT NULL,
[ActualSessionId] [bigint] NOT NULL,
[AttendeeId] [bigint] NOT NULL,
[FirstName] [nvarchar](50) NULL,
[LastName] [nvarchar](50) NULL,
[PreferredName] [nvarchar](50) NULL,
[GroupId] [bigint] NULL,
[GroupName] [nvarchar](50) NULL,
[GroupTypeId] [bigint] NULL,
[GroupTypeName] [nvarchar](50) NULL,
[GroupTypeAD] [bit] NULL,
[GroupTypeADName] [nvarchar](200) NULL,
[GroupTypeDB] [bit] NULL,
[GroupTypeDBQuery] [nvarchar](1000) NULL,
[GroupTypeManual] [bit] NULL
) ON [PRIMARY]
GO
I believe the error you are receiving is related to the usage of execute @Query
instead of execute (@Query)
. Looking at the Microsoft doc on EXECUTE , executing a string variable requires open and close parens:
Execute a character string
{ EXEC | EXECUTE }
( { @string_variable | [ N ]'tsql_string' } [ + ...n ] )
[ AS { LOGIN | USER } = ' name ' ]
[;]
Once I added the parens, I was able to get what I believe is an equivalent statement to yours to execute as expected with some sample data I created.
As for your date format, I believe your date format string has an issue. I believe your current date format string of dd-mm-yyyy
is meant to be dd-MM-yyyy
. Per the Custom date and time format strings Microsoft doc (referenced by Microsoft doc on FORMAT
):
You have two issues here:
execute
you need to enclose @Query
in parenthesis ()
. I suggest, though, that you use sp_executesql
, because this enables you to pass through parameters if necessaryQUOTENAME
DECLARE @Query AS nvarchar(MAX), @cols nvarchar(MAX);
SELECT @cols = STUFF((
SELECT DISTINCT ',' + QUOTENAME(FORMAT(StartDate, 'dd-mm-yyyy'))
FROM ActualSession
FOR XML PATH(''), TYPE
).value('text()[1]', 'NVARCHAR(MAX)')
, 1, LEN(','), '');
SET @Query = '
SELECT
Code,
LastName,
FirstName,
' + @cols + '
FROM (
SELECT
i.Code,
aa.LastName,
aa.FirstName,
FORMAT(StartDate, ''dd-mm-yyyy'') AS StartDate,
FORMAT(s.SignOut-s.SignIn, ''hh:mm'') AS AttendanceTime
FROM ActualSession AS a
INNER JOIN ActualAttendee aa ON (a.id = aa.ActualSessionId)
INNER JOIN Attendee att ON (att.Id = aa.AttendeeId)
LEFT JOIN SignIn s ON (a.Id = s.ActualSessionId)
LEFT JOIN Identification i ON (i.AttendeeId = aa.AttendeeId
AND i.IdentificationTypeId = (SELECT Id FROM IdentificationType WHERE [Name] = ''Student Code''))
) x
PIVOT ( max(AttendanceTime)
FOR StartDate in (
' + @cols + '
) ) p;
';
PRINT @Query --for debugging
EXEC sp_executesql @Query;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.