Sql server SQL:仅选择具有空值的列

Sql server SQL:仅选择具有空值的列,sql-server,Sql Server,如何选择表中仅包含所有行的空值的所有列?我正在使用MS SQL Server 2005。我试图找出表中没有使用的列,以便删除它们。您可能需要澄清一下。你到底想完成什么?如果您真的想找出只包含空值的列名,那么您必须遍历scheama并基于此执行动态查询 SELECT cols FROM table WHERE cols IS NULL 我不知道您使用的是哪种DBMS,所以我将在这里放一些伪代码 for each col begin @cmd = 'if not exists (select

如何选择表中仅包含所有行的空值的所有列?我正在使用MS SQL Server 2005。我试图找出表中没有使用的列,以便删除它们。

您可能需要澄清一下。你到底想完成什么?如果您真的想找出只包含空值的列名,那么您必须遍历scheama并基于此执行动态查询

SELECT cols
FROM table
WHERE cols IS NULL
我不知道您使用的是哪种DBMS,所以我将在这里放一些伪代码

for each col
begin
  @cmd = 'if not exists (select * from tablename where ' + col + ' is not null begin print ' + col + ' end'
exec(@cmd)
end

或者您只是想看看一列是否只有空值,因此可能未使用

进一步澄清这个问题可能会有所帮助

编辑: 好啊这里有一些非常粗略的代码让你去

