SQL 根据另一行中的值排除行
Posted
技术标签:
【中文标题】SQL 根据另一行中的值排除行【英文标题】:SQL exclude rows based on value in another row 【发布时间】:2019-03-04 14:42:16 【问题描述】:我正在尝试排除另一行中存在值的行。
select * from TABLE1
ROW SEQ VALUE
1 1 HIGH
1 2 HIGH
1 3 LOW
1 4 HIGH
2 1 MED
2 2 HIGH
2 3 HIGH
2 4 LOW
2 5 HIGH
2 6 HIGH
所有数据都来自同一张表,我想要做的是排除 VALUE = 'LOW' 的行以及 SEQ
ROW SEQ VALUE
1 4 HIGH
2 5 HIGH
2 6 HIGH
这是正在进行的工作,但它只排除了一行
select * from TABLE1
where not exists(select VALUE from TABLE1
where ROW = ROW and VALUE = 'LOW' and SEQ <= SEQ)
我需要将其写入 where 原因,因为选择是硬编码的。我迷失了任何帮助将不胜感激。提前致谢!
【问题讨论】:
您的描述和示例数据似乎不匹配。 标记您正在使用的 DBMS。 【参考方案1】:select *
from table1
left outer join (
select row, max(seq) as seq
from table1
where value = 'low'
group by row
) lows on lows.row = table1.row
where lows.row is null
or table1.seq > lows.seq
【讨论】:
【参考方案2】:您应该为表设置别名。我很惊讶你从这个查询中得到任何结果,因为你根本没有别名。
select *
from TABLE1 As t0
where not exists(
select VALUE
from TABLE1 As t1
where t0.ROW = t1.ROW
and t1.VALUE = 'LOW'
and t0.SEQ <= t1.SEQ
)
【讨论】:
谢谢@Zohar 对不起,我是别名,但试图简化查询示例。但是,我没有在 not exists 子句中为表起别名。谢谢你成功了! Glad to help :-)【参考方案3】:您可以使用具有累积方法的窗口函数:
select t.*
from (select t.*, sum(case when value = 'LOW' then 1 else 0 end) over (partition by row order by seq) as cnt
from table t
) t
where cnt = 1 and value <> 'LOW';
【讨论】:
【参考方案4】:对于您提到的结果,您似乎想要最后一个“低”之后的行。一种方法是:
select t1.*
from table1 t1
where t1.seq > (select max(t2.seq) from table1 tt1 where tt1.row = t1.row and tt1.value = 'LOW');
(注意:这需要一个“低”行。如果没有“低”行并且您希望返回所有行,则很容易将其添加到查询中。)
或者,类似地,使用not exists
:
select t1.*
from table1 t1
where not exists (select 1
from table1 tt1
where tt1.row = t1.row and
tt1.seq > t.seq and
tt1.value = 'LOW'
);
这可能是您问题的最直接翻译。
但是,我更可能使用窗口函数:
select t1.*
from (select t1.*,
max(case when t1.value = 'low' then seqnum end) over (partition by row) as max_low_seqnum
from table1 t1
) t1
where seqnum > max_low_seqnum;
如果没有“低”行,您可能需要添加 or max_low_seqnum is null
以返回所有行。
【讨论】:
以上是关于SQL 根据另一行中的值排除行的主要内容,如果未能解决你的问题,请参考以下文章