Отфильтровать записи бесхозных таблиц - PullRequest
1 голос
/ 16 ноября 2011

Предположим, есть таблица только с двумя столбцами (пример показан ниже). За каждой записью «1» следует (в порядке сортировки, указанном ниже) знак «0». Однако, как вы можете видеть, в таблице есть некоторые «сироты», где есть два последовательных «1».

Как создать запрос, который возвращает все строки, кроме первой из любых последовательных единиц? (Это уменьшит пример ниже с 16 строк до 14)

1 E
0 A
1 T
0 S
1 R
0 E
1 F
0 T
1 G
1 T
0 R
1 X
1 R
0 R
1 E
0 T

Я собираюсь попытаться прояснить мою проблему, я думаю, что выше я слишком упростил ее. Представьте себе одну таблицу с именем logs с четырьмя столбцами:

  • user (строка, содержащая имя пользователя)
  • machine (строка, однозначно идентифицирующая различные ПК)
  • type (тип события: 1 для журнала i n и 0 для журнала o ut)
  • time (время регистрации события)

[Пара машина / время предоставляет уникальный ключ, так как ни одна машина не может войти или выйти дважды в одно и то же время. Предположительно, при необходимости может быть искусственно создан столбец «ID» на основе машинной / временной сортировки.]

Идея состоит в том, что каждое событие входа в систему должно сопровождаться событием выхода из системы. Одним словом, было бы довольно просто сопоставить входы в систему и, следовательно, проанализировать время, проведенное в системе.

Однако в случае отключения питания выход из системы не будет записан. Поэтому (учитывая только данные одного компьютера, отсортированные по времени), если в строке два события входа в систему, мы хотим игнорировать первый вход в систему, потому что у нас нет надежных данных от него. Это проблема, которую я пытаюсь решить.

Ответы [ 4 ]

1 голос
/ 16 ноября 2011

при условии, что

  • только 1 являются одураченными, а не 0
  • Вы хотите избавиться от всех первых 1, если их больше.

В вашем тексте написано "за исключением первого из любого последовательного", но я думаю, это то, что вы хотите. Или может быть только 2, тогда это то же самое.

SELECT x.*
FROM   x
LEFT   JOIN x y on y.id = (x.id + 1)
WHERE  (x.nr = y.nr) IS NOT TRUE -- OR x.nr = 0
ORDER  BY x.id

Если вы хотите сохранить двойные нули, используйте закомментированное предложение дополнительно, но, вероятно, в этом нет необходимости.

Редактировать после редактирования вопроса:

Возможно, вы захотите добавить столбец автоинкремента к вашим данным, чтобы сделать это проще: Создание (т.е. запись) индексного столбца номера строки в MySQL

Другие СУБД (PostgreSQL, Oracle, SQL Server, ..) имеют оконные функции, такие как row_number() или lag() и lead(), которые значительно упрощают такую ​​операцию.

0 голосов
/ 16 ноября 2011

Попробуйте:

select l.*
from logs l
where l.type = 0 or
      not (select type
           from (select * from logs order by `time` desc) n
           where n.machine = l.machine and
                 n.user = l.user and
                 n.time > l.time)
           group by () )
0 голосов
/ 16 ноября 2011

ИСПОЛЬЗУЯ CTE, чтобы отделить лаг-логику от критериев выбора.

DROP TABLE tmp.bits;
CREATE TABLE tmp.bits
    ( id SERIAL NOT NULL
    , bit INTEGER NOT NULL
    , code CHAR(1)
    );
INSERT INTO tmp.bits(bit, code) VALUES
(1, 'T' )
, (0, 'S' )
, (1, 'R' )
, (0, 'E' )
, (1, 'F' )
, (0, 'T' )
, (1, 'G' )
, (1, 'T' )
, (0, 'R' )
, (1, 'X' )
, (1, 'R' )
, (0, 'R' )
, (1, 'E' )
, (0, 'T' )
    ;

SET search_path='tmp';
SELECT * FROM bits;

-- EXPLAIN ANALYZE
WITH prevnext AS (
SELECT
    bt.id AS thisid
    , bt.bit  AS thisbit
    , bt.code AS thiscode
    , bp.bit AS prevbit
    , bp.code AS prevcode
    FROM bits bt
    LEFT JOIN bits bp ON (bt.id > bp.id)
    AND NOT EXISTS ( SELECT * FROM bits nx
        WHERE nx.id > bp.id
        AND nx.id < bt.id
        )   
    )
SELECT thisid, thisbit, thiscode
FROM prevnext
WHERE thisbit=0
OR prevbit IS NULL OR thisbit <> prevbit
    ;

РЕДАКТИРОВАТЬ:

для тех бедных почв, которые не могут использовать CTE, легко создать представлениевместо:

CREATE VIEW prevnext AS (
SELECT
    bt.id AS thisid
    , bt.bit  AS thisbit
    ,bt.code AS thiscode
    , bp.bit AS prevbit
    , bp.code AS prevcode
    FROM bits bt
    LEFT JOIN bits bp ON (bt.id > bp.id)
    AND NOT EXISTS ( SELECT * FROM bits nx
        WHERE nx.id > bp.id
        AND nx.id < bt.id
        )
    )
    ;
SELECT thisid, thisbit, thiscode
FROM prevnext
WHERE thisbit=0
OR prevbit IS NULL OR thisbit <> prevbit
    ;
0 голосов
/ 16 ноября 2011

Если вы получаете идентификатор (добавить столбец, задать идентификатор столбца = номер записи в базе данных), используйте:

select a.*
  from the_table a
  left join the_table b on b.id = a.id + 1
                       and b.col1 = 0
 where a.col1 = 1
   and b.id is null
...