SET NOCOUNT ON
DECLARE @TableName Varchar(100)
SET @TableName='YourTableName'
CREATE TABLE #NullColumns (ColumnName Varchar(100), OnlyNulls BIT)
INSERT INTO #NullColumns (ColumnName, OnlyNulls) SELECT c.name, 0 FROM syscolumns c INNER JOIN sysobjects o ON c.id = o.id AND o.name = @TableName AND o.xtype = 'U'
DECLARE @DynamicSQL AS Nvarchar(2000)
DECLARE @ColumnName Varchar(100)
DECLARE @RC INT
    SELECT TOP 1 @ColumnName = ColumnName FROM #NullColumns WHERE OnlyNulls=0
    WHILE @@ROWCOUNT > 0
    BEGIN
        SET @RC=0
        SET @DynamicSQL = 'SELECT TOP 1 1 As HasNonNulls FROM ' + @TableName + ' (nolock) WHERE ''' + @ColumnName + ''' IS NOT NULL'
        EXEC sp_executesql @DynamicSQL
        set @RC=@@rowcount
        IF @RC=1
        BEGIN
            SET @DynamicSQL = 'UPDATE #NullColumns SET OnlyNulls=1 WHERE ColumnName=''' + @ColumnName + ''''
            EXEC sp_executesql @DynamicSQL
        END
        ELSE
        BEGIN
            SET @DynamicSQL = 'DELETE FROM #NullColumns WHERE ColumnName=''' + @ColumnName+ ''''
            EXEC sp_executesql @DynamicSQL
        END
    SELECT TOP 1 @ColumnName = ColumnName FROM #NullColumns WHERE OnlyNulls=0
    END

SELECT * FROM #NullColumns

DROP TABLE #NullColumns
SET NOCOUNT OFF

是的,有更简单的方法,但我现在有个会议要开。祝你好运

您必须在列集合上循环并检查每个列。您应该能够使用descripe table命令获得所有列的列表

伪代码:

我知道这似乎有点违反直觉,但SQL不提供选择列的本机方法,只提供行。

您可以:

select 
  count(<columnName>)
from
  <tableName>
如果计数返回0,则表示该列中的所有行都为NULL,或者表中根本没有行

可以改为

select 
    case(count(<columnName>)) when 0 then 'Nulls Only' else 'Some Values' end
from 
    <tableName>

如果要实现自动化,可以使用系统表来迭代您感兴趣的表中的列名

我还建议搜索所有字段都具有相同的值,而不仅仅是空值

也就是说,对每个表中的每一列执行以下查询:

SELECT COUNT(DISTINCT field) FROM tableName

然后将注意力集中在那些结果返回1的列上。

这将为您提供一个Person表中所有只有空值的列的列表。您将以多个结果集的形式获得结果,这些结果集要么为空,要么包含单个列的名称。您需要在两个位置替换人员,才能使用另一个表

DECLARE crs CURSOR LOCAL FAST_FORWARD FOR SELECT name FROM syscolumns WHERE id=OBJECT_ID('Person')
OPEN crs
DECLARE @name sysname
FETCH NEXT FROM crs INTO @name
WHILE @@FETCH_STATUS = 0
BEGIN
    EXEC('SELECT ''' + @name + ''' WHERE NOT EXISTS (SELECT * FROM Person WHERE ' + @name + ' IS NOT NULL)')
    FETCH NEXT FROM crs INTO @name
END
CLOSE crs
DEALLOCATE crs

以下是sql 2005或更高版本:用您的表名替换ADDR_地址

declare @col varchar(255), @cmd varchar(max)

DECLARE getinfo cursor for
SELECT c.name FROM sys.tables t JOIN sys.columns c ON t.Object_ID = c.Object_ID
WHERE t.Name = 'ADDR_Address'

OPEN getinfo

FETCH NEXT FROM getinfo into @col

WHILE @@FETCH_STATUS = 0
BEGIN
    SELECT @cmd = 'IF NOT EXISTS (SELECT top 1 * FROM ADDR_Address WHERE [' + @col + '] IS NOT NULL) BEGIN print ''' + @col + ''' end'
    EXEC(@cmd)

    FETCH NEXT FROM getinfo into @col
END

CLOSE getinfo
DEALLOCATE getinfo

如果您需要列出所有列值为NULL的所有行,那么我将使用COLLATE函数。这将获取值列表并返回第一个非空值。如果将所有列名添加到列表中,则use为NULL,则应获取仅包含NULL的所有行

SELECT * FROM MyTable WHERE COLLATE(Col1, Col2, Col3, Col4......) IS NULL
您不应该有任何表的所有列都为null,因为这意味着您没有不允许为null的主键。没有主键是需要避免的;这打破了第一个正常形式。

试试这个-

DECLARE @table VARCHAR(100) = 'dbo.table'

DECLARE @sql NVARCHAR(MAX) = ''

SELECT @sql = @sql + 'IF NOT EXISTS(SELECT 1 FROM ' + @table + ' WHERE ' + c.name + ' IS NOT NULL) PRINT ''' + c.name + ''''
FROM sys.objects o
JOIN sys.columns c ON o.[object_id] = c.[object_id]
WHERE o.[type] = 'U'
    AND o.[object_id] = OBJECT_ID(@table)
    AND c.is_nullable = 1

EXEC(@sql)

这是Bryan 2008年及以后查询的更新版本。它使用INFORMATION_SCHEMA.COLUMNS,为表模式和表名添加变量。列数据类型已添加到输出中。包含列数据类型有助于查找特定数据类型的列。我没有添加列宽或其他内容

对于输出错误。。。使用NOWAIT时,文本将立即显示,而不是像PRINT一样在末尾显示大部分内容

SET NOCOUNT ON;

DECLARE
 @ColumnName sysname
,@DataType nvarchar(128)
,@cmd nvarchar(max)
,@TableSchema nvarchar(128) = 'dbo'
,@TableName sysname = 'TableName';

DECLARE getinfo CURSOR FOR
SELECT
     c.COLUMN_NAME
    ,c.DATA_TYPE
FROM
    INFORMATION_SCHEMA.COLUMNS AS c
WHERE
    c.TABLE_SCHEMA = @TableSchema
    AND c.TABLE_NAME = @TableName;

OPEN getinfo;

FETCH NEXT FROM getinfo INTO @ColumnName, @DataType;

WHILE @@FETCH_STATUS = 0
BEGIN
    SET @cmd = N'IF NOT EXISTS (SELECT * FROM ' + @TableSchema + N'.' + @TableName + N' WHERE [' + @ColumnName + N'] IS NOT NULL) RAISERROR(''' + @ColumnName + N' (' + @DataType + N')'', 0, 0) WITH NOWAIT;';
    EXECUTE (@cmd);

    FETCH NEXT FROM getinfo INTO @ColumnName, @DataType;
END;

CLOSE getinfo;
DEALLOCATE getinfo;

“user2466387”版本的更新版本,带有额外的小测试,可以提高性能,因为测试不可为null的列是无用的:

