我有一个包含 20 多列的表,有些行的所有列都只有 0。有没有办法过滤掉所有列都是0的行?
我可以用
select *
from table
where concat(col1, col2, col3) != '000'
但我不想在我的例子中写入 20 个以上的零,并且列数将来可能会增加。
我也可以用
select *
from table
where coalesce(col1, col2, col3) > 0
or coalesce(col1, col2, col3) < 0
因为某些值可能是负数。但我不想写20+列名。
有没有动态的方法来解决这个问题?
您可以使用 INFORMATION_SCHEMA 动态抓取表中的列。
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.columns
WHERE TABLE_SCHEMA = "your_database"
AND TABLE_NAME = "your_table"
使用根据 sys.tables 和 sys.colums 信息构造的动态 SQL。使用 ABS 对列求和,然后与零进行比较。
如果使用 2017 年之前的 SQL SERVER:
DECLARE @Criteria Varchar(max) =''
DECLARE @SQL NVarchar(max) =''
SELECT @Criteria=STUFF
(
(SELECT '+' + 'ABS('+ QUOTENAME(c.name) +')'
FROM sys.tables t
JOIN sys.columns c ON t.object_id = c.object_id
WHERE t.name = 'Example'
FOR XML PATH ('')
), 1, 1, ''
)
--SELECT @Criteria returns ABS([A])+ABS([B])+ABS([C])
SET @SQL='SELECT * FROM Example WHERE ' + @Criteria + ' !=0'
--SELECT @SQL Returns SELECT * FROM Example WHERE ABS([A])+ABS([B])+ABS([C]) !=0
EXEC sys.sp_executesql @SQL
如果 SQL Server 2017+:
DECLARE @Criteria Varchar(max) =''
DECLARE @SQL NVarchar(max) =''
SELECT @Criteria=STRING_AGG('ABS('+ QUOTENAME(c.name) +')','+')
FROM sys.tables t
JOIN sys.columns c
ON t.object_id = c.object_id
WHERE t.name = 'Example'
SET @SQL='SELECT * FROM Example WHERE ' + @Criteria + ' !=0'
EXEC sys.sp_executesql @SQL
JSON方法(FOR JSON)可以将表行作为集合处理。之后,您可以解剖组件并检查是否满足条件。
参见示例。
测试源数据
create table test (id int,col1 int,col2 int,col3 int);
insert into test values
(1,10,11,12)
,(2,20,21,22)
,(3,0,0,0)
,(4,30,0,33)
;
id | col1 | col2 | col3 |
---|---|---|---|
1 | 10 | 11 | 12 |
2 | 20 | 21 | 22 |
3 | 0 | 0 | 0 |
4 | 30 | 0 | 33 |
目标查询。我们在查询中不使用列名称,除了
id
列。
select *
,case when replace(replace(
json_modify(
(SELECT * FROM test t2 where t2.id=t.id FOR JSON PATH,WITHOUT_ARRAY_WRAPPER )
,'$.id',null)
,'":0,"','":null,"'),'":0}','":null}') like '%:[0-9]%'
then 1
else 0 end fl
from test t
;
和输出
id | col1 | col2 | col3 | fl |
---|---|---|---|---|
1 | 10 | 11 | 12 | 1 |
2 | 20 | 21 | 22 | 1 |
3 | 0 | 0 | 0 | 0 |
4 | 30 | 0 | 33 | 1 |
一步一步相同的查询
select *
,case when jv3 like '%:[0-9]%' then 1 else 0 end fl
from(
select *
,replace(replace(jv2,'":0,"','":null,"'),'":0}','":null}') jv3
from(
select *
,json_modify(jv,'$.id',null)jv2
from(
select id
,(SELECT * FROM test t2 where t2.id=t.id
FOR JSON PATH,WITHOUT_ARRAY_WRAPPER ) jv
from test t
)a
)b
)c;
id | jv | jv2 | jv3 | fl |
---|---|---|---|---|
1 | {"id":1,"col1":10,"col2":11,"col3":12} | {"col1":10,"col2":11,"col3":12} | {"col1":10,"col2":11,"col3":12} | 1 |
2 | {"id":2,"col1":20,"col2":21,"col3":22} | {“col1”:20,“col2”:21,“col3”:22} | {“col1”:20,“col2”:21,“col3”:22} | 1 |
3 | {"id":3,"col1":0,"col2":0,"col3":0} | {"col1":0,"col2":0,"col3":0} | {"col1":null,"col2":null,"col3":null} | 0 |
4 | {"id":4,"col1":30,"col2":0,"col3":33} | {"col1":30,"col2":0,"col3":33} | {"col1":30,"col2":null,"col3":33} | 1 |