【问题标题】:Is it possible to create a Foreign Key on 2 columns with differing Collations?是否可以在具有不同排序规则的 2 列上创建外键?
【发布时间】:2013-07-17 05:37:17
【问题描述】:

我已经尝试在所有外键/排序规则问题中搜索大约一个小时,但我什至找不到与我的问题很接近的东西。

我有两个来自两个不同软件供应商的表位于同一个数据库中。一个供应商将其排序规则硬编码为 Latin1_General_BIN,而另一个使用数据库默认值(在本例中为 Latin1_General_CI_AS)。是否可以在不更改任何列的情况下在这两种排序规则类型之间创建外键?

通常您只需更改一个,但在这种情况下,表格非常敏感,我不允许进行此类更改,但由于触发器中的一段逻辑读取数据之间的数据,我必须创建一个外键这两个表只有在找到外键时:

SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE 
WHERE CONSTRAINT_NAME = 
( 
    SELECT name FROM sys.foreign_keys 
    WHERE parent_object_id = OBJECT_ID( 'Table1' )
    AND referenced_object_id = OBJECT_ID( 'Table2' ) 
)

任何帮助将不胜感激

附:如果有人能帮助我,我似乎无法弄清楚这段代码是如何工作的,我输入了 4 个必需的空格,但它仍然只是将我的代码显示为文本:(

【问题讨论】:

  • 在四个空格之前尝试额外的换行符,并确保每个 rw 都有空格(或者单个制表符也可以)
  • 你真是个聪明的裤子,谢谢大卫,额外的换行符起到了作用:) 你如何做一个标签?每次我按 Tab 时,它都会将焦点转移到下一个控件。
  • 我通常在 notepad++ 中编辑我的代码,然后选择所有代码并按一次 Tab(然后我将其粘贴到 stackoverflow 中)。这样我就可以同时检查我的 SQL 或 C# 或 python 或其他什么的语法。您可以在 sql server management studio 和 Visual Studio 中执行相同的技巧。

标签: tsql foreign-keys collation


【解决方案1】:

无法将外键约束从一个排序规则的字段添加到另一个排序规则的字段。您将收到错误消息 1757。

要么更改其中一个表的排序规则,要么创建一个解决方法,使用一个新列代替正确的排序规则,或者创建具有用于引用的整数的代理键列。

如果没有其他方法,并且您确实需要修复这种类型的约束并且性能不是问题,请添加检查约束和/或触发器,以检查放入表中的数据的引用完整性。这些规则必须将一个表中的所有值强制转换为另一个表的排序规则,以便比较值,所以它会很慢,而且要使用索引真的很棘手,请谨慎行事。

例如,您可以在引用表上设置一个插入触发器,以检查引用表中是否存在带有插入字符串的记录。然后,您还必须为引用的表添加更新和删除触发器,以便它不会超出引用表中的记录所引用的值范围或级联更新/删除的值范围。基本上你复制外键是什么,它变得非常缓慢并且扩展得可怕。

简短的回答:不要这样做,让表格保持松散状态或修复其中一个的排序规则。

【讨论】:

  • 感谢上述 David,我们确实在某些表上为非常具体的实例使用了参照完整性触发器,所以我听到了你在说什么。我也理解排序规则的更改,因为这是我们通常所做的,但不幸的是,我们不允许更改两个表中任何一个的引用列的排序规则,因为它们对于两个供应商软件的完整性至关重要.然而,我喜欢的是你所说的可能添加代理键,尽管它不是最真实的形式。在我快速制定规范后,我会回复你。谢谢!
【解决方案2】:

Sweet,我认为解决方案非常优雅。我将其写为纯粹的答案,因为它是最接近所需解决方案的完整替代方案。但我会将您的答案标记为答案,因为它正确回答了我最初的问题。

好吧,首先我所做的是,我得到了触发器需要外键的供应商的许可,以便在他们的表中创建一个新列作为其他供应商表的排序规则中的持久计算列:

DECLARE @Collation  nvarchar(100)
DECLARE @SQL        nvarchar(1000)
SET @Collation = ( SELECT collation_name FROM sys.columns WHERE OBJECT_ID IN ( SELECT OBJECT_ID FROM sys.objects WHERE type = 'U' AND name = 'Vendor1Table' ) AND name = 'Vendor1Column' )
SET @SQL = 'ALTER TABLE [Vendor2Table] ADD [Vendor2ComputedColumn] AS [Vendor2Column] COLLATE ' + @Collation + ' PERSISTED'
EXECUTE( @SQL )
GO

接下来,我在计算列中添加了一个候选键:

ALTER TABLE [Vendor2Table] ADD CONSTRAINT [CCUNQ1_x] UNIQUE NONCLUSTERED 
(
    [Vendor2ComputedColumn] ASC
)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) 
ON [PRIMARY]
GO

然后,我只是为计算列创建了外键:

ALTER TABLE [dbo].[Vendor1Table]  WITH CHECK ADD CONSTRAINT [CCFOK01_x] FOREIGN KEY ( [Vendor1Column] )
REFERENCES [dbo].[Vendor2Table] ( [Vendor2ComputedColumn] )
GO

ALTER TABLE [dbo].[Vendor1Table] CHECK CONSTRAINT [CCFOK01_x]
GO

最后,原始的 SQL 脚本顺利通过:

SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE 
WHERE CONSTRAINT_NAME = 
( 
    SELECT name FROM sys.foreign_keys 
    WHERE parent_object_id = OBJECT_ID( 'Vendor1Table' )
    AND referenced_object_id = OBJECT_ID( 'Vendor2Table' ) 
)

希望这个小小的演练有一天能帮助其他一些人:)

感谢大卫的帮助,不胜感激!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多