it-swarm-eu.dev

SQL: Vyberte sloupce pouze s hodnotami NULL

Jak mohu vybrat všechny sloupce v tabulce, které obsahují pouze hodnoty NULL pro všechny řádky? Používám MS SQL Server 2005 . Snažím se zjistit, které sloupce nejsou v tabulce použity, abych je mohl smazat.

44
Bryan Roth

Zde je verze sql 2005 nebo novější: Nahraďte ADDR_Address tabulkovým názvem.

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

To by vám měl poskytnout seznam všech sloupců v tabulce "Osoba", která má pouze hodnoty NULL. Výsledky získáte jako více výsledných sad, které jsou buď prázdné, nebo obsahují název jednoho sloupce. Musíte nahradit "Osoba" na dvou místech, abyste ji mohli použít s jinou tabulkou.

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

Nebo chcete vidět, zda má sloupec pouze hodnoty NULL (a tedy je pravděpodobně nepoužívaný)?

Další objasnění otázky by mohlo pomoci.

EDIT: Ok .. tady je nějaký opravdu hrubý kód, který vás dostane ...

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

Ano, existují jednodušší způsoby, ale teď mám schůzku, abych šel hned. Hodně štěstí!

3
Kevin Fairchild

Můžete dělat: 

select 
  count(<columnName>)
from
  <tableName>

Pokud počet vrátí hodnotu 0, znamená to, že všechny řádky v tomto sloupci mají hodnotu NULL (nebo v tabulce nejsou žádné řádky)

lze změnit na 

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

Chcete-li jej automatizovat, můžete pomocí systémových tabulek iterovat názvy sloupců v tabulce, o kterou máte zájem

2
kristof

Zde je aktualizovaná verze Bryanova dotazu pro rok 2008 a novější. Používá INFORMATION_SCHEMA.COLUMNS, přidává proměnné pro schéma schématu a název tabulky. K výstupu byl přidán datový typ sloupce. Zahrnutí sloupcového datového typu pomáhá při hledání sloupce určitého datového typu. Nepřidal jsem šířky sloupců ani nic.

Pro výstup se použije RAISERROR ... S NOWAIT, takže text se zobrazí okamžitě místo všeho najednou (z větší části) na konci jako 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

V roce 2005 to není jisté, ale rok 2008 to snědl:

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

Doporučil bych také vyhledat pole, která mají stejnou hodnotu, ne jen NULL.

To znamená, že pro každý sloupec v každé tabulce proveďte dotaz:

SELECT COUNT(DISTINCT field) FROM tableName

a soustředit se na ty, kteří v důsledku toho 1 vrátí.

1
squadette

Pokud potřebujete seznam všech řádků, kde jsou všechny hodnoty sloupců NULL, pak bych použil funkci COLLATE. To trvá seznam hodnot a vrátí první hodnotu null. Pokud do seznamu přidáte všechny názvy sloupců, pak použijte IS NULL, měli byste získat všechny řádky obsahující pouze hodnoty null.

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

Neměli byste mít ve skutečnosti žádné tabulky s hodnotou ALLcolumns null, protože to znamená, že nemáte primary key (nesmí být null). Neexistence primárního klíče je něco, čemu je třeba se vyhnout; toto rozbije první normální formu.

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

Aktualizovaná verze verze „user2466387“ s malým malým testem, který může zlepšit výkon, protože je zbytečné testovat sloupce s nulovací hodnotou:

AND IS_NULLABLE = 'YES'

Celý kód:

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

Zkuste to -

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

Budete muset smyčku přes sadu sloupců a zkontrolovat každý z nich. Měli byste být schopni získat seznam všech sloupců příkazem DESCRIBE table.

Pseudo kód:


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;

Vím, že to vypadá trochu kontraintuitivně, ale SQL neposkytuje nativní metodu výběru sloupců, pouze řádků.

0
Daniel Papasian