简体   繁体   中英

SQL pivot with unknown number of columns - not a valid identifier and showing minimum only

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 ):

  • "mm" The minute, from 00 through 59.
  • "MM" The month, from 01 through 12.

You have two issues here:

  • Your main issue: when you call 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 necessary
  • Your second problem: don't try to quote the column names yourself, use QUOTENAME
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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM