我正在尝试创建一个存储过程,该存储过程将返回外键列的列表及其值(其中包含两列的表),当在该表中提供表名和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
答案 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,因为如果不是所有键都是整数,它将抛出错误。
希望有所帮助