AND IS_NULLABLE = 'YES'
完整代码:

SET NOCOUNT ON;

DECLARE
 @ColumnName sysname
,@DataType nvarchar(128)
,@cmd nvarchar(max)
,@TableSchema nvarchar(128) = 'dbo'
,@TableName sysname = 'TableName';

DECLARE getinfo CURSOR FOR
SELECT
     c.COLUMN_NAME
    ,c.DATA_TYPE
FROM
    INFORMATION_SCHEMA.COLUMNS AS c
WHERE
    c.TABLE_SCHEMA = @TableSchema
    AND c.TABLE_NAME = @TableName
    AND IS_NULLABLE = 'YES';

OPEN getinfo;

FETCH NEXT FROM getinfo INTO @ColumnName, @DataType;

WHILE @@FETCH_STATUS = 0
BEGIN
    SET @cmd = N'IF NOT EXISTS (SELECT * FROM ' + @TableSchema + N'.' + @TableName + N' WHERE [' + @ColumnName + N'] IS NOT NULL) RAISERROR(''' + @ColumnName + N' (' + @DataType + N')'', 0, 0) WITH NOWAIT;';
    EXECUTE (@cmd);

    FETCH NEXT FROM getinfo INTO @ColumnName, @DataType;
END;

CLOSE getinfo;
DEALLOCATE getinfo;

实际上不确定2005年,但2008年吃了它:

USE [DATABASE_NAME] -- !
GO

DECLARE @SQL NVARCHAR(MAX)
DECLARE @TableName VARCHAR(255)

SET @TableName = 'TABLE_NAME'   -- !

SELECT @SQL = 
(
    SELECT 
        CHAR(10)
        +'DELETE FROM ['+t1.TABLE_CATALOG+'].['+t1.TABLE_SCHEMA+'].['+t1.TABLE_NAME+'] WHERE '
        +(
            SELECT  
            CASE t2.ORDINAL_POSITION 
                WHEN (SELECT MIN(t3.ORDINAL_POSITION) FROM INFORMATION_SCHEMA.COLUMNS t3 WHERE t3.TABLE_NAME=t2.TABLE_NAME) THEN ''
                ELSE  'AND '
            END
            +'['+COLUMN_NAME+'] IS NULL' AS 'data()'
            FROM INFORMATION_SCHEMA.COLUMNS t2 WHERE t2.TABLE_NAME=t1.TABLE_NAME FOR XML PATH('')
         )  AS 'data()'
    FROM INFORMATION_SCHEMA.TABLES t1 WHERE t1.TABLE_NAME = @TableName FOR XML PATH('')
)

SELECT @SQL -- EXEC(@SQL)

在这里,我为任何类型的SQL表创建了一个脚本。请复制此存储过程并在您的环境中创建它,然后在表中运行此存储过程

exec [dbo].[SP_RemoveNullValues] 'Your_Table_Name'
存储过程

