使用SQL Server中的值检索所有外键列的存储过程

时间:2015-01-10 19:33:37

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

我正在尝试创建一个存储过程,该存储过程将返回外键列的列表及其值(其中包含两列的表),当在该表中提供表名和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

1 个答案:

答案 0 :(得分: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,因为如果不是所有键都是整数,它将抛出错误。

希望有所帮助