You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何查询关系型数据库中两张表的关联路径及关联键

Alright, let's figure out how to solve this problem. Since you don't have access to the database diagram and need to batch check relationship chains between table pairs (like A and D) along with the required join columns, we can leverage the database's built-in system catalogs to retrieve this metadata automatically. Below are tailored solutions for the most common database systems:

Solution for MySQL

MySQL stores relationship metadata in the information_schema database. This recursive CTE will trace the path from table A to D, then generate the full JOIN query:

WITH RECURSIVE table_relationships AS (
    -- Start with direct relationships from table A
    SELECT 
        tc.table_name AS from_table,
        kcu.column_name AS from_column,
        ccu.table_name AS to_table,
        ccu.column_name AS to_column,
        1 AS depth
    FROM 
        information_schema.table_constraints tc
        JOIN information_schema.key_column_usage kcu 
            ON tc.constraint_name = kcu.constraint_name
        JOIN information_schema.constraint_column_usage ccu 
            ON tc.constraint_name = ccu.constraint_name
    WHERE 
        tc.constraint_type = 'FOREIGN KEY'
        AND kcu.table_name = 'A' -- Replace with your starting table
    UNION ALL
    -- Recursively follow relationships until we reach table D
    SELECT 
        tr.from_table,
        tr.from_column,
        ccu.table_name AS to_table,
        ccu.column_name AS to_column,
        tr.depth + 1 AS depth
    FROM 
        table_relationships tr
        JOIN information_schema.table_constraints tc 
            ON tr.to_table = kcu.table_name
        JOIN information_schema.key_column_usage kcu 
            ON tc.constraint_name = kcu.constraint_name
        JOIN information_schema.constraint_column_usage ccu 
            ON tc.constraint_name = ccu.constraint_name
    WHERE 
        tc.constraint_type = 'FOREIGN KEY'
        AND tr.to_table != 'D' -- Stop when we hit the target table
)
-- Build the final JOIN query string
SELECT 
    CONCAT('SELECT A.*, D.* FROM A ', 
           GROUP_CONCAT(
               CONCAT('JOIN ', tr.to_table, ' ON ', tr.from_table, '.', tr.from_column, ' = ', tr.to_table, '.', tr.to_column)
               ORDER BY depth SEPARATOR ' '
           ),
           ' JOIN D ON ', last_tr.to_table, '.', last_tr.to_column, ' = D.', (SELECT column_name FROM information_schema.columns WHERE table_name='D' AND column_key='PRI')
    ) AS full_join_query
FROM 
    table_relationships tr
    JOIN (
        SELECT from_table, from_column, to_table, to_column 
        FROM table_relationships 
        WHERE to_table = 'D'
    ) last_tr ON tr.depth = last_tr.depth - 1
WHERE 
    tr.depth = (SELECT MAX(depth) FROM table_relationships WHERE to_table = 'D') - 1
GROUP BY 
    tr.from_table, tr.from_column;
Solution for SQL Server

SQL Server uses system views like sys.tables and sys.foreign_keys to store relationship data. Here's the equivalent recursive query:

WITH RECURSIVE table_relationships AS (
    -- Start with direct relationships from table A
    SELECT 
        OBJECT_NAME(fk.parent_object_id) AS from_table,
        col_parent.name AS from_column,
        OBJECT_NAME(fk.referenced_object_id) AS to_table,
        col_ref.name AS to_column,
        1 AS depth
    FROM 
        sys.foreign_keys fk
        JOIN sys.foreign_key_columns fkc 
            ON fk.object_id = fkc.constraint_object_id
        JOIN sys.columns col_parent 
            ON fkc.parent_object_id = col_parent.object_id 
            AND fkc.parent_column_id = col_parent.column_id
        JOIN sys.columns col_ref 
            ON fkc.referenced_object_id = col_ref.object_id 
            AND fkc.referenced_column_id = col_ref.column_id
    WHERE 
        OBJECT_NAME(fk.parent_object_id) = 'A' -- Replace with your starting table
    UNION ALL
    -- Recursively follow relationships until we reach table D
    SELECT 
        tr.from_table,
        tr.from_column,
        OBJECT_NAME(fk.referenced_object_id) AS to_table,
        col_ref.name AS to_column,
        tr.depth + 1 AS depth
    FROM 
        table_relationships tr
        JOIN sys.foreign_keys fk 
            ON tr.to_table = OBJECT_NAME(fk.parent_object_id)
        JOIN sys.foreign_key_columns fkc 
            ON fk.object_id = fkc.constraint_object_id
        JOIN sys.columns col_ref 
            ON fkc.referenced_object_id = col_ref.object_id 
            AND fkc.referenced_column_id = col_ref.column_id
    WHERE 
        OBJECT_NAME(fk.referenced_object_id) != 'D' -- Stop when we hit the target table
)
-- Build the final JOIN query string
SELECT 
    CONCAT('SELECT A.*, D.* FROM A ',
           STRING_AGG(
               CONCAT('JOIN ', tr.to_table, ' ON ', tr.from_table, '.', tr.from_column, ' = ', tr.to_table, '.', tr.to_column),
               ' '
           ) WITHIN GROUP (ORDER BY depth),
           ' JOIN D ON ', last_tr.to_table, '.', last_tr.to_column, ' = D.', (SELECT name FROM sys.columns WHERE object_id = OBJECT_ID('D') AND is_identity = 1 OR (SELECT COUNT(*) FROM sys.columns WHERE object_id = OBJECT_ID('D') AND column_id IN (SELECT column_id FROM sys.index_columns WHERE object_id = OBJECT_ID('D') AND index_id = 1)) = 1)
    ) AS full_join_query
