Tìm khóa ngoại liên kết với khóa chính đã cho


19

Tôi muốn một cách để thiết lập các cột trong cơ sở dữ liệu nhất định được nối thông qua các mối quan hệ PK / FK. Tôi có thể trả về thông tin PK / FK cho một bảng đã cho qua

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

nhưng đối với một PK được trả về từ một truy vấn như vậy, làm cách nào để thiết lập FK liên quan (giả sử có một)?

Tôi biết bạn cũng có thể lấy các bảng được tham chiếu qua:

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

nhưng tôi đang vật lộn để có được các tài liệu tham khảo cột rõ ràng.

Tôi đang tạo một trình tạo tập lệnh cho QlikView. Để tạo tập lệnh, tôi cần các ràng buộc và các liên kết liên quan. Tôi cần tất cả các thông tin ràng buộc cho bất kỳ cột nào (nếu có).

Tôi muốn xây dựng một lớp cơ sở dữ liệu chứa tất cả thông tin cho một cơ sở dữ liệu nhất định. Cấu trúc lớp nàydatabase.table.column.constraints này sau đó sẽ được sử dụng để có được các kết quả khớp giữa các cột khác nhau trên PK / FK.

Rõ ràng một số cột sẽ chỉ có FK và trong trường hợp này tôi cũng muốn lấy thông tin PK của khóa tương ứng; một số sẽ chỉ có PK và sau đó tôi muốn ngược lại. Một số tất nhiên có thể có cả hai.

Câu trả lời:


35

Đây là một truy vấn đơn giản để khớp các khóa ngoại với các bảng / cột được tham chiếu của chúng:

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

Đầu ra có tám cột: tên bảng và cột cho các khóa ngoại (FK_table, FK_column), tên của các ràng buộc khóa ngoài (FK_name), PK được tham chiếu hoặc tên chỉ mục duy nhất và tên cột (PK_table, PK_column), tên của PK được tham chiếu hoặc chỉ mục duy nhất (PK_name) và các hành động cập nhật / xóa tầng (Delete_Action, Update_Action).

(Đã chỉnh sửa để thêm một số cột đầu ra.)

EDIT: Tôi trở lại 6 năm sau với phiên bản cải tiến này. Tôi nhận ra rằng truy vấn ban đầu không thực sự xử lý tốt các khóa ngoại nhiều cột và tôi cũng muốn có thể nhanh chóng xác định các khóa ngoại bị vô hiệu hóa, không tin cậy hoặc không bị khóa. Vì vậy, đây là phiên bản mới sửa chữa tất cả điều đó.

Các khóa nhiều cột được hiển thị dưới dạng danh sách được phân tách bằng dấu phẩy trong FK_columnsPK_columns, bằng cách sử dụng truyền thống FOR XML/ STUFFlạm dụng. Các FK_indexeschương trình cột tên của bất kỳ chỉ số trên bàn nước ngoài quan trọng mà khả năng có thể được sử dụng để thỏa mãn tìm kiếm bằng cách sử dụng các cột khóa ngoài (chủ yếu là để tối ưu hóa xóa hoặc cập nhật vào bảng khóa chính). Nếu vậy NULL, thì bạn đã có một khóa ngoại chưa được giải thích. Bạn có thể điều chỉnh ORDER BYhoặc thêm một WHEREmệnh đề (nhận xét bên dưới) nếu bạn muốn sắp xếp theo tên bảng PK, bộ lọc cho các bảng PK / FK cụ thể, v.v.

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

Truy vấn này cung cấp cho bạn tất cả các mối quan hệ FK trong cơ sở dữ liệu - tên ràng buộc FK, lược đồ / bảng của bảng tham chiếu, tên cột tham chiếu, lược đồ / bảng của bảng tham chiếu và tên cột được tham chiếu. Sẽ có nhiều hàng cho một ràng buộc nhiều cột.

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;

Nếu bạn theo sau các cột từ một ràng buộc khóa chính cụ thể và bạn đã biết tên của ràng buộc PK đó, bạn có thể viết điều này:

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;

Nếu bạn chỉ muốn bao gồm tên PK cùng với các thông tin khác:

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;

Ngoài ra, có một số mẹo để đưa danh sách cột vào, ví dụ, danh sách được phân tách bằng dấu phẩy hoặc các cột riêng lẻ, thay vì được trải rộng trên các hàng, nhưng tôi sẽ không đầu tư vào việc sửa đổi các truy vấn này để tạo ra cho đến khi tôi biết chính xác dạng nào bạn đang theo đuổi

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.