it-swarm-pt.tech

SQL: Selecione colunas apenas com valores NULL

Como faço para selecionar todas as colunas em uma tabela que contêm apenas valores NULL para todas as linhas? Estou usando MS SQL Server 2005 . Estou tentando descobrir quais colunas não são usadas na tabela para que eu possa excluí-las.

44
Bryan Roth

Aqui está o sql 2005 ou versão posterior: Substitua ADDR_Address pelo seu nome de tabela.

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
61
Charles Graham
SELECT cols
FROM table
WHERE cols IS NULL
22
Eight Characters

Isso deve fornecer uma lista de todas as colunas na tabela "Person" que possui apenas valores NULL. Você obterá os resultados como vários conjuntos de resultados, que estão vazios ou contêm o nome de uma única coluna. Você precisa substituir "Person" em dois lugares para usá-lo com outra tabela.

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
5
MobyDX

Ou você quer apenas ver se uma coluna tem apenas valores NULL (e, portanto, provavelmente não é usada)?

Mais esclarecimentos sobre a questão podem ajudar.

EDIT: Ok .. aqui está um código muito difícil para você ir ...

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 @[email protected]@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

Sim, existem maneiras mais fáceis, mas eu tenho uma reunião para ir agora. Boa sorte!

3
Kevin Fairchild

Você pode fazer: 

select 
  count(<columnName>)
from
  <tableName>

Se a contagem retornar 0, isso significa que todas as linhas nessa coluna são todas NULL (ou não há linhas na tabela)

pode ser alterado para 

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

Se você quiser automatizá-lo, pode usar as tabelas do sistema para iterar os nomes das colunas na tabela em que está interessado

2
kristof

Aqui está uma versão atualizada da consulta de Bryan para 2008 e posterior. Ele usa INFORMATION_SCHEMA.COLUMNS, adiciona variáveis ​​para o esquema da tabela e o nome da tabela. O tipo de dados da coluna foi adicionado à saída. A inclusão do tipo de dados da coluna ajuda na busca por uma coluna de um determinado tipo de dados. Eu não adicionei as larguras de coluna nem nada.

Para a saída, o RAISERROR ... WITH NOWAIT é usado para que o texto seja exibido imediatamente em vez de todos de uma vez (na maior parte) no final, como o 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;

2
user2466387

Não tenho certeza sobre 2005, mas 2008 comeu:

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)
1
user8120267

Eu também recomendo procurar campos que tenham o mesmo valor, não apenas NULL.

Ou seja, para cada coluna em cada tabela faça a consulta:

SELECT COUNT(DISTINCT field) FROM tableName

e concentre-se naqueles que retornam 1 como resultado.

1
squadette

Se você precisar listar todas as linhas em que todos os valores de coluna são NULL, use a função COLLATE. Isso leva uma lista de valores e retorna o primeiro valor não nulo. Se você adicionar todos os nomes de colunas à lista, então use IS NULL, você deve obter todas as linhas contendo apenas nulos.

SELECT * FROM MyTable WHERE COLLATE(Col1, Col2, Col3, Col4......) IS NULL

Você realmente não deve ter nenhuma tabela com TODOS os columns null, pois isso significa que você não tem um primary key (não pode ser null). Não ter uma chave primária é algo a ser evitado; isso quebra a primeira forma normal.

1
The Doc
SELECT  t.column_name
FROM    user_tab_columns t
WHERE   t.nullable = 'Y' AND t.table_name = 'table name here' AND t.num_distinct = 0;
0
user3827049

Uma versão atualizada da versão 'user2466387', com um pequeno teste adicional que pode melhorar o desempenho, porque é inútil testar colunas não anuláveis:

AND IS_NULLABLE = 'YES'

O código completo:

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;
0
Sylvain Bruyere

Tente isso -

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)
0
Jasmina Shevchenko

Você terá que percorrer o conjunto de colunas e verificar cada uma delas. Você deve conseguir obter uma lista de todas as colunas com um comando de tabela DESCRIBE.

Pseudo-código:


foreach $column ($cols) {
   query("SELECT count(*) FROM table WHERE $column IS NOT NULL")
   if($result is zero)  {
      # $column contains only null values"
      Push @onlyNullColumns, $column;
   } else {
      # $column contains non-null values
   }
}
return @onlyNullColumns;

Eu sei que isso parece um pouco contraditório, mas SQL não fornece um método nativo de selecionar colunas, apenas linhas.

0
Daniel Papasian