FROM 
    table_relationships tr
    JOIN (
        SELECT from_table, from_column, to_table, to_column 
        FROM table_relationships 
        WHERE to_table = 'D'
    ) last_tr ON tr.depth = last_tr.depth - 1
WHERE 
    tr.depth = (SELECT MAX(depth) FROM table_relationships WHERE to_table = 'D') - 1
GROUP BY 
    tr.from_table, tr.from_column;
Solution for PostgreSQL

PostgreSQL uses information_schema tables similar to MySQL, with a few differences in metadata access. Here's the recursive query for PostgreSQL:

WITH RECURSIVE table_relationships AS (
    -- Start with direct relationships from table A
    SELECT 
        tc.table_name AS from_table,
        kcu.column_name AS from_column,
        ccu.table_name AS to_table,
        ccu.column_name AS to_column,
        1 AS depth
    FROM 
        information_schema.table_constraints tc
        JOIN information_schema.key_column_usage kcu 
            ON tc.constraint_name = kcu.constraint_name
        JOIN information_schema.constraint_column_usage ccu 
            ON tc.constraint_name = ccu.constraint_name
    WHERE 
        tc.constraint_type = 'FOREIGN KEY'
        AND kcu.table_name = 'A' -- Replace with your starting table
    UNION ALL
    -- Recursively follow relationships until we reach table D
    SELECT 
        tr.from_table,
        tr.from_column,
        ccu.table_name AS to_table,
        ccu.column_name AS to_column,
        tr.depth + 1 AS depth
    FROM 
        table_relationships tr
        JOIN information_schema.table_constraints tc 
            ON tr.to_table = kcu.table_name
        JOIN information_schema.key_column_usage kcu 
            ON tc.constraint_name = kcu.constraint_name
        JOIN information_schema.constraint_column_usage ccu 
            ON tc.constraint_name = ccu.constraint_name
    WHERE 
        tc.constraint_type = 'FOREIGN KEY'
        AND tr.to_table != 'D' -- Stop when we hit the target table
)
-- Build the final JOIN query string
SELECT 
    CONCAT('SELECT A.*, D.* FROM A ',
           STRING_AGG(
               CONCAT('JOIN ', tr.to_table, ' ON ', tr.from_table, '.', tr.from_column, ' = ', tr.to_table, '.', tr.to_column),
               ' '
           ORDER BY depth),
           ' JOIN D ON ', last_tr.to_table, '.', last_tr.to_column, ' = D.', (SELECT column_name FROM information_schema.columns WHERE table_name='D' AND column_key='PRI')
    ) AS full_join_query
FROM 
    table_relationships tr
    JOIN (
        SELECT from_table, from_column, to_table, to_column 
        FROM table_relationships 
        WHERE to_table = 'D'
    ) last_tr ON tr.depth = last_tr.depth - 1
WHERE 
    tr.depth = (SELECT MAX(depth) FROM table_relationships WHERE to_table = 'D') - 1
GROUP BY 
    tr.from_table, tr.from_column;

Notes:

  • Replace 'A' and 'D' with your actual table names in each query.
  • If multiple relationship paths exist between A and D (e.g., A→B→D and A→C→D), the query will return all valid JOIN statements.
  • This base version handles single-column primary/foreign keys. For composite keys, you'll need to extend the query to aggregate multiple join columns into a single condition.

内容的提问来源于stack exchange,提问作者Make an Impact

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:03:01