我有一些带有100-300列的大表,有时一个项目充满了空值,只留下了ID,就像这样:
|---------------------|------------------|------------------| |------------------|
| ID | Column 1 | Column 2 | ....| Column 300 |
|---------------------|------------------|------------------| |----------------- |
| 1 | value | value | ....
|---------------------|------------------|------------------|
| 2 | NULL | NULL | ....
|---------------------|------------------|------------------|
| 3 | NULL | NULL | ....
|---------------------|------------------|------------------|
所以我想删除那些,但我能想到的唯一方法是很大一部分
CASE (colA IS NULL and colB IS NULL AND colC IS NULL ...)
但这对我来说是不切实际的,因为有很多表和很多列。
是否有一种方法可以删除除ID列之外仅包含NULL的每一行?
答案 0 :(得分:2)
只需替换为您的表和架构:
Pre-request Script
在上面的示例中,我们获取主键列(如果存在),以便不将其包含在DECLARE @TableSchema SYSNAME
,@TableName SYSNAME
SELECT @TableSchema = 'dbo'
,@TableName = 'SurveyInstances';
DECLARE @DynamicTSQLStatement NVARCHAR(MAX);
SET @DynamicTSQLStatement = 'DELETE FROM ' + @TableSchema + '.' + @TableName + ' WHERE ' + STUFF
(
(
SELECT ' AND ' + [name] + ' IS NULL'
FROM [sys].[columns]
WHERE [object_id] = OBJECT_ID(@TableSchema + '.' + @TableName)
AND [column_id] NOT IN
(
SELECT IC.[column_id]
FROM [sys].[indexes] I
INNER JOIN [sys].[index_columns] IC
ON I.[object_id] = IC.[object_id]
AND I.[index_id] = IC.[index_id]
WHERE I.[is_primary_key] = 1
AND I.[object_id] = OBJECT_ID(@TableSchema + '.' + @TableName)
)
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1
,5
,''
);
EXEC sp_executesql @DynamicTSQLStatement;
子句中。然后有了这些列,只需连接WHERE
语句,您的T-SQL语句就准备好了。
答案 1 :(得分:2)
到目前为止,这里还没有SQL专家,但是您可以将表转换为XML,将所有NULL值列标记为nil-elements,然后过滤出除列id之外仅包含nil-elements的所有行。
--Glorious test table with an amazing amount of three columns..
declare @tTable table ([id] int, [c1] varchar(10), [c2] bit);
insert into @tTable values
(1, 'wayne', null),
(2, null, 1),
(3, null, null), --This one goes
(4, null, 0),
(5, '', null),
(7, null, null); --This one goes;
--Transform table to XML marking NULL values with @nil..
declare @tXML xml; set @tXML = (
select
*
from
@tTable
for xml path('row'), type, elements xsinil
);
--Removes all [id] contained in the select below..
delete from @tTable where [id] in (
--Select all [id] which have no element NOT being marked as NULL (=merely NULL values)
select
p.value('./id[1]', 'int')
from
(select 1 as [wayne]) as [tT]
cross apply @tXML.nodes('/row') as t(p)
where
(
p.exist('./*[not(local-name(.)="id")][not(@xsi:nil)]') = 0
)
);
select * from @tTable;
答案 2 :(得分:1)
有一种方法可以在没有动态SQL的情况下,也不需要对ID以外的所有值均为NULL的列进行任何手动选择:
IDENTITY INSERT ON/OFF
。
IF OBJECT_ID('tempdb..#a') IS NOT NULL DROP TABLE #a;
DELETE FROM Foobar WHERE id = -666;
SET IDENTITY_INSERT dbo.Foobar ON; -- only if the id field is an IDENTITY
INSERT INTO Foobar(id) SELECT -666 AS id;
SET IDENTITY_INSERT dbo.Foobar OFF; -- only if the id field is an IDENTITY
SELECT *
INTO #a
FROM Foobar
WHERE Foobar.id = -666;
ALTER TABLE #a DROP COLUMN id;
DELETE FROM Foobar WHERE id = -666;
DELETE FROM Foobar WHERE Foobar.id IN
(
SELECT tIntersect.id FROM
(
SELECT * FROM Foobar
INTERSECT
SELECT
Foobar.id
,tNullValues.*
FROM Foobar
CROSS JOIN #a AS tNullValues
) AS tIntersect
);
IF OBJECT_ID('tempdb..#a') IS NOT NULL DROP TABLE #a;
请注意,如果您具有xml,text,geoge或architectureid类型的列,则相交将失败。另外,请注意,SQL-server并未实现INTERSECT ALL,因此只有在表具有主键的情况下(仅当您至少具有一个具有唯一ID的不可空列时,这才可靠地工作-主键可确保但该列不必一定要定义为主键)。
示例:
CREATE TABLE dbo.Foobar
(
id int NOT NULL,
nam varchar(50) NULL
)
输入一些具有ID和名称的值,以及一些仅具有ID的值
然后做:
DECLARE @maxId as integer
SET @maxId = (SELECT MAX(id) FROM Foobar);
;WITH CTE AS
(
SELECT 1 AS i
UNION ALL
SELECT i+1 AS i
FROM CTE
WHERE CTE.i < @maxId
)
SELECT
id
,nam
FROM Foobar
INTERSECT
SELECT
i AS id
,CAST(NULL AS varchar(50)) AS nam
FROM CTE
OPTION (MAXRECURSION 0)
这将产生要删除的所有行的id值。
然后您可以执行以下操作:
DECLARE @maxId as integer
SET @maxId = (SELECT MAX(id) FROM Foobar);
;WITH CTE AS
(
SELECT 1 AS i
UNION ALL
SELECT i+1 AS i
FROM CTE
WHERE CTE.i < @maxId
)
DELETE FROM Foobar WHERE id IN
(
SELECT id FROM
(
SELECT
id
,nam
FROM Foobar
INTERSECT
SELECT
i AS id
,CAST(NULL AS varchar(50)) AS nam
FROM CTE
) AS t
)
OPTION (MAXRECURSION 0)
或者您可以动态生成列列表:
SELECT
CASE
WHEN ORDINAL_POSITION = 1 THEN ' CAST(NULL AS ' + DATA_TYPE + ') AS ' + QUOTENAME(COLUMN_NAME)
ELSE ',CAST(NULL AS ' + DATA_TYPE + ') AS ' + QUOTENAME(COLUMN_NAME)
END
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Foobar'
AND TABLE_SCHEMA = 'dbo'
然后使用它,您可以获得主键列,因此可以从列列表中排除它们:
SELECT kcu.COLUMN_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS tc
LEFT JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS kcu
ON kcu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME
AND kcu.CONSTRAINT_SCHEMA = tc.CONSTRAINT_SCHEMA
AND kcu.TABLE_SCHEMA = tc.TABLE_SCHEMA
AND kcu.TABLE_NAME = tc.TABLE_NAME
WHERE tc.CONSTRAINT_TYPE = 'PRIMARY KEY'
AND tc.TABLE_SCHEMA = 'dbo'
AND tc.TABLE_NAME = 'Foobar'
答案 3 :(得分:1)
这是我“欺骗”引擎执行此操作的方法:
1)手动查找所有列均为空的ID。假设您发现匹配的ID为56。该表的所有行(ID除外)都应为null。将其放入模板:
select *
into #a
from yourtable
where ID=56
2)从该表中删除ID列。仅保留空列。
alter table #a drop column ID
3)通过使用id和临时表的笛卡尔积来创建所有可能不必要的行。 然后,使用EXCEPT将其从原始表中删除:
select * from yourtable
except
select t.ID,#a.*
from yourtable t
cross join #a
答案 4 :(得分:1)
您可以根据需要在查询下面运行。它将删除所有具有NULL值(ID除外)COLUMN的行
DECLARE @TSchema SYSNAME
,@TName SYSNAME
SELECT @TSchema = 'dbo'
,@TName = 'yourTableName';
DECLARE @TSQLStatement NVARCHAR(MAX);
SET @TSQLStatement = 'DELETE FROM ' + @TSchema + '.' + @TName + ' WHERE ' + STUFF
(
(
SELECT ' AND ' + [name] + ' IS NULL'
FROM [sys].[columns]
WHERE [object_id] = OBJECT_ID(@TSchema + '.' + @TName)
AND [column_id] NOT IN
(
SELECT IC.[column_id] FROM [sys].[indexes] I
INNER JOIN [sys].[index_columns] IC ON I.[object_id] = IC.[object_id]
AND I.[index_id] = IC.[index_id]
WHERE I.[type] = 1
AND I.[object_id] = OBJECT_ID(@TSchema + '.' + @TName)
)AND name <> 'id'
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1
,5
,''
);
EXEC sp_executesql @TSQLStatement;
免费查询。