ค้นหาคีย์ต่างประเทศที่เกี่ยวข้องกับคีย์หลักที่กำหนด


19

ฉันต้องการวิธีในการสร้างคอลัมน์ในฐานข้อมูลที่กำหนดที่จะเข้าร่วมผ่านความสัมพันธ์ PK / FK ฉันสามารถส่งคืนข้อมูล PK / FK สำหรับตารางที่กำหนดผ่าน

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

แต่สำหรับ PK ที่ส่งคืนจากคิวรีดังกล่าวฉันจะสร้าง FK ที่เชื่อมโยงได้อย่างไร (สมมติว่ามี)

ฉันรู้ว่าคุณยังสามารถรับตารางอ้างอิงผ่าน:

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

แต่ตอนนี้ฉันกำลังดิ้นรนเพื่อรับการอ้างอิงคอลัมน์ที่ชัดเจน

ฉันกำลังสร้างตัวสร้างสคริปต์สำหรับ QlikView เพื่อสร้างสคริปต์ฉันต้องการข้อ จำกัด และลิงค์ที่เกี่ยวข้อง ฉันต้องการข้อมูลข้อ จำกัด ทั้งหมดสำหรับคอลัมน์ที่ระบุ (ถ้ามี)

ฉันต้องการสร้างคลาสฐานข้อมูลที่เก็บข้อมูลทั้งหมดสำหรับฐานข้อมูลที่กำหนด โครงสร้างคลาสนี้database.table.column.constraintsจะถูกใช้เพื่อรับการจับคู่ระหว่างคอลัมน์ต่าง ๆ ใน PK / FK

เห็นได้ชัดว่าบางคอลัมน์จะมี FK เท่านั้นและในกรณีนี้ฉันต้องการดึงข้อมูล PK ของคีย์ที่เกี่ยวข้อง บางคนจะมี PKs เท่านั้นจากนั้นฉันต้องการย้อนกลับ บางหลักสูตรสามารถมีได้ทั้งคู่

คำตอบ:


35

ต่อไปนี้เป็นคำค้นหาทั่วไปเพื่อจับคู่คีย์ต่างประเทศกับตาราง / คอลัมน์ที่อ้างอิง:

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

เอาต์พุตมีแปดคอลัมน์: ชื่อตารางและคอลัมน์สำหรับ foreign key (FK_table, FK_column), ชื่อของข้อ จำกัด foreign-key (FK_name), PK ที่อ้างอิงหรือตารางดัชนีเฉพาะและชื่อคอลัมน์ (PK_table, PK_column) ชื่อของ PK ที่อ้างอิงหรือดัชนีที่ไม่ซ้ำกัน (PK_name) และการดำเนินการอัพเดต / ลบทั้งหมด (Delete_Action, Update_Action)

(แก้ไขเพื่อเพิ่มคอลัมน์เอาต์พุตเพิ่มเติม)

แก้ไข:ฉันกลับมาอีก 6 ปีในภายหลังด้วยการปรับปรุงนี้ ฉันรู้ว่าข้อความค้นหาดั้งเดิมไม่สามารถจัดการกับคีย์ต่างประเทศหลายคอลัมน์ได้ดีและฉันก็ต้องการที่จะสามารถระบุได้อย่างรวดเร็วปิดการใช้งานไม่น่าเชื่อถือหรือไม่ได้คีย์ต่างประเทศ ดังนั้นนี่คือเวอร์ชั่นใหม่ที่สามารถแก้ไขทั้งหมดได้

ปุ่มหลายคอลัมน์จะแสดงเป็นรายการที่คั่นด้วยเครื่องหมายจุลภาคในFK_columnsและPK_columnsโดยใช้แบบดั้งเดิมFOR XML/ STUFFการละเมิด FK_indexesแสดงชื่อคอลัมน์ของดัชนีใด ๆ บนโต๊ะต่างประเทศที่สำคัญที่อาจนำมาใช้เพื่อตอบสนองความพยายามใช้คอลัมน์คีย์ต่างประเทศ (ส่วนใหญ่สำหรับการเพิ่มประสิทธิภาพการลบหรือการปรับปรุงตารางคีย์หลัก) ถ้าเป็นNULLเช่นนั้นคุณมีรหัสต่างประเทศที่ไม่ได้ทำดัชนี คุณสามารถปรับแต่งORDER BYหรือเพิ่มส่วนWHEREคำสั่ง (ใส่ความเห็นด้านล่าง) หากคุณต้องการเรียงลำดับตามชื่อตาราง PK ตัวกรองสำหรับตาราง PK / FK เฉพาะเป็นต้น

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

แบบสอบถามนี้ให้คุณความสัมพันธ์ FK ทั้งหมดในฐานข้อมูล - ชื่อข้อ จำกัด FK, สคีมา / ตารางของตารางอ้างอิง, ชื่อคอลัมน์อ้างอิง, สคีมา / ตารางของตารางอ้างอิงและชื่อคอลัมน์ที่อ้างอิง จะมีหลายแถวสำหรับข้อ จำกัด หลายคอลัมน์

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;

หากคุณอยู่หลังคอลัมน์จากข้อ จำกัด คีย์หลักเฉพาะและคุณรู้ชื่อของข้อ จำกัด PK นั้นแล้วคุณสามารถเขียนสิ่งนี้:

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 พร้อมกับข้อมูลอื่น ๆ :

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;

นอกจากนี้ยังมีเทคนิคในการรับรายการคอลัมน์พูดเป็นรายการที่คั่นด้วยเครื่องหมายจุลภาคหรือแต่ละคอลัมน์แทนที่จะแพร่กระจายข้ามแถว แต่ฉันจะไม่ลงทุนในการแก้ไขการค้นหาเหล่านี้เพื่อสร้างสิ่งนั้นจนกว่าฉันจะรู้ว่าแบบฟอร์มใด คุณหลังจาก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.