Mysql 筛选出孤立表项

Mysql 筛选出孤立表项,mysql,sql,duplicate-removal,gaps-and-islands,Mysql,Sql,Duplicate Removal,Gaps And Islands,假设有一个只有两列的表(下面显示了一个示例)。每个“1”条目后面都应该跟一个“0”(按照下面给出的排序顺序)。但是,正如您所看到的,在表中,有一些“孤儿”,其中有两个连续的“1” 如何创建一个返回所有行的查询,除了任何连续“1”中的第一行之外?(这将使下面的示例从16行减少到14行) 我将尝试澄清我的问题,我认为上面我简化了太多。想象一个名为“日志”的表,它有四列: user(包含用户名的字符串) 机器(唯一标识各种PC的字符串) 类型(事件类型:1表示登录,0表示注销) 时间(记录事件的时

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

如何创建一个返回所有行的查询,除了任何连续“1”中的第一行之外?(这将使下面的示例从16行减少到14行)


我将尝试澄清我的问题,我认为上面我简化了太多。想象一个名为“日志”的表,它有四列:

  • user
    (包含用户名的字符串)
  • 机器
    (唯一标识各种PC的字符串)
  • 类型
    (事件类型:1表示登录,0表示注销)
  • 时间
    (记录事件的时间)
[机器/时间对提供唯一密钥,因为任何机器都不能同时登录或注销两次。如果需要,可以根据机器/时间排序人工创建“ID”列。]

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

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

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

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

只要

  • 只有1是被复制的,而不是0
  • 如果有更多的1,你想去掉所有的前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,请另外使用注释子句,但可能不需要

问题编辑后编辑: 您可能希望向数据中添加一个自动增量列,以简化此操作:

其他RDBMS(PostgreSQL、Oracle、SQL Server等)具有窗口功能,如
row_number()
lag()
lead()

  • 只有1是被复制的,而不是0
  • 如果有更多的1,你想去掉所有的前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,请另外使用注释子句,但可能不需要

问题编辑后编辑: 您可能希望向数据中添加一个自动增量列,以简化此操作:


其他RDBMS(PostgreSQL、Oracle、SQL Server等)具有窗口功能,如
行号()
滞后()
超前()
,这使得此类操作更加容易。

使用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
    ;
删除表tmp.bits;
创建表tmp.bits
(id序列号不为空
,位整数不为空
,代码字符(1)
);
插入tmp.bits(位,代码)值
(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')
;
设置search_path='tmp';
从位中选择*;
--解释分析
以下一个为例(
挑选
bt.id作为thisid
,bt.bit与thisbit相同
,bt.code作为此代码
,bp.bit作为前一位
,bp.code作为prevcode
来自英国电信
左连接位bp开启(bt.id>bp.id)
并且不存在(从位nx中选择*
其中nx.id>bp.id
和nx.id
编辑:

对于那些不能使用CTE的糟糕的SOAL,很容易创建一个视图:

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
    ;
创建下一个视图作为(
挑选
bt.id作为thisid
,bt.bit与thisbit相同
,bt.code作为此代码
,bp.bit作为前一位
,bp.code作为prevcode
来自英国电信
左连接位bp开启(bt.id>bp.id)
并且不存在(从位nx中选择*
其中nx.id>bp.id
和nx.id
使用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
    ;
删除表tmp.bits;
创建表tmp.bits
(id序列号不为空
,位整数不为空
,代码字符(1)
);
插入tmp.bits(位,代码)值
(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')
;
设置search_path='tmp';
从位中选择*;
--解释分析
以下一个为例(
挑选
bt.id作为thisid
,bt.bit与thisbit相同
,bt.code作为此代码
,bp.bit作为前一位
,bp.code作为prevcode
来自英国电信
左连接位bp开启(bt.id>bp.id)
并且不存在(从位nx中选择*
其中nx.id>bp.id
和nx.id
编辑:

对于那些不能使用CTE的糟糕的SOAL,很容易创建一个视图:

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
    ;
创建下一个视图作为(
挑选
bt.id作为thisid
,bt.bit与thisbit相同
,bt.code作为此代码
,bp.bit作为前一位
,bp.code作为prevcode
来自英国电信
左连接位bp开启(bt.id>bp.id)
并且不存在(从位nx中选择*
其中nx.id>bp.id
和nx.id