繁体   English   中英

列数未知的 SQL 数据透视表 - 不是有效标识符,仅显示最小值

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

我的动态查询在 MS SQL Server 2014 中以未知数量的列为中心时遇到问题。我的查询基于文章SQL Server 2005 以未知数量的列和其他类似文章为基础。 但是,我有两个无法破译的问题。

执行动态 SQL 时,出现此错误:

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.

但是,如果我将查询复制并粘贴到 SQL Server Management Studio 中的单独窗口中,它会运行...我看不出有什么问题,除了错误消息仅返回查询的前 xxx 个字符。 . 任何关于我做错了什么的建议将不胜感激。 是连接还是我选择列的方式?

但是......这把我带到了第二个问题。 当我单独运行复制的查询文本时,它可以工作,但它为所有用户显示相同的值(以小时/分钟为单位的时间),而不是用户特定的值(尽管未登录的用户正确地出现了 NULL )。 枢轴似乎需要一个最小/最大/其他聚合,但它应该将它保留给每个用户(根据我所看到的,通过一些 SQL 巫术),它不是......列名似乎也即将到来以美国日期格式显示,即使我已将格式指定为澳大利亚 (dd-mm-yyyy)。 如果有人知道如何纠正这些问题,那也将不胜感激。

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

我正在运行的完整查询是:

@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

相关的表定义是:

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


我相信您收到的错误与execute @Query而不是execute (@Query) 查看EXECUTE上的 Microsoft 文档,执行字符串变量需要打开和关闭括号:

Execute a character string  
{ EXEC | EXECUTE }   
    ( { @string_variable | [ N ]'tsql_string' } [ + ...n ] )  
    [ AS { LOGIN | USER } = ' name ' ]  
[;] 

一旦我添加了括号,我就能够得到我认为与您的语句等效的语句,以使用我创建的一些示例数据按预期执行。

至于你的日期格式,我相信你的日期格式字符串有问题。 我相信您当前的dd-mm-yyyy日期格式字符串应该是dd-MM-yyyy 根据自定义日期和时间格式字符串Microsoft doc(由 Microsoft doc 在FORMAT上引用):

  • "mm" 分钟,从 00 到 59。
  • “MM” 月份,从 01 到 12。

你在这里有两个问题:

  • 您的主要问题:当您调用execute您需要将@Query括在括号() 不过,我建议您使用sp_executesql ,因为这使您可以在必要时传递参数
  • 你的第二个问题:不要试图自己引用列名,使用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;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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