【问题标题】:Stored procedure to retrieve all foreign key columns with values in SQL server用于检索 SQL Server 中具有值的所有外键列的存储过程
【发布时间】:2015-03-08 22:37:44
【问题描述】:

我正在尝试创建一个存储过程,当在该表中提供一个表名和一个 ID 时,它将返回一个外键列 + 其值的列表(一个包含两列的表)。保证一个 ID 是唯一的。结果应包含与外键列数相等的行数。如果没有找到外键,则应生成 NULL 行,例如Key = NULL, Value = NULL.

考虑以下示例表和数据:

员工表:

 Id | Name       | AddressId | JobId 
----|------------|-----------|-------
 1  | John Smith | 2         | 3

Foreign keys:
- FK_Employee_Address
- FK_Employee_Job

地址表:

 Id | Street    | Suite  | City     | Postal Code | CountryId 
----|-----------|--------|----------|-------------|-----------
 2  | 1 Main St | 101    | New York | 10001       | 4

Foreign keys:
- FK_Address_Country

国家表:

 Id | Name
----|------
 4  | USA

职位表:

 Id  | Title
-----|-----------
 3   | Developer 

问题:如何在生成的 SQL 查询中获取所有外键列 + 它们的值,每行一个?

测试用例 1:

spGetForeignKeyColumns 'Employee', 1

Key       | Value
----------|------
AddressId | 2
JobId     | 3

测试用例 2:

spGetForeignKeyColumns 'Address', 2

Key       | Value
----------|------
CountryId | 4

测试用例 3:

spGetForeignKeyColumns 'Country', 4

Key       | Value
----------|------
NULL      | NULL

假设 Id 总是 int 是安全的,所以不会有任何类型冲突。

尝试的解决方案。我知道如何使用以下 SELECT 语句检索给定表的所有外键列没有值

SELECT * FROM (    
    SELECT f.name AS ForeignKey, OBJECT_NAME(f.parent_object_id) AS TableName,
    COL_NAME(fc.parent_object_id, fc.parent_column_id) AS ColumnName,
    OBJECT_NAME(f.referenced_object_id) AS ReferenceTableName,
    COL_NAME(fc.referenced_object_id, fc.referenced_column_id) AS ReferenceColumnName
FROM sys.foreign_keys AS f
INNER JOIN sys.foreign_key_columns AS fc
ON f.OBJECT_ID = fc.constraint_object_id) fk
WHERE TableName = @TableName

上面的 Employee 表会产生以下结果:

 ForeignKey          | TableName       | ColumnName | ReferenceTableName | ReferenceColumnName
---------------------|-----------------|------------|--------------------|---------------------
 FK_Employee_Address | Employee        | AddressId  | Address            | Id
 FK_Employee_Job     | Employee        | JobId      | Job                | Id

【问题讨论】:

    标签: sql sql-server stored-procedures foreign-keys


    【解决方案1】:

    你离得很近。我使用了您在问题中提供的查询,并添加了代码来检索相关表的主键。剩下的就是构建 SQL 以提取值并动态执行它。试试这个

    DECLARE @TableName  VARCHAR(64) = 'Employee',
            @Id     INT = 1,
            @SQL    NVARCHAR(MAX) = '';
    
    --Comment this out to debug
    SELECT @SQL = @SQL + '
    SELECT ''' + ColumnName + ''' as [Key], CONVERT(VARCHAR(255), ' + quotename(ColumnName) + ') as Value
    FROM ' + quotename(TableName) + ' data
    WHERE ' + quotename(primarykey) + ' = @Id
    UNION
    '
    -- Uncomment this to debug...
    --SELECT ColumnName, quotename(TableName), quotename(primarykey) 
    --The column that returns null is the one with the problem
    FROM (    
        SELECT f.name AS ForeignKey, 
            OBJECT_NAME(f.parent_object_id) AS TableName,
            COL_NAME(fc.parent_object_id, fc.parent_column_id) AS ColumnName,
            OBJECT_NAME(f.referenced_object_id) AS ReferenceTableName,
            COL_NAME(fc.referenced_object_id, fc.referenced_column_id) AS ReferenceColumnName,
            COL_NAME(ic.object_id, ic.column_id) as primarykey
        FROM sys.foreign_keys AS f
            INNER JOIN sys.foreign_key_columns fc ON f.OBJECT_ID = fc.constraint_object_id
            LEFT JOIN sys.index_columns ic ON ic.object_id = f.parent_object_id
            LEFT JOIN sys.indexes i ON i.object_id = ic.object_id and i.is_primary_key = 1 and i.index_id = ic.index_id) fk
    WHERE TableName = @TableName
    
    IF NULLIF(@SQL, '') IS NULL
    BEGIN
        SELECT NULL AS [Key], NULL as Value
    END
    ELSE
    BEGIN
        SET @SQL = LEFT(@SQL, LEN(@SQL) - 7)
        EXEC sp_executesql @SQL, N'@Id INT', @Id
    END
    

    我没有遍历你所有的测试用例,但这应该让你非常接近。另外,我将值转换为 VARCHAR,因为如果不是所有键都是整数,它将引发错误。

    希望有帮助

    【讨论】:

    • 我认为这行不通。现在它说Invalid length parameter passed to the LEFT or SUBSTRING function.,并且生成的@SQL 是空的(调试时),但我很难理解一般方法。例如,我在那里看到一个 UNION,它后来被截断,那么首先添加它有什么意义呢?您是否尝试针对任何数据运行查询?我唯一清楚的是我必须使用动态 SQL 查询。还有其他方法吗?我想这将很难调试,即使它有效。
    • 我在我的一个本地数据库上的一张表上运行它。它工作正常。如果@SQL 为空白,则意味着您的关系设置与我的不同,您可能需要调整主键检索。将为每个外键重复选择语句,并且在查询末尾会有一个 UNION 需要被截断......如果主查询没有返回任何记录,那么 LEFT 将失败。删除 \@SQL = \@SQL + ' 部分以查看主查询返回的内容。我将更新答案以适应没有外键的表
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-01-16
    • 2018-07-22
    • 1970-01-01
    • 1970-01-01
    • 2017-03-14
    • 2015-01-30
    • 1970-01-01
    相关资源
    最近更新 更多