Belirli Bir Birincil Anahtarla İlişkili Yabancı Anahtarları Bulma


19

Belirli bir veritabanındaki hangi sütunların PK / FK ilişkileri yoluyla birleştirildiğini belirlemenin bir yolunu istiyorum. Belirli bir tablo için PK / FK bilgilerini

SELECT *  
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS cu 
WHERE EXISTS (
    SELECT tc.* 
    FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS tc 
    WHERE tc.CONSTRAINT_CATALOG = 'MyDatabase'  
        AND tc.TABLE_NAME = 'MyTable'  
        /*AND tc.CONSTRAINT_TYPE = 'PRIMARY KEY'*/
        AND tc.CONSTRAINT_NAME = cu.CONSTRAINT_NAME);
GO

ancak böyle bir sorgudan dönen bir PK için ilişkili FK'yi nasıl kurabilirim (bir tane varsayarak)?

Ben de başvurulan tablolar yoluyla alabilirsiniz biliyorum:

SELECT CONSTRAINT_NAME = name, 
       FOREIGN_SCHEMA = OBJECT_SCHEMA_NAME(parent_object_id), 
       FOREIGN_TABLE = OBJECT_NAME(parent_object_id), 
       REFERENCED_SCHEMA = OBJECT_SCHEMA_NAME(referenced_object_id), 
       REFERENCED_TABLE = OBJECT_NAME(referenced_object_id) 
FROM sys.foreign_keys
WHERE OBJECT_NAME(referenced_object_id) = 'MyTable';
GO

ancak şimdi açık sütun referanslarını almak için mücadele ediyorum.

QlikView için bir komut dosyası oluşturucu oluşturuyorum. Komut dosyasını oluşturmak için kısıtlamalara ve ilişkili bağlantılara ihtiyacım var. Herhangi bir sütun (varsa) için tüm kısıtlama bilgilerine ihtiyacım var.

Belirli bir veritabanı için tüm bilgileri tutan bir veritabanı sınıfı oluşturmak istiyorum. Bu sınıf yapısı database.table.column.constraintsdaha sonra PK / FK'lerdeki farklı sütunlar arasındaki eşleşmeleri elde etmek için kullanılacaktır.

Açıkçası bazı sütunlar sadece FK'lere sahip olacak ve bu durumda ben de karşılık gelen anahtarın PK bilgilerini almak istiyorum; bazılarının sadece PK'ları olacak ve sonra bunun tersini istiyorum. Bazıları elbette her ikisine de sahip olabilir.

Yanıtlar:


35

Yabancı anahtarları başvurulan tablolarla / sütunlarla eşleştirmek için basit bir sorgu:

SELECT
    o1.name AS FK_table,
    c1.name AS FK_column,
    fk.name AS FK_name,
    o2.name AS PK_table,
    c2.name AS PK_column,
    pk.name AS PK_name,
    fk.delete_referential_action_desc AS Delete_Action,
    fk.update_referential_action_desc AS Update_Action
FROM sys.objects o1
    INNER JOIN sys.foreign_keys fk
        ON o1.object_id = fk.parent_object_id
    INNER JOIN sys.foreign_key_columns fkc
        ON fk.object_id = fkc.constraint_object_id
    INNER JOIN sys.columns c1
        ON fkc.parent_object_id = c1.object_id
        AND fkc.parent_column_id = c1.column_id
    INNER JOIN sys.columns c2
        ON fkc.referenced_object_id = c2.object_id
        AND fkc.referenced_column_id = c2.column_id
    INNER JOIN sys.objects o2
        ON fk.referenced_object_id = o2.object_id
    INNER JOIN sys.key_constraints pk
        ON fk.referenced_object_id = pk.parent_object_id
        AND fk.key_index_id = pk.unique_index_id
ORDER BY o1.name, o2.name, fkc.constraint_column_id

Çıktıda sekiz sütun vardır: yabancı anahtarlar için tablo ve sütun adları (FK_table, FK_column), yabancı anahtar kısıtlamalarının adları (FK_name), başvurulan PK veya benzersiz dizin tablosu ve sütun adları (PK_table, PK_column), atıfta bulunulan PK veya benzersiz dizinin adı (PK_name) ve basamaklı eylemleri güncelle / sil (Delete_Action, Update_Action).

(Daha fazla çıktı sütunu eklemek için düzenlendi.)

