Выберите строки из таблицы, игнорируйте строки, пока не встретите значение поля - PullRequest
1 голос
/ 05 января 2020

Допустим, у меня есть таблица, которая содержит информацию о сбережениях пользователей в экономном обществе и оценку каждого типа депозита как хорошо или плохо на основе внутренних логик c. Как выбрать строки из этой таблицы, чтобы все предыдущие строки до последней правильной строки пропускались для пользователя?

До

id     | user |type | amount
----------------------------
20     | 98   | good | 40
35     | 98   | bad  | 30
62     | 98   | good | 20
89     | 98   | bad  | 60
93     | 98   | bad  | 10
100    | 99   | good | 20
103    | 99   | good | 22
109    | 99   | good | 220
121    | 99   | bad  | 640
193    | 99   | bad  | 110

Я хотел бы игнорировать все записи для пользователя до тех пор, пока не встретится последняя хорошая строка, после чего можно будет подсчитать последующие строки. Строки упорядочены по возрастанию id s, которые не являются последовательными.

После

id     | user |type | amount
----------------------------
62     | 98   | good | 20
89     | 98   | bad  | 60
93     | 98   | bad  | 10
100    | 99   | good | 220
121    | 99   | bad  | 640
193    | 99   | bad  | 110

Ответы [ 3 ]

1 голос
/ 05 января 2020

Присоедините таблицу к запросу, который возвращает максимальный идентификатор для каждого пользователя с помощью 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    |
0 голосов
/ 05 января 2020

Для MariaDB 10.2+, Window Analyti c Могут использоваться такие функции, как

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;

Демонстрация

0 голосов
/ 05 января 2020

Один метод использует коррелированный подзапрос:

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).

Исходя из формулировки вашего вопроса, я интерпретировать это как требующий хотя бы одного хорошего ряда. Если это не так, то можно использовать следующие логики c:

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;
...