【问题标题】:SQL Server - Conflicts column type during UNPIVOTSQL Server - 在 UNPIVOT 期间冲突列类型
【发布时间】:2021-09-29 04:54:28
【问题描述】:

需要帮助。我正在创建用于检查电子邮件服务器配置的 SQL 服务器单元测试,并且在使用 UNPIVOT 时我的行为很奇怪。以下代码在供应商数据库上运行时会引发错误,但在默认数据库(master、model、msdb、tempdb)中运行良好。有什么想法吗?

消息 8167,第 16 级,状态 1,第 16 行 “端口”列的类型与 UNPIVOT 列表中指定的其他列的类型冲突。

        SELECT * FROM (
                SELECT 
                CAST(p.name AS VARCHAR(256)) name, 
                CAST(a.email_address AS VARCHAR(256)) email_address, 
                CAST(a.display_name AS VARCHAR(256)) display_name, 
                CAST(a.replyto_address AS VARCHAR(256)) replyto_address,
                CAST(s.servertype AS VARCHAR(256)) servertype,  
                CAST(s.servername AS VARCHAR(256)) servername,
                CAST(s.port AS VARCHAR(256)) port
                FROM msdb.dbo.sysmail_profile p 
                JOIN msdb.dbo.sysmail_profileaccount pa ON p.profile_id = pa.profile_id 
                JOIN msdb.dbo.sysmail_account a ON pa.account_id = a.account_id 
                JOIN msdb.dbo.sysmail_server s ON a.account_id = s.account_id
            ) AS dummyName1
            UNPIVOT(
                configValue for configKey IN (name, email_address, display_name, replyto_address, servertype, servername, port)
            )   as dummyName2

【问题讨论】:

  • 如果您使用VALUES 表结构来反透视表,那么您会遇到同样的问题吗?
  • 供应商数据库的排序规则集可能与 msdb 数据库不同。其他列是 varchar,因此强制转换继承了现有的排序规则,但端口不是,因此它从命令上下文中获取默认排序规则。您可以通过在每列之后添加“COLLATE DATABASE_DEFAULT”来强制它们全部使用相同的排序规则。

标签: sql sql-server tsql unpivot


【解决方案1】:

基于它适用于某些数据库而不适用于其他数据库的事实,最可能的罪魁祸首是整理。

当您将 varchar/nvarchar 列强制转换为 varchar/nvarchar 时,它将保持其现有的排序规则。当您转换另一种类型,如 int(如 port 列)时,它采用您正在执行查询的数据库的默认排序规则。如果供应商数据库的排序规则与 msdb 不同,则 unpivot 将给出您所看到的错误。

几个可能的修复:

  1. 在您的查询之前添加它以强制它从 msdb 执行:

    USE msdb;
    
  2. 手动强制您的端口列使用与 msdb 相同的排序规则:

    --Check the collation for msdb
    SELECT name,collation_name FROM master.sys.databases
    --Use that collation (ex: SQL_Latin1_General_CP1_CI_AS) in your query
    CAST(s.port AS VARCHAR(256)) COLLATE SQL_Latin1_General_CP1_CI_AS port
    
  3. 强制其他列使用与端口相同的默认排序规则:

    CAST(p.name AS VARCHAR(256)) COLLATE DATABASE_DEFAULT name, 
    CAST(a.email_address AS VARCHAR(256)) COLLATE DATABASE_DEFAULT email_address,
    ...
    

【讨论】:

    【解决方案2】:

    我还没有尝试过 Larnu 解决方案,但是 bt224 提到的整理解决了这个问题。默认数据库使用 SQL_Latin1_General_CP1_CI_AS,而供应商数据库使用 Latin1_General_CI_AS。 这是更新的代码,它可以工作!谢谢bt224!

    SELECT * FROM (
                    SELECT 
                    CAST(p.name AS VARCHAR(256)) COLLATE DATABASE_DEFAULT name, 
                    CAST(a.email_address AS VARCHAR(256)) COLLATE DATABASE_DEFAULT email_address, 
                    CAST(a.display_name AS VARCHAR(256)) COLLATE DATABASE_DEFAULT display_name, 
                    CAST(a.replyto_address AS VARCHAR(256)) COLLATE DATABASE_DEFAULT replyto_address,
                    CAST(s.servertype AS VARCHAR(256)) COLLATE DATABASE_DEFAULT servertype,  
                    CAST(s.servername AS VARCHAR(256)) COLLATE DATABASE_DEFAULT servername,
                    CAST(s.port AS VARCHAR(256)) COLLATE DATABASE_DEFAULT port
                    FROM msdb.dbo.sysmail_profile p 
                    JOIN msdb.dbo.sysmail_profileaccount pa ON p.profile_id = pa.profile_id 
                    JOIN msdb.dbo.sysmail_account a ON pa.account_id = a.account_id 
                    JOIN msdb.dbo.sysmail_server s ON a.account_id = s.account_id
                ) AS dummyName1
                UNPIVOT(
                    configValue for configKey IN (name, email_address, display_name, replyto_address, servertype, servername, port)
                )   as dummyName2
    

    【讨论】:

      猜你喜欢
      • 2014-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多