1

假设有一个只有两列的表(示例如下所示)。每个 '1' 条目后(按照下面给出的排序顺序)应该跟一个 '0'。但是,如您所见,在表中,有一些“孤儿”,其中有两个连续的“1”。

如何创建一个返回所有行的查询,除了任何连续的“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(唯一标识各种 PC 的字符串)
  • type(事件类型:1 表示登录0表示注销)
  • time(记录事件的时间)

[机器/时间对提供唯一的密钥,因为任何机器都不能同时登录或退出两次。如果需要,可以根据机器/时间排序人为地创建一个“ID”列。]

这个想法是每个登录事件都应该伴随一个注销事件。用理想的话来说,将登录与注销相匹配是相当容易的,因此可以分析登录所花费的时间。

但是,在断电的情况下,不会记录注销。因此(仅考虑一台机器的数据,按时间排序)如果连续有两个登录事件,我们希望忽略第一次登录,因为我们没有任何可靠的数据。这是我试图解决的问题。

4

4 回答 4

1

前提是

  • 只有 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

如果要保留双 0,请另外使用注释子句,但可能不需要。

问题编辑后编辑:

您可能希望在数据中添加一个自动增量列以使其更简单: Generate (ie write) a row number index column in MySQL

其他 RDBMS(PostgreSQL、Oracle、SQL Server 等)具有类似row_number()or的窗口函数lag()lead()这使得此类操作更加容易。

于 2011-11-16T10:14:23.457 回答
0

使用 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 的可怜的 soals,很容易创建一个视图来代替:

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
    ;
于 2011-11-16T11:44:09.677 回答
0

假设您获得一个 id(添加列,设置列 id = 数据库中的记录号),请使用:

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
于 2011-11-16T10:00:00.767 回答
0

尝试:

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 () )
于 2011-11-16T12:01:32.287 回答