假设我有一个表格,其中包含有关节俭社会的用户储蓄信息,以及基于内部逻辑对每种存款类型的好坏评估。如何从此表中选择行,以便每个用户跳过前面的所有行到最后一行?
以前
ID | 用户 |类型 | 金额 ---------------------------- 20 |98 |好 |40 35 |98 |不好 |30 62 |98 |好 |20 89 |98 |不好 |60 93 |98 |不好 |10 100 |99 |好 |20 103 |99 |好 |22 109 |99 |好 |220 121 |99 |不好 |54秒 193 |99 |不好 |110
我想忽略用户的所有记录,直到遇到最后一行好,然后可以计算后续行。行按递增 id 进行排序,这些id不是连续的。
后
ID | 用户 |类型 | 金额 ---------------------------- 62 |98 |好 |20 89 |98 |不好 |60 93 |98 |不好 |10 100 |99 |好 |220 121 |99 |不好 |54秒 193 |99 |不好 |110
将表连接到一个查询,该查询返回每个用户的最大 id,type = 'good'
:
select t.*
from tablename t inner join (
select user, max(id) id
from tablename
where type = 'good'
group by user
) tt on tt.user = t.user and tt.id <= t.id
请参阅演示。
结果:
| id | user | type | amount |
| --- | ---- | ---- | ------ |
| 62 | 98 | good | 20 |
| 89 | 98 | bad | 60 |
| 93 | 98 | bad | 10 |
| 109 | 99 | good | 220 |
| 121 | 99 | bad | 640 |
| 193 | 99 | bad | 110 |
一种方法使用相关的子查询:
select t.*
from t
where t.id >= (select max(t2.id)
from t t2
where t2.user = t.user and t2.type = 'good'
);
如果您有(user, type, id)
上的索引,这应该具有良好的性能。
根据你问题的措辞,我将其解释为至少需要一个好的行。 如果不是这种情况,则可以使用以下逻辑:
select t.*
from t
where t.id >= all (select t2.id
from t t2
where t2.user = t.user and t2.type = 'good'
);
您还可以使用窗口函数:
select t.*
from (select t.*,
max(case when type = 'good' then id end) over (partition by user) as max_good_id
from t
) t
where id >= max_good_id;
对于MariaDB 10.2+
,可以使用窗口分析函数,例如
SUM() OVER (PARTITION BY ... ORDER BY ...)
WITH T2 AS
(
SELECT SUM(CASE WHEN type = 'good' THEN 1 ELSE 0 END)
OVER (PARTITION BY user ORDER BY id DESC) AS sum,
T.*
FROM T
)
SELECT id, user, type, amount
FROM T2
WHERE ( type = 'good' AND sum = 1 ) OR ( type != 'good' AND sum = 0 )
ORDER BY id;
演示