如何获取存储过程中引用的所有列的列表?

How can I get a list of all columns referenced in a stored procedure?

我有许多使用 CTE、temp tables、table 变量和子查询的存储过程,我需要获取所有列的列表(包括数据库、模式、和 table/view) 在存储过程中使用。我不需要获取临时 tables、table 变量或 CTE 中的列。我只需要在 table 中定义的引用列或在我的服务器上的数据库中查看。

我试过 sys.dm_sql_referenced_entities and sys.sql_expression_dependencies 但在第一个 select 查询或 select 在 CTE 中编辑后它们没有 return 列。

执行存储过程时,它会被解析并编译成查询计划,这会被缓存,您可以通过 sys.dm_exec_cached_plans 和 sys.dm_exec_query_plan 以 XML 格式访问它。查询计划记录了每段解析代码的'output list'。查看存储过程使用了哪些列只是查询这个 XML 的问题,就像这样:

--Execute the stored procedure to put its query plan in the cache
exec sys.sp_columns ''

DECLARE @TargetObject nvarchar(100) = 'sys.sp_columns';

WITH XMLNAMESPACES (
    'http://schemas.microsoft.com/sqlserver/2004/07/showplan' as ns1
), CompiledPlan AS (
    SELECT 
        (SELECT query_plan FROM sys.dm_exec_query_plan(cp.plan_handle)) qp,
        (SELECT ObjectID FROM sys.dm_exec_sql_text(cp.plan_handle)) ob
    FROM sys.dm_exec_cached_plans cp
    WHERE objtype = 'Proc'
), ColumnReferences AS (
    SELECT DISTINCT
        ob,
        p.query('.').value('./ns1:ColumnReference[1]/@Database', 'sysname') AS [Database],
        p.query('.').value('./ns1:ColumnReference[1]/@Schema', 'sysname') AS [Schema],
        p.query('.').value('./ns1:ColumnReference[1]/@Table', 'sysname') AS [Table],
        p.query('.').value('./ns1:ColumnReference[1]/@Column', 'sysname') AS [Column]
    FROM CompiledPlan
        CROSS APPLY qp.nodes('//ns1:ColumnReference') t(p)
)

SELECT 
    [Database], 
    [Schema], 
    [Table], 
    [Column]
FROM ColumnReferences 
WHERE 
    [Database] IS NOT NULL AND 
    ob = OBJECT_ID(@TargetObject, 'P')

买者自负 这取决于您如何定义'used'。存储过程中的 CTE 可能引用 table 中的 5 列,但是当使用此 CTE 时,仅传递其中的三列。查询优化器可能 忽略这些额外字段并且不将它们包括在计划中。另一方面,优化器可能会决定它可以通过在输出中包含额外的字段来使其能够在以后使用更好的索引来进行更高效的查询。此代码将 return 查询计划使用的列,它们可能不完全是存储过程代码中的列。

这是我用来获取存储过程中使用的所有表的方法,但它没有 return 列。

    declare
        @target_table as varchar(255) = N'my_sp',
        @target_schema as varchar(255) = N'dbo';

    select distinct od.name as depname
        ,1 as depnumber
        ,od.type as deptype
        ,sd.name as depschemaname
    from sys.objects as o
    inner join sys.schemas as s
        on s.schema_id = o.schema_id
    inner join sys.objects as od
        on od.object_id = o.parent_object_id
    inner join sys.schemas as sd
        on sd.schema_id = od.schema_id
    where s.name = @target_schema
        and o.name = @target_table and od.type = 'U'

    union

    select distinct od.name as depname
        ,case 
            when od.type = 'P'
                then np.procedure_number
            else 1
            end as depnumber
        ,od.type as deptype
        ,sd.name as depschemaname
    from sys.sql_expression_dependencies d
    inner join sys.objects o
        on o.object_id = d.referencing_id
    inner join sys.schemas s
        on s.schema_id = o.schema_id
    inner join sys.objects od
        on od.object_id = d.referenced_id
    inner join sys.schemas sd
        on sd.schema_id = od.schema_id
    left join sys.numbered_procedures np
        on np.object_id = d.referenced_id
    where s.name = @target_schema
        and o.name = @target_table and od.type = 'U';