表列引用表 B 的部分鍵
在我的數據庫(MS SQL Server)中,我使用特定於語言的文本。所以我定義表格文本如下:
CREATE TABLE [dbo].[Texts]( [Id] [int] NOT NULL, [language] [nchar](5) NOT NULL, [text] [nvarchar](max) NULL, CONSTRAINT [PK_Texts] PRIMARY KEY CLUSTERED ( [Id] ASC, [language] ASC ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] ALTER TABLE [dbo].[Texts] WITH CHECK ADD CONSTRAINT [CK_Texts_language] CHECK (([language]='en-US' OR [language]='de-DE')) ALTER TABLE [dbo].[Texts] CHECK CONSTRAINT [CK_Texts_language]
這些文本應該在我的表格中的任何地方使用,例如這裡:
CREATE TABLE [dbo].[MyObject]( [id] [int] NOT NULL, [name] [int] NOT NULL, [comment] [int] NOT NULL, CONSTRAINT [PK_PlantDescription] PRIMARY KEY CLUSTERED ( [id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY]
如何指定一個值
MyObject.name
或MyObject.comment
應該是部分鍵值的約束Texts.Id
?一個 id 可能有多個文本,使用不同的語言。所以 (
Id, language
) 是唯一的,而不是Id
它本身。編輯:這是表格文本的範例:
Id language text 1 de-DE Holunder 1 en-US elder 2 de-DE Von diedem Busch kann man sowohl die Blüten als auch die Früchte verwerten. 2 en-US From this bush you can use both flowers and fruits.
和表 MyObject:
Id name comment 512 1 2
與UDF一起
CREATE FUNCTION [dbo].[GetText] ( @id int, @language nchar(5) ) RETURNS nvarchar(MAX) AS BEGIN Declare @result nvarchar(max); Select @result = text from dbo.Texts where id = @id AND [language] = @language; if @result is NULL BEGIN Select TOP 1 @result = text from dbo.Texts where id = @id ; END return @result; END
使用這些定義和以下查詢
SELECT [Id] ,[dbo].[GetText]([name], 'en-US') AS Name ,[dbo].[GetText]([comment], 'en-US') AS Comment FROM [dbo].[PlantDescription]
我得到結果:
Id Name Comment 512 elder From this bush you can use both flowers and fruits.
您會看到:當我刪除行 (Id = 1) 時,會有一些我必須通過觸發器刪除的孤立行。
或者是否有我在 inetrnet 中找不到的特定語言文本的標準方法?
一種方法是為文本鍵創建域表:
CREATE TABLE TEXT_KEYS ( TEXT_KEY INT NOT NULL PRIMARY KEY ); CREATE TABLE Texts ( TEXT_KEY INT NOT NULL REFERENCES TEXT_KEYS (TEXT_KEY) , [language] [nchar](5) NOT NULL , [text] [nvarchar](max) NULL , CONSTRAINT [PK_Texts] PRIMARY KEY CLUSTERED ( TEXT_KEY ASC, [language] ASC [...]
現在您可以使用
TEXT_KEY
fromTEXT_KEYS
作為其他表的外鍵。
您可以使用查詢創建一個
INSERT TRIGGER
查詢以在插入時驗證數據,或者您可以使用類似於如何基於查詢創建 CHECK CONSTRAINT 中的範例的使用者定義函式?. 從那個文章:-- we want to check if the values in the following tables are a subset of the main state table CREATE TABLE t1 (stateId INT NOT NULL) -- create a function to check the state values and return 1 if stateId is invalid CREATE FUNCTION dbo.fnc_IsValidState(@StateId INT, @TypeId Int) RETURNS BIT AS BEGIN DECLARE @flag BIT = 1 IF NOT EXISTS (SELECT 1 FROM state WHERE stateId =@StateId AND TypeId=@TypeId) BEGIN SET @flag = 0 END RETURN @flag END go --Add a check constraints to the table to call the function ALTER TABLE dbo.[t1] WITH NOCHECK ADD CONSTRAINT [CK_StateCHeck] CHECK ((dbo.fnc_IsValidState(StateId,1)=1))
我確實找到了一篇關於小心使用Tibor Karaszi 呼叫 UDF 的約束的警告文章。從那個文章:
小心呼叫 UDF 的約束
你可能只是不明白你的想法。如果還沒有寫部落格,我會感到驚訝,但如果是這樣,那值得重複。這是交易(來自論壇的範例,稍作修改):
我希望一列中的值是唯一的,假設另一列中的值為 1。我可以為此使用 UDF 嗎?
從表面上看,是的。您可以編寫一個 UDF 來傳遞應該有條件唯一的值,並在該 UDF 中檢查有多少行具有此值和 othercolumn = 1。如果超過 1 行,則函式返回 0,否則返回 1(或其他信號“OK”或“Not OK”)。現在,您可以在 CHECK 約束中呼叫此函式。像 CHECK(myFunction(uniqueCol) = 1) 這樣的東西。只要您 INSERT 到表中,這將在表面上完成它的工作。但是如果你更新了一行並且只將某行的 otherColumn 設置為 0 到 1,那麼檢查約束將不會被檢查。優化器足夠聰明,可以理解更新不會改變我們在 CHECK 約束中引用的任何內容,那麼為什麼還要檢查約束呢?這裡的最終結果是約束不’ t 做我們想讓它做的事情。改用觸發器(或其他方法)。