SQL: выберите столбцы только со значениями NULL - PullRequest
46 голосов
/ 15 сентября 2008

Как выбрать все столбцы в таблице, которые содержат только значения NULL для всех строк? Я использую MS SQL Server 2005 . Я пытаюсь выяснить, какие столбцы не используются в таблице, чтобы я мог их удалить.

Ответы [ 14 ]

62 голосов
/ 15 сентября 2008

Вот SQL 2005 или более поздняя версия: замените ADDR_Address своим именем таблицы.

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
21 голосов
/ 15 сентября 2008
SELECT cols
FROM table
WHERE cols IS NULL
5 голосов
/ 15 сентября 2008

Это должно дать вам список всех столбцов в таблице «Person», которая имеет только NULL-значения. Вы получите результаты в виде нескольких наборов результатов, которые либо пусты, либо содержат имя одного столбца. Вам нужно заменить «Человек» в двух местах, чтобы использовать его с другой таблицей.

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
4 голосов
/ 15 сентября 2008

Или вы просто хотели посмотреть, имеет ли столбец только значения NULL (и, следовательно, вероятно, не используется)?

Может помочь дальнейшее разъяснение вопроса.

EDIT: Хорошо ... вот вам действительно грубый код, который поможет вам ...

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

Да, есть более простые способы, но у меня есть встреча, на которую я должен пойти прямо сейчас. Удачи!

3 голосов
/ 10 июля 2014

Вот обновленная версия запроса Брайана за 2008 год и позже. Он использует INFORMATION_SCHEMA.COLUMNS, добавляет переменные для схемы таблицы и имени таблицы. Тип данных столбца был добавлен к выводу. Включение типа данных столбца помогает при поиске столбца определенного типа данных. Я не добавил ширину столбца или что-то еще.

Для вывода используется RAISERROR ... WITH 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;

2 голосов
/ 15 сентября 2008

Вы можете сделать:

select 
  count(<columnName>)
from
  <tableName>

Если счетчик возвращает 0, это означает, что все строки в этом столбце все NULL (или в таблице вообще нет строк)

можно изменить на

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

Если вы хотите автоматизировать его, вы можете использовать системные таблицы для итерации имен столбцов в интересующей вас таблице

1 голос
/ 06 июня 2017

Не совсем уверен насчет 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)
1 голос
/ 15 сентября 2008

Если вам нужно перечислить все строки, в которых все значения столбцов равны NULL, то я бы использовал функцию COLLATE. Он принимает список значений и возвращает первое ненулевое значение. Если вы добавляете все имена столбцов в список, а затем используете IS NULL, вы должны получить все строки, содержащие только нули.

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

У вас не должно быть таблиц со ВСЕМ значением columns, поскольку это означает, что у вас нет primary key (недопустимо быть null). Отсутствие первичного ключа - это то, чего следует избегать; это нарушает первую нормальную форму.

1 голос
/ 15 сентября 2008

Я бы также рекомендовал искать поля, которые имеют одинаковое значение, а не только NULL.

То есть для каждого столбца в каждой таблице выполняется запрос:

SELECT COUNT(DISTINCT field) FROM tableName

и сконцентрируйтесь на тех, которые возвращают 1 в результате.

0 голосов
/ 05 мая 2017

Обновленная версия версии '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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...