SQL Server'ın benzersiz bir dizin ve birincil anahtar arasında seçim yapma yöntemi var mı?
En azından yabancı anahtar oluşturulurken ve başvurulan tabloda alternatif anahtar kısıtlamaları veya benzersiz dizinler mevcut olduğunda SqlServer'ı birincil anahtara başvuruda bulunmak mümkündür.
Birincil anahtara başvurulması gerekiyorsa, yabancı anahtar tanımında yalnızca başvurulmakta olan tablonun adı belirtilmelidir ve başvuruda bulunulan sütunların listesi atlanmalıdır:
ALTER TABLE Child
ADD CONSTRAINT FK_Child_Parent FOREIGN KEY (ParentID)
-- omit key columns of the referenced table
REFERENCES Parent /*(ParentID)*/;
Daha fazla ayrıntı aşağıda.
Aşağıdaki kurulumu düşünün:
CREATE TABLE T (id int NOT NULL, a int, b int, c uniqueidentifier, filler binary(1000));
CREATE TABLE TRef (tid int NULL);
burada tablonun TRef
referans tablosuna bakması amaçlanmaktadır T
.
Referans kısıtlaması oluşturmak ALTER TABLE
için iki alternatifli komut kullanılabilir :
ALTER TABLE TRef
ADD CONSTRAINT FK_TRef_T_1 FOREIGN KEY (tid) REFERENCES T (id);
ALTER TABLE TRef
ADD CONSTRAINT FK_TRef_T_2 FOREIGN KEY (tid) REFERENCES T;
ikinci durumda başvurulan tablonun hiçbir sütununun ( REFERENCES T
karşı REFERENCES T (id)
) belirtilmediğine dikkat edin .
T
Henüz anahtar dizini bulunmadığından , bu komutların yürütülmesi hatalar üretecektir.
İlk komut aşağıdaki hatayı döndürür:
Msg 1776, Seviye 16, Durum 0, Satır 4
Referans verilen 'T' tablosunda, 'FK_TRef_T_1' yabancı anahtarındaki referans sütun listesiyle eşleşen birincil veya aday anahtarlar yok .
Ancak ikinci komut farklı bir hata döndürür:
Msg 1773, Seviye 16, Durum 0, Satır 4
Yabancı anahtar 'FK_TRef_T_2', üzerinde birincil anahtar tanımlanmamış 'T' nesnesine örtük bir referansa sahip .
birinci durumda beklentinin birincil veya aday anahtarlar olduğunu , ikinci durumda beklentinin ise yalnızca birincil anahtar olduğunu görün .
SqlServer'ın ikinci komutla birincil anahtar dışında bir şey kullanıp kullanmayacağını kontrol edelim.
Şuna bazı benzersiz dizinler ve benzersiz anahtar eklersek T
:
CREATE UNIQUE INDEX IX_T_1 on T(id) INCLUDE (filler);
CREATE UNIQUE INDEX IX_T_2 on T(id) INCLUDE (c);
CREATE UNIQUE INDEX IX_T_3 ON T(id) INCLUDE (a, b);
ALTER TABLE T
ADD CONSTRAINT UQ_T UNIQUE CLUSTERED (id);
FK_TRef_T_1
oluşturma komutu başarılı, ancak FK_TRef_T_2
oluşturma komutu Msg 1773 ile hala başarısız oluyor.
Son olarak, üzerine birincil anahtar eklersek T
:
ALTER TABLE T
ADD CONSTRAINT PK_T PRIMARY KEY NONCLUSTERED (id);
FK_TRef_T_2
oluşturma komutu başarılı.
Tablonun hangi dizinlerine T
referans olarak tablonun yabancı anahtarları ile bakalım TRef
:
select
ix.index_id,
ix.name as index_name,
ix.type_desc as index_type_desc,
fk.name as fk_name
from sys.indexes ix
left join sys.foreign_keys fk on
fk.referenced_object_id = ix.object_id
and fk.key_index_id = ix.index_id
and fk.parent_object_id = object_id('TRef')
where ix.object_id = object_id('T');
bu döndürür:
index_id index_name index_type_desc fk_name
--------- ----------- ----------------- ------------
1 UQ_T CLUSTERED NULL
2 IX_T_1 NONCLUSTERED FK_TRef_T_1
3 IX_T_2 NONCLUSTERED NULL
4 IX_T_3 NONCLUSTERED NULL
5 PK_T NONCLUSTERED FK_TRef_T_2
FK_TRef_T_2
karşılık gelen bakın PK_T
.
Yani, evet, REFERENCES T
sözdizimi kullanımı ile yabancı anahtarın TRef
birincil anahtarına eşlenir T
.
Doğrudan SqlServer belgelerinde açıklanan bu tür bir davranış bulamadı, ancak özel Msg 1773 yanlışlıkla olmadığını gösteriyor. Muhtemelen böyle bir uygulama SQL Standardına uygunluk sağlar, aşağıda ANSI / ISO 9075-2: 2003'ün 11.8 bölümünden kısa alıntıdır.
Şema tanımı ve manipülasyonu
11.8 <başvuru kısıtlaması tanımı>
İşlev
Bir referans kısıtlaması belirleyin.
Biçim
<referential constraint definition> ::=
FOREIGN KEY <left paren> <referencing columns> <right paren>
<references specification>
<references specification> ::=
REFERENCES <referenced table and columns>
[ MATCH <match type> ]
[ <referential triggered action> ]
...
Sözdizimi Kuralları
...
3) Durum:
...
b) <Başvurulan tablo ve sütunlar> bir <başvuru sütun listesi> belirtmezse, başvurulan tablonun tablo tanımlayıcısı PRIMARY KEY'i belirten benzersiz bir kısıtlama içermelidir. Let başvurulan sütunları sütun veya benzersiz kısıtlama benzersiz kolonlar tarafından belirlenen sütun olmak ve izin başvurulan sütun
böyle bir sütun. <Referans verilen tablo ve sütunlar>, bu <benzersiz sütun listesi> ile aynı olan bir <referans sütun listesi> örtük olarak belirtilmiş kabul edilecektir.
...
Transact-SQL, ANSI SQL'i destekler ve genişletir. Ancak SQL Standardına tam olarak uymaz. Transact-SQL tarafından sağlanan destek düzeyini açıklayan SQL Server Transact-SQL ISO / IEC 9075-2 Standartları Destek Belgesi (kısaca MS-TSQLISO02, buraya bakın ) adlı bir belge vardır . Belge, standartlara göre uzantıları ve varyasyonları listeler. Örneğin, MATCH
yan tümcenin başvuru kısıtlaması tanımında desteklenmediğini belgeler . Ancak belirtilen standart parça ile ilgili belgelenmiş varyasyon yoktur. Benim görüşüme göre gözlemlenen davranış yeterince belgeleniyor.
REFERENCES T (<reference column list>)
Sözdizimi kullanıldığında, SqlServer başvurulan tablonun dizinleri arasında ilk uygun kümelenmemiş dizini (en az index_id
görünüşte olan, soru yorumlarında varsayılan olarak en küçük fiziksel boyuta sahip olanı değil) veya kümelenmiş dizini seçiyor gibi görünüyor. uygun ve kümelenmemiş indeksler yoktur. Bu davranış, SqlServer 2008'den (sürüm 10.0) beri tutarlı görünüyor. Bu sadece gözlemdir, bu durumda hiçbir garanti yoktur.