it-swarm-eu.dev

SQL: Wählen Sie nur Spalten mit NULL-Werten aus

Wie wähle ich alle Spalten in einer Tabelle aus, die nur NULL-Werte für alle Zeilen enthalten? Ich verwende MS SQL Server 2005 . Ich versuche herauszufinden, welche Spalten in der Tabelle nicht verwendet werden, damit ich sie löschen kann.

44
Bryan Roth

Hier ist die SQL-Version 2005 oder höher: Ersetzen Sie ADDR_Address durch Ihren Tabellennamen.

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

Dies sollte Ihnen eine Liste aller Spalten in der Tabelle "Person" geben, die nur NULL-Werte enthält. Sie erhalten die Ergebnisse als mehrere Ergebnissätze, die entweder leer sind oder den Namen einer einzelnen Spalte enthalten. Sie müssen "Person" an zwei Stellen ersetzen, um sie mit einer anderen Tabelle zu verwenden.

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

Oder wollten Sie nur sehen, ob eine Spalte nur NULL-Werte hat (und daher wahrscheinlich nicht verwendet wird)?

Eine weitere Klärung der Frage könnte hilfreich sein.

EDIT: Ok ... hier ein paar sehr grobe Codes, um dich in Gang zu bringen.

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

Ja, es gibt einfachere Wege, aber ich habe jetzt ein Treffen, zu dem ich gehen kann. Viel Glück!

3
Kevin Fairchild

Du kannst tun: 

select 
  count(<columnName>)
from
  <tableName>

Wenn der Zähler 0 zurückgibt, bedeutet dies, dass alle Zeilen in dieser Spalte alle NULL sind (oder dass es überhaupt keine Zeilen in der Tabelle gibt)

kann in geändert werden 

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

Wenn Sie sie automatisieren möchten, können Sie Systemtabellen verwenden, um die Spaltennamen in der gewünschten Tabelle zu durchlaufen

2
kristof

Hier ist eine aktualisierte Version von Bryans Abfrage für 2008 und später. Es verwendet INFORMATION_SCHEMA.COLUMNS und fügt Variablen für das Tabellenschema und den Tabellennamen hinzu. Der Spaltendatentyp wurde der Ausgabe hinzugefügt. Das Einbeziehen des Spaltendatentyps hilft bei der Suche nach einer Spalte eines bestimmten Datentyps. Ich habe die Spaltenbreiten oder nichts hinzugefügt.

Für die Ausgabe wird RAISERROR ... WITH NOWAIT verwendet, so dass der Text sofort angezeigt wird (größtenteils auf einmal) und am Ende wie bei 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

Nicht wirklich sicher über 2005, aber 2008 hat es gegessen:

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

Ich würde auch empfehlen, nach Feldern zu suchen, die alle den gleichen Wert haben, nicht nur NULL.

Das heißt für jede Spalte in jeder Tabelle die Abfrage:

SELECT COUNT(DISTINCT field) FROM tableName

und konzentrieren Sie sich auf diejenigen, die als Ergebnis 1 zurückgeben.

1
squadette

Wenn Sie alle Zeilen auflisten müssen, in denen alle Spaltenwerte NULL sind, dann würde ich die COLLATE-Funktion verwenden. Dies nimmt eine Liste von Werten und gibt den ersten Wert ungleich Null zurück. Wenn Sie alle Spaltennamen zur Liste hinzufügen und IS NULL verwenden, sollten Sie alle Zeilen erhalten, die nur Nullen enthalten.

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

Sie sollten eigentlich keine Tabellen mit ALL der Variable columns null haben, da dies bedeutet, dass Sie keinen primary key haben (dies darf nicht null sein). Es ist zu vermeiden, keinen Primärschlüssel zu haben. Dies bricht die erste Normalform.

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

Eine aktualisierte Version der 'user2466387'-Version mit einem zusätzlichen kleinen Test, der die Leistung verbessern kann, da es nicht sinnvoll ist, nicht nullfähige Spalten zu testen:

AND IS_NULLABLE = 'YES'

Der vollständige Code:

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

Versuche dies -

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

Sie müssen den Satz von Spalten durchlaufen und jede prüfen. Sie sollten in der Lage sein, eine Liste aller Spalten mit einem Tabellenbefehl DESCRIBE abzurufen.

Pseudo-Code:


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;

Ich weiß, dass dies ein wenig uninteressant erscheint, aber SQL bietet keine native Methode zum Auswählen von Spalten, sondern nur für Zeilen.

0
Daniel Papasian