it-swarm-eu.dev

Najděte cizí klíče spojené s daným primárním klíčem

Chci způsob, jak zjistit, které sloupce v dané databázi jsou spojeny prostřednictvím vztahů PK/FK. Mohu vrátit informace o PK/FK pro danou tabulku přes

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

ale pro PK vrácený z takového dotazu, jak mohu založit přidružené FK (za předpokladu, že existuje)?

Vím, že můžete také získat referenční tabulky prostřednictvím:

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

ale nyní se snažím získat explicitní odkazy na sloupce.

Vytvářím skriptový generátor pro QlikView. K vytvoření skriptu potřebuji omezení a související odkazy. Potřebuji všechny informace o omezeních pro daný sloupec (pokud existují).

Chci postavit databázovou třídu, která obsahuje všechny informace o dané databázi. Tato struktura třídy database.table.column.constraints pak bude použito k získání shody mezi různými sloupci na PK/FK.

Je zřejmé, že některé sloupce budou mít pouze FK, a v tomto případě také chci načíst informace o PK příslušného klíče; někteří budou mít jen PK a pak chci naopak. Někteří samozřejmě mohou mít obojí.

19
MoonKnight

Zde je jednoduchý dotaz, který porovnává cizí klíče s jejich odkazovanými tabulkami/sloupci:

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

Výstup má osm sloupců: názvy tabulek a sloupců pro cizí klíče (FK_table, FK_column), názvy omezení pro cizí klíče (FK_name), odkazované PK nebo jedinečné indexové tabulky a názvy sloupců (PK_table, PK_column), název referenčního PK nebo jedinečného indexu (PK_name) a aktualizace/smazání kaskádových akcí (Delete_Action, Update_Action).

(Upraveno pro přidání dalších výstupních sloupců.)

ÚPRAVA: Vrátím se o 6 let později se zlepšenou verzí. Uvědomil jsem si, že původní dotaz opravdu nezvládne více sloupcové cizí klíče dobře, a také jsem chtěl být schopen rychle identifikovat zakázané, nedůvěryhodné nebo neindexované cizí klíče. Tady je nová verze, která vše opravuje.

Vícenásobné sloupce se zobrazují jako seznamy oddělené čárkami v FK_columns A PK_columns, Přičemž se používá tradiční zneužití FOR XML/STUFF. Sloupec FK_indexes Zobrazuje názvy všech indexů v tabulce cizího klíče, které by mohly být potenciálně použity k uspokojení vyhledávání pomocí sloupců cizího klíče (hlavně pro optimalizaci vymazání nebo aktualizace tabulky primárního klíče). Pokud je to NULL, pak máte neindexovaný cizí klíč. Můžete vyladit ORDER BY, Nebo přidat klauzuli WHERE (komentář je uveden níže), pokud chcete seřadit podle názvu tabulky PK, filtru pro konkrétní tabulky PK/FK atd.

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
36
db2

Tento dotaz vás spojí se všemi vztahy FK v databázi - název omezení FK, schéma/tabulka odkazující tabulky, odkazující název sloupce, schéma/tabulka odkazované tabulky a odkazovaný název sloupce. Pro více sloupců bude existovat více řádků.

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;

Pokud jste za sloupci z specifického omezení primárního klíče a již znáte název tohoto omezení PK, můžete napsat toto:

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;

Pokud chcete pouze přidat název PK spolu s dalšími informacemi:

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;

Existují také triky, jak získat seznam sloupců, řekněme, seznam oddělený čárkami nebo jednotlivé sloupce, místo toho, aby byly rozloženy do řádků, ale nebudu investovat do úpravy těchto dotazů, aby to bylo vytvořeno, dokud nebudu přesně vědět, v jaké formě jsi po.

7
Aaron Bertrand