GO
/****** Object:  StoredProcedure [dbo].[SP_RemoveNullValues]    Script Date: 09/09/2019 11:26:53 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- akila liyanaarachchi
Create procedure [dbo].[SP_RemoveNullValues](@PTableName Varchar(50) ) as 
begin


DECLARE Cussor CURSOR FOR 
SELECT COLUMN_NAME,TABLE_NAME,DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @PTableName  

OPEN Cussor;

Declare @ColumnName Varchar(50)
Declare @TableName  Varchar(50)
Declare @DataType Varchar(50)
Declare @Flage  int 

FETCH NEXT FROM Cussor INTO @ColumnName,@TableName,@DataType
WHILE @@FETCH_STATUS = 0
BEGIN

set @Flage=0


If(@DataType in('bigint','numeric','bit','smallint','decimal','smallmoney','int','tinyint','money','float','real'))
begin
set @Flage=1
end 
If(@DataType in('date','atetimeoffset','datetime2','smalldatetime','datetime','time'))
begin
set @Flage=2
end 
If(@DataType in('char','varchar','text','nchar','nvarchar','ntext'))
begin
set @Flage=3
end 

If(@DataType in('binary','varbinary'))
begin
set @Flage=4
end 



DECLARE @SQL VARCHAR(MAX) 

if  (@Flage in(1,4))
begin 

SET @SQL ='  update ['+@TableName+'] set ['+@ColumnName+']=0 where ['+@ColumnName+'] is null'
end 

if  (@Flage =3)
begin 

SET @SQL ='  update ['+@TableName+'] set ['+@ColumnName+'] = '''' where ['+@ColumnName+'] is null '
end 

if  (@Flage =2)
begin 

SET @SQL ='  update ['+@TableName+'] set ['+@ColumnName+'] ='+'''1901-01-01 00:00:00.000'''+' where ['+@ColumnName+'] is null '
end 


EXEC(@SQL)



FETCH NEXT FROM Cussor INTO @ColumnName,@TableName,@DataType
END

CLOSE Cussor
DEALLOCATE Cussor

END

根据我对这个问题的理解,他想知道只有空值的列的列表。我正在尝试查找表中每一行中包含空值的所有列。这应该可以工作,但可以简化。。。而不是计数*只要做一个前1,并设置一个变量,表示你得到了一个命中。。。不需要知道有多少不是空的,只要至少有一个不是…MSSQL。。。线索在标签上;这并不能回答问题,但我想你的意思是,而不是整理。那么,我该如何做相反的事情,即只选择非空值的列?将代码中的IS NOT NULL更改为IS NULL?@Steam从WHILE内的查询中删除NOT,您将得到一个列列表,其中至少有一条带值的记录。这只是说,如果没有所有列都为NULL,则该命令在没有其他输出的情况下成功运行?嗨,Charles..此代码不适用于临时表。从临时表中获取值是否需要任何更改?虽然此代码可能会回答此问题,但提供有关如何和/或为什么解决此问题的附加上下文将提高答案的长期值。请阅读这篇文章,提供高质量的答案。在一个非常大的表格上,可以扫描数百万或数十亿条记录。如果使用EXISTS,则至少可以在会使列作为感兴趣的列无效的条件下短路。该问题要求MS SQL Serv的解决方案
er 2005这段代码对我来说非常有效!!!提示是将结果格式设置为文本,以便您可以快速复制结果并获得所需内容。谢谢你,莫比!这个对我有用
exec [dbo].[SP_RemoveNullValues] 'Your_Table_Name'
GO
/****** Object:  StoredProcedure [dbo].[SP_RemoveNullValues]    Script Date: 09/09/2019 11:26:53 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- akila liyanaarachchi
Create procedure [dbo].[SP_RemoveNullValues](@PTableName Varchar(50) ) as 
begin


DECLARE Cussor CURSOR FOR 
SELECT COLUMN_NAME,TABLE_NAME,DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @PTableName  

OPEN Cussor;

Declare @ColumnName Varchar(50)
Declare @TableName  Varchar(50)
Declare @DataType Varchar(50)
Declare @Flage  int 

FETCH NEXT FROM Cussor INTO @ColumnName,@TableName,@DataType
WHILE @@FETCH_STATUS = 0
BEGIN

set @Flage=0


If(@DataType in('bigint','numeric','bit','smallint','decimal','smallmoney','int','tinyint','money','float','real'))
begin
set @Flage=1
end 
If(@DataType in('date','atetimeoffset','datetime2','smalldatetime','datetime','time'))
begin
set @Flage=2
end 
If(@DataType in('char','varchar','text','nchar','nvarchar','ntext'))
begin
set @Flage=3
end 

If(@DataType in('binary','varbinary'))
begin
set @Flage=4
end 



DECLARE @SQL VARCHAR(MAX) 

if  (@Flage in(1,4))
begin 

SET @SQL ='  update ['+@TableName+'] set ['+@ColumnName+']=0 where ['+@ColumnName+'] is null'
end 

if  (@Flage =3)
begin 

SET @SQL ='  update ['+@TableName+'] set ['+@ColumnName+'] = '''' where ['+@ColumnName+'] is null '
end 

if  (@Flage =2)
begin 

SET @SQL ='  update ['+@TableName+'] set ['+@ColumnName+'] ='+'''1901-01-01 00:00:00.000'''+' where ['+@ColumnName+'] is null '
end 


EXEC(@SQL)



FETCH NEXT FROM Cussor INTO @ColumnName,@TableName,@DataType
END

CLOSE Cussor
DEALLOCATE Cussor

END