EDIT: 6 yıl sonra bunun geliştirilmiş bir sürümü ile geri döndüm. Orijinal sorgunun gerçekten çok sütunlu yabancı anahtarları iyi işlemediğini fark ettim ve ayrıca devre dışı, güvenilmeyen veya dizine eklenmemiş yabancı anahtarları hızlı bir şekilde tanımlamak istedim. İşte tüm bunları düzelten yeni sürüm.

Çok kolon anahtarlar virgülle ayrılmış listeler halinde gösterilmiştir FK_columnsve PK_columnsgeleneksel kullanılarak, FOR XML/ STUFFkötüye. FK_indexesSütun Şekil potansiyel olarak karşılamak için kullanılabilir yabancı anahtar tablo herhangi bir dizin isimleri (özellikle birincil anahtar tablosuna siler veya güncelleştirme optimize etmek için) yabancı anahtar sütunları kullanılarak olarak istediği. Eğer öyleyse NULL, endekssiz bir yabancı anahtarınız var. PK tablo adına göre sıralamak, belirli PK / FK tabloları için filtre yapmak, vb. Yapmak isterseniz ORDER BY, ayarını yapabilir veya bir WHEREcümle ekleyebilirsiniz (aşağıda yorumlanmıştır).

SELECT
    fk.is_disabled,
    fk.is_not_trusted,
    OBJECT_SCHEMA_NAME(o1.object_id) AS FK_schema,
    o1.name AS FK_table,
    --Generate list of columns in referring side of foreign key
    STUFF(
        (
            SELECT ', ' + c1.name AS [text()]
            FROM sys.columns c1 INNER
                JOIN sys.foreign_key_columns fkc
                    ON c1.object_id = fkc.parent_object_id
                    AND c1.column_id = fkc.parent_column_id
            WHERE fkc.constraint_object_id = fk.object_id
            FOR XML PATH('')
        ), 1, 2, '') AS FK_columns,
    --Look for any indexes that will fully satisfy the foreign key columns
    STUFF(
        (
            SELECT ', ' + i.name AS [text()]
            FROM sys.indexes i
            WHERE i.object_id = o1.object_id
                AND NOT EXISTS ( --Find foreign key columns that don't match the index key columns
                    SELECT fkc.constraint_column_id, fkc.parent_column_id
                    FROM sys.foreign_key_columns fkc
                    WHERE fkc.constraint_object_id = fk.object_id
                    EXCEPT
                    SELECT ic.key_ordinal, ic.column_id
                    FROM sys.index_columns ic
                    WHERE ic.object_id = i.object_id AND ic.index_id = i.index_id
                )
            FOR XML PATH('')
        ), 1, 2, '') AS FK_indexes,
    fk.name AS FK_name,
    OBJECT_SCHEMA_NAME(o2.object_id) AS PK_schema,
    o2.name AS PK_table,
    --Generate list of columns in referenced (i.e. PK) side of foreign key
    STUFF(
        (
            SELECT ', ' + c2.name AS [text()]
            FROM sys.columns c2
                INNER JOIN sys.foreign_key_columns fkc
                    ON c2.object_id = fkc.referenced_object_id
                    AND c2.column_id = fkc.referenced_column_id
            WHERE fkc.constraint_object_id = fk.object_id
            FOR XML PATH('')
        ), 1, 2, '') AS PK_columns,
    pk.name AS PK_name,
    fk.delete_referential_action_desc AS Delete_Action,
    fk.update_referential_action_desc AS Update_Action
FROM sys.objects o1
    INNER JOIN sys.foreign_keys fk
        ON o1.object_id = fk.parent_object_id
    INNER JOIN sys.objects o2
        ON fk.referenced_object_id = o2.object_id
    INNER JOIN sys.key_constraints pk
        ON fk.referenced_object_id = pk.parent_object_id
        AND fk.key_index_id = pk.unique_index_id
--WHERE o2.name = 'Company_Address'
ORDER BY o1.name, o2.name

7

Bu sorgu, veritabanındaki tüm FK ilişkilerini (FK kısıtlama adı, şema / başvuru tablosunun tablosu, başvuru sütunu adı, başvurulan tablonun şeması / tablosu ve başvurulan sütun adı) sağlar. Çok sütunlu bir kısıtlama için birden çok satır olacaktır.

