SQL 服务器 - UNPIVOT 期间列类型冲突
SQL Server - Conflicts column type during UNPIVOT
需要一些帮助。我正在创建 SQL 服务器单元测试来检查电子邮件服务器配置,并且在使用 UNPIVOT 时我有一个奇怪的行为。以下代码在供应商数据库上运行时会抛出错误,但在默认数据库(master、model、msdb、tempdb)中运行良好。有什么想法吗?
Msg 8167, Level 16, State 1, Line 16
The type of column "port" conflicts with the type of other columns specified in the UNPIVOT list.
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
基于它适用于某些数据库而不适用于其他数据库的事实,最有可能的罪魁祸首是排序规则。
当您将 varchar/nvarchar 列转换为 varchar/nvarchar 时,它将保持其现有排序规则。当您转换另一种类型如 int(如端口列)时,它采用您正在执行查询的数据库的默认排序规则。如果供应商数据库的排序规则与 msdb 不同,则 unpivot 将给出您所看到的错误。
几个可能的修复:
在你的查询之前添加这个以强制它从 msdb 执行:
USE msdb;
手动强制您的端口列使用与 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
强制其他列使用与端口相同的默认排序规则:
CAST(p.name AS VARCHAR(256)) COLLATE DATABASE_DEFAULT name,
CAST(a.email_address AS VARCHAR(256)) COLLATE DATABASE_DEFAULT email_address,
...
我还没有尝试过 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
需要一些帮助。我正在创建 SQL 服务器单元测试来检查电子邮件服务器配置,并且在使用 UNPIVOT 时我有一个奇怪的行为。以下代码在供应商数据库上运行时会抛出错误,但在默认数据库(master、model、msdb、tempdb)中运行良好。有什么想法吗?
Msg 8167, Level 16, State 1, Line 16 The type of column "port" conflicts with the type of other columns specified in the UNPIVOT list.
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
基于它适用于某些数据库而不适用于其他数据库的事实,最有可能的罪魁祸首是排序规则。
当您将 varchar/nvarchar 列转换为 varchar/nvarchar 时,它将保持其现有排序规则。当您转换另一种类型如 int(如端口列)时,它采用您正在执行查询的数据库的默认排序规则。如果供应商数据库的排序规则与 msdb 不同,则 unpivot 将给出您所看到的错误。
几个可能的修复:
在你的查询之前添加这个以强制它从 msdb 执行:
USE msdb;
手动强制您的端口列使用与 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
强制其他列使用与端口相同的默认排序规则:
CAST(p.name AS VARCHAR(256)) COLLATE DATABASE_DEFAULT name, CAST(a.email_address AS VARCHAR(256)) COLLATE DATABASE_DEFAULT email_address, ...
我还没有尝试过 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