使用SQL Server选择非空列

Had*_*adi 0 sql t-sql sql-server query-optimization sql-server-2012

我使用的是SQL Server 2012.我有一个包含90列的表.我试图只选择包含数据的列.搜索后,我使用以下程序:

1-使用一个选择查询获取所有列数

2-将结果表旋转到Temp表中

3-创建选择查询

4-执行此查询

这是我使用的查询:

DECLARE @strTablename  varchar(100) = 'dbo.MyTable'
DECLARE @strQuery  varchar(max) = ''
DECLARE @strSecondQuery  varchar(max) = 'SELECT '
DECLARE @strUnPivot as varchar(max) = ' UNPIVOT ([Count] for [Column] IN ('

CREATE TABLE ##tblTemp([Column] varchar(50), [Count]  Int)

SELECT @strQuery = ISNULL(@strQuery,'') + 'Count([' + name + ']) as [' + name + ']  ,' from sys.columns where object_id = object_id(@strTablename) and is_nullable = 1
SELECT @strUnPivot = ISNULL(@strUnPivot,'') + '[' + name + '] ,' from sys.columns where object_id = object_id(@strTablename) and is_nullable = 1


SET @strQuery = 'SELECT [Column],[Count] FROM ( SELECT ' + SUBSTRING(@strQuery,1,LEN(@strQuery) - 1) + ' FROM ' + @strTablename + ') AS p ' + SUBSTRING(@strUnPivot,1,LEN(@strUnPivot) - 1) + ')) AS unpvt '

INSERT INTO ##tblTemp EXEC (@strQuery)

SELECT @strSecondQuery = @strSecondQuery + '[' + [Column] + '],'  from ##tblTemp WHERE [Count] > 0

DROP TABLE ##tblTemp

SET @strSecondQuery = SUBSTRING(@strSecondQuery,1,LEN(@strSecondQuery) - 1) + ' FROM ' + @strTablename

EXEC (@strSecondQuery)
Run Code Online (Sandbox Code Playgroud)

问题是这个查询太慢了.有没有最好的方法来实现这一目标?

笔记:

  • 表在主键列上只有一个聚簇索引,ID并且不包含任何其他索引.
  • 表格不可编辑.
  • 表包含非常大的数据.
  • 查询大约需要1分钟才能执行

提前致谢.

Shn*_*ugo 6

我不知道这是否更快,但你可能会使用一个技巧:FOR XML AUTO将省略没有内容的列:

DECLARE @tbl TABLE(col1 INT,col2 INT,col3 INT);
INSERT INTO @tbl VALUES (1,2,NULL),(1,NULL,NULL),(NULL,NULL,NULL);

SELECT * 
FROM @tbl AS tbl
FOR XML AUTO
Run Code Online (Sandbox Code Playgroud)

这是结果:col3缺少......

<tbl col1="1" col2="2" />
<tbl col1="1" />
<tbl />
Run Code Online (Sandbox Code Playgroud)

知道这一点,你可以找到所有行中不是NULL的列列表,如下所示:

DECLARE @ColList VARCHAR(MAX)=
STUFF
(
    (
    SELECT DISTINCT ',' + Attr.value('local-name(.)','nvarchar(max)')
    FROM
    (
        SELECT
        (
            SELECT *
            FROM @tbl AS tbl
            FOR XML AUTO,TYPE
        ) AS TheXML
    ) AS t
    CROSS APPLY t.TheXML.nodes('/tbl/@*') AS A(Attr) 
    FOR XML PATH('')
    ),1,1,''
);

SELECT @ColList
Run Code Online (Sandbox Code Playgroud)

的内容@ColList是现在col1,col2.这个字符串可以放在动态创建的中SELECT.

更新:提示

SELECT *用一个INFORMATION_SCHEMA.COLUMNS排除所有不可空的列列表替换它是非常聪明的.并且 - 如果需要和可能 - 类型,包含非常大的数据(BLOB).

更新2:性能

不知道你的大数据实际意味着什么...只是在一个有大约500.000行(带SELECT *)的表上试过这个并且在不到一分钟后它正确返回.希望,这足够快......

  • 实例/演示+1 (2认同)