SELECT 
    FK = OBJECT_NAME(pt.constraint_object_id),
    Referencing_table = QUOTENAME(OBJECT_SCHEMA_NAME(pt.parent_object_id))
            + '.' + QUOTENAME(OBJECT_NAME(pt.parent_object_id)),
    Referencing_col = QUOTENAME(pc.name), 
    Referenced_table = QUOTENAME(OBJECT_SCHEMA_NAME(pt.referenced_object_id)) 
            + '.' + QUOTENAME(OBJECT_NAME(pt.referenced_object_id)),
    Referenced_col = QUOTENAME(rc.name)
FROM sys.foreign_key_columns AS pt
INNER JOIN sys.columns AS pc
ON pt.parent_object_id = pc.[object_id]
AND pt.parent_column_id = pc.column_id
INNER JOIN sys.columns AS rc
ON pt.referenced_column_id = rc.column_id
AND pt.referenced_object_id = rc.[object_id]
ORDER BY Referencing_table, FK, pt.constraint_column_id;

Belirli bir birincil anahtar kısıtlamasının sütunlarının peşindeyseniz ve bu PK kısıtlamasının adını zaten biliyorsanız, bunu yazabilirsiniz:

DECLARE @PK_Constraint SYSNAME = N'Name of PK constraint';

SELECT
    FK = OBJECT_NAME(fkc.constraint_object_id),
    Referencing_table = QUOTENAME(OBJECT_SCHEMA_NAME(fkc.parent_object_id))
            + '.' + QUOTENAME(OBJECT_NAME(fkc.parent_object_id)),
    Referencing_col = QUOTENAME(pc.name), 
    Referenced_table = QUOTENAME(OBJECT_SCHEMA_NAME(fkc.referenced_object_id)) 
            + '.' + QUOTENAME(OBJECT_NAME(fkc.referenced_object_id)),
    Referenced_col = QUOTENAME(rc.name)
FROM sys.foreign_key_columns AS fkc
INNER JOIN sys.columns AS pc
ON fkc.parent_object_id = pc.[object_id]
AND fkc.parent_column_id = pc.column_id
INNER JOIN sys.columns AS rc
ON fkc.referenced_column_id = rc.column_id
AND fkc.referenced_object_id = rc.[object_id]
WHERE EXISTS 
(
  SELECT 1 FROM sys.indexes AS i
  INNER JOIN sys.foreign_keys AS fk
  ON i.[object_id] = fk.referenced_object_id
  AND i.index_id = fk.key_index_id
  AND fk.[object_id] = fkc.constraint_object_id
  AND i.name = @PK_Constraint
)
ORDER BY Referencing_table, FK, fkc.constraint_column_id;

PK adını diğer bilgilerle birlikte eklemek istiyorsanız:

SELECT 
    FK = OBJECT_NAME(fkc.constraint_object_id),
    Referencing_table = QUOTENAME(OBJECT_SCHEMA_NAME(fkc.parent_object_id))
            + '.' + QUOTENAME(OBJECT_NAME(fkc.parent_object_id)),
    Referencing_col = QUOTENAME(pc.name),
    Referenced_table = QUOTENAME(OBJECT_SCHEMA_NAME(fkc.referenced_object_id)) 
            + '.' + QUOTENAME(OBJECT_NAME(fkc.referenced_object_id)),
    Referenced_col = QUOTENAME(rc.name),
    PK = pk.name
FROM sys.foreign_key_columns AS fkc
INNER JOIN sys.columns AS pc
ON fkc.parent_object_id = pc.[object_id]
AND fkc.parent_column_id = pc.column_id
INNER JOIN sys.columns AS rc
ON fkc.referenced_column_id = rc.column_id
AND fkc.referenced_object_id = rc.[object_id]
INNER JOIN (SELECT i.name, fk.[object_id]
  FROM sys.indexes AS i
  INNER JOIN sys.foreign_keys AS fk
  ON i.[object_id] = fk.referenced_object_id
  AND i.index_id = fk.key_index_id
) AS pk
ON pk.[object_id] = fkc.constraint_object_id
ORDER BY Referencing_table, FK, fkc.constraint_column_id;

Sütun listesini, örneğin, virgülle ayrılmış bir listede veya tek tek sütunlarda, satırlara yayılmak yerine almanın hileleri de vardır, ancak tam olarak hangi formu tam olarak bilinceye kadar bu sorguları değiştirmek için yatırım yapmayacağım. peşindesin.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.