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

如何将仅返回非空列的T-SQL查询封装为可复用函数?

实现方案:封装返回NOT NULL列的可复用逻辑

核心限制说明

T-SQL的内置标量/表值函数不允许执行动态SQL(EXEC或sp_executesql),所以无法直接在函数内生成并执行动态查询返回结果集。推荐两种实用实现方式:


方式1:封装为标量函数(返回NOT NULL列列表)

这个函数负责获取指定表的所有NOT NULL列名(逗号分隔),你可以在外部拼接动态SQL执行查询。

创建函数

CREATE FUNCTION dbo.GetNotNullColumns(@TableName NVARCHAR(256))
RETURNS NVARCHAR(MAX)
AS
BEGIN
    DECLARE @ColumnList NVARCHAR(MAX) = '';

    -- SQL Server 2017+ 使用STRING_AGG简化拼接
    SELECT @ColumnList = STRING_AGG(c.name, ', ')
    FROM sys.columns c
    JOIN sys.tables t ON c.object_id = t.object_id
    JOIN sys.schemas s ON t.schema_id = s.schema_id
    WHERE s.name + '.' + t.name = @TableName
      AND c.is_nullable = 0;

    -- 兼容SQL Server 2016及更早版本,替换上面的STRING_AGG为以下代码:
    /*
    SELECT @ColumnList = STUFF((SELECT ', ' + c.name
                               FROM sys.columns c
                               JOIN sys.tables t ON c.object_id = t.object_id
                               JOIN sys.schemas s ON t.schema_id = s.schema_id
                               WHERE s.name + '.' + t.name = @TableName
                                 AND c.is_nullable = 0
                               FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '');
    */

    RETURN @ColumnList;
END;

使用示例

-- 获取test1表的NOT NULL列并执行查询
DECLARE @TableName NVARCHAR(256) = 'dbo.test1';
DECLARE @SQL NVARCHAR(MAX) = 'SELECT ' + dbo.GetNotNullColumns(@TableName) + ' FROM ' + @TableName;
EXEC sp_executesql @SQL;

方式2:封装为存储过程(直接返回结果集)

如果希望直接执行并返回结果,存储过程是更合适的选择,因为它原生支持动态SQL。

创建存储过程

CREATE PROCEDURE dbo.SelectNotNullColumns
    @TableName NVARCHAR(256)
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @ColumnList NVARCHAR(MAX);
    DECLARE @SchemaName NVARCHAR(128);
    DECLARE @PureTableName NVARCHAR(128);

    -- 拆分Schema和表名,避免SQL注入风险
    IF CHARINDEX('.', @TableName) > 0
    BEGIN
        SET @SchemaName = LEFT(@TableName, CHARINDEX('.', @TableName) - 1);
        SET @PureTableName = SUBSTRING(@TableName, CHARINDEX('.', @TableName) + 1, LEN(@TableName));
    END
    ELSE
    BEGIN
        SET @SchemaName = 'dbo';
        SET @PureTableName = @TableName;
    END

    -- 获取NOT NULL列列表
    SELECT @ColumnList = STRING_AGG(c.name, ', ')
    FROM sys.columns c
    JOIN sys.tables t ON c.object_id = t.object_id
    JOIN sys.schemas s ON t.schema_id = s.schema_id
    WHERE s.name = @SchemaName
      AND t.name = @PureTableName
      AND c.is_nullable = 0;

    -- 生成并执行安全的动态SQL
    IF @ColumnList IS NOT NULL
    BEGIN
        DECLARE @SQL NVARCHAR(MAX) = 'SELECT ' + @ColumnList + ' FROM ' + QUOTENAME(@SchemaName) + '.' + QUOTENAME(@PureTableName);
        EXEC sp_executesql @SQL;
    END
    ELSE
    BEGIN
        RAISERROR('指定的表不存在或没有定义NOT NULL约束的列', 16, 1);
    END
END;

使用示例

-- 直接查询test1表的NOT NULL列
EXEC dbo.SelectNotNullColumns @TableName = 'dbo.test1';

关于WHERE子句的疑问

不需要在WHERE子句中使用此函数。我们的需求是选择表中架构层面定义为NOT NULL的列(即创建表时加了NOT NULL约束的列),这属于SELECT子句的列选择逻辑,而WHERE子句是用来筛选符合条件的数据行,两者完全无关。


内容的提问来源于stack exchange,提问作者ERPISE

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 03:00:54