it-swarm-id.com

SQL: Pilih kolom dengan nilai NULL saja

Bagaimana cara memilih semua kolom dalam tabel yang hanya berisi nilai NULL untuk semua baris? Saya menggunakan MS SQL Server 2005 . Saya mencoba mencari tahu kolom mana yang tidak digunakan dalam tabel sehingga saya bisa menghapusnya.

44
Bryan Roth

Ini adalah versi sql 2005 atau yang lebih baru: Ganti ADDR_Address dengan tablename Anda.

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

Ini akan memberi Anda daftar semua kolom dalam tabel "Orang" yang hanya memiliki nilai NULL. Anda akan mendapatkan hasilnya sebagai beberapa set hasil, yang kosong atau berisi nama satu kolom. Anda perlu mengganti "Orang" di dua tempat untuk menggunakannya dengan tabel lain.

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

Atau apakah Anda hanya ingin melihat apakah kolom hanya memiliki nilai NULL (dan, dengan demikian, mungkin tidak digunakan)?

Klarifikasi lebih lanjut dari pertanyaan ini mungkin membantu.

EDIT: Ok .. ini beberapa kode yang sangat kasar untuk membuat Anda maju ...

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

Ya, ada cara-cara yang lebih mudah, tetapi saya harus pergi ke pertemuan sekarang. Semoga berhasil!

3
Kevin Fairchild

Anda dapat melakukan: 

select 
  count(<columnName>)
from
  <tableName>

Jika jumlah mengembalikan 0 itu berarti bahwa semua baris di kolom itu semua NULL (atau tidak ada baris sama sekali dalam tabel)

dapat diubah menjadi 

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

Jika Anda ingin mengotomatiskannya, Anda dapat menggunakan tabel sistem untuk mengulangi nama kolom pada tabel yang Anda minati

2
kristof

Ini adalah versi terbaru dari permintaan Bryan untuk 2008 dan yang lebih baru. Ini menggunakan INFORMATION_SCHEMA.COLUMNS, menambahkan variabel untuk skema tabel dan nama tabel. Tipe data kolom ditambahkan ke output. Termasuk tipe data kolom membantu ketika mencari kolom dari tipe data tertentu. Saya tidak menambahkan lebar kolom atau apa pun.

Untuk output, RAISERROR ... WITH NOWAIT digunakan sehingga teks akan segera ditampilkan, bukan sekaligus (sebagian besar) di akhir seperti 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

Tidak benar-benar yakin tentang 2005, tetapi 2008 memakannya:

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

Saya juga merekomendasikan untuk mencari bidang yang semuanya memiliki nilai yang sama, bukan hanya NULL.

Artinya, untuk setiap kolom di setiap tabel lakukan kueri:

SELECT COUNT(DISTINCT field) FROM tableName

dan berkonsentrasi pada yang mengembalikan 1 sebagai hasilnya.

1
squadette

Jika Anda perlu mendaftar semua baris di mana semua nilai kolom NULL, maka saya akan menggunakan fungsi COLLATE. Ini mengambil daftar nilai dan mengembalikan nilai bukan nol pertama. Jika Anda menambahkan semua nama kolom ke daftar, lalu gunakan IS NULL, Anda harus mendapatkan semua baris yang hanya berisi nol.

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

Anda seharusnya tidak benar-benar memiliki tabel dengan SEMUA columns null, karena ini berarti Anda tidak memiliki primary key (tidak diizinkan null). Tidak memiliki kunci utama adalah sesuatu yang harus dihindari; ini merusak bentuk normal pertama.

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

Versi terbaru dari versi 'user2466387', dengan tes kecil tambahan yang dapat meningkatkan kinerja, karena tidak berguna untuk menguji kolom yang tidak dapat dibatalkan:

AND IS_NULLABLE = 'YES'

Kode lengkap:

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

Coba ini -

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

Anda harus mengulang set kolom dan memeriksa masing-masing. Anda harus bisa mendapatkan daftar semua kolom dengan perintah tabel DESCRIBE.

Kode semu:


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;

Saya tahu ini tampaknya sedikit berlawanan dengan intuisi tetapi SQL tidak menyediakan metode asli memilih kolom, hanya baris.

0
Daniel Papasian