MySQL 5.5-选择记录更改的行

时间:2019-02-01 11:14:56

标签: mysql sql window-functions

我已经有了这张表,我需要用最后一个A,第一个B,然后最后一个B和第一个A生成一行。预期结果在这里:

    ID | Date       | OPS
     6 | 2018-12-20 | A
     7 | 2018-12-20 | B
    11 | 2018-12-24 | B
    12 | 2018-12-25 | A

我尝试用零运气处理以下代码。 我无法使用分析功能,例如ROW_NUMBER(),LEAD()或LAG()。

SELECT *
FROM T1
JOIN (
    SELECT COUNT(*) cnt, t1.OPS
    FROM (
        SELECT DISTINCT ts1.OPS
        FROM T1 ts1
        JOIN T1 tx1 ON ts1.OPS = tx1.OPS
    ) t1
    JOIN (
        SELECT DISTINCT ts2.OPS
        FROM T1 ts2
        JOIN T1 tx2 ON ts2.OPS = tx2.OPS
    ) t2 on t1.OPS <= t2.OPS
    GROUP BY t1.OPS
) tt ON T1.OPS = tt.OPS

我的桌子是:

CREATE TABLE t1(
    ID int,
    Date1 date,
    OPS CHAR
);
INSERT INTO T1 VALUES
( 1, '2018-12-17', 'A'),
( 2, '2018-12-18', 'A'),
( 3, '2018-12-19', 'A'),
( 4, '2018-12-19', 'A'),
( 5, '2018-12-19', 'A'),
( 6, '2018-12-20', 'A'),
( 7, '2018-12-20', 'B'),
( 8, '2018-12-21', 'B'),
( 9, '2018-12-22', 'B'),
(10, '2018-12-23', 'B'),
(11, '2018-12-24', 'B'),
(12, '2018-12-25', 'A'),
(13, '2018-12-26', 'A'),
(14, '2018-12-27', 'A'),
(15, '2018-12-28', 'A');

4 个答案:

答案 0 :(得分:1)

如果没有LEADLAG,并且考虑到每个日期有多个记录,则可以使用可怕的简化解决方案,它假定记录是按以下顺序排序的id,而不是日期。它不需要id连续,并且可以用于两个以上的ops值:

SELECT *
FROM t AS ref
WHERE EXISTS (
    SELECT 1
    FROM t AS lag
    WHERE ops <> ref.ops
    AND id < ref.id
    AND NOT EXISTS (
        SELECT 1
        FROM t AS tmp
        WHERE id > lag.ID
        AND id < ref.id
    )
) OR EXISTS (
    SELECT 1
    FROM t AS led
    WHERE ops <> ref.ops
    AND id > ref.id
    AND NOT EXISTS (
        SELECT 1
        FROM t AS tmp
        WHERE id < led.ID
        AND id > ref.id
    )
)

基本上,对于每一行,查询都会搜索ID不匹配的所有先前行,然后确定它们之间是否存在一行。它也向前搜索。

答案 1 :(得分:0)

尝试以下逻辑,该逻辑使用一系列并集来表达您的问题:

(SELECT ID, Date1, OPS FROM T1 WHERE OPS = 'B' ORDER BY Date1 LIMIT 1)

UNION ALL

(SELECT ID, Date1, OPS FROM T1
WHERE OPS = 'A' AND Date1 <= (SELECT MIN(Date1) FROM T1 WHERE OPS = 'B')
ORDER BY Date1 DESC LIMIT 1)

UNION ALL

(SELECT ID, Date1, OPS FROM T1 WHERE OPS = 'B' ORDER BY Date1 DESC LIMIT 1)

UNION ALL

(SELECT ID, Date1, OPS FROM T1
WHERE OPS = 'A' AND Date1 >= (SELECT MAX(Date1) FROM T1 WHERE OPS = 'B')
ORDER BY Date1 LIMIT 1)

ORDER BY Date1, OPS;

enter image description here

Demo

通常请注意,这是一个空白和孤岛的问题。如果不使用您似乎没有的分析功能,这些操作将很难处理。如果您使用的是MySQL 8+,那么我们可以用一个简洁得多的查询来表述。

答案 2 :(得分:0)

您可以使用相关子查询来计算每个操作的最小和最大ID,例如

SELECT t.*
FROM T1 t
WHERE
    t.id IN (
        SELECT MIN(id) FROM T1 WHERE ops = t.ops
        UNION ALL SELECT MAX(id) FROM T1 WHERE ops = t.ops
    )
ORDER BY t.ops, t.id DESC

答案 3 :(得分:0)

如果我们允许使用max和min函数,那么很容易分别计算这4个结果并合并各个结果。

-选择最后一个A 选择ID,Date1,OPS   从test_t1  其中test_t1.OPS ='A'    和test_t1.Date1在        (         选择max(t1_a.Date1)作为Date1           从                (选择ID,Date1,OPS                   从test_t1                  其中OPS ='A')t1_a内部联接                (选择min(Date1)作为Date1                   从test_t1                   其中OPS ='B')t1_min_b                 在t1_a.Date1 <= t1_min_b.Date1上        ) 联合

-选择第一个B

选择ID,Date1,OPS   从test_t1  其中test_t1.OPS ='B'    和test_t1.Date1在        (         选择min(Date1)作为Date1           从test_t1          其中OPS ='B'        ) 联盟 / * 选择最后一个B / 选择ID,Date1,OPS   从test_t1  其中test_t1.OPS ='B'    和test_t1.Date1在        (         选择max(Date1)作为Date1           从test_t1          其中OPS ='B'        ) 联盟 / 选择第一个A * / 选择ID,Date1,OPS   从test_t1  其中test_t1.OPS ='A'    和test_t1.Date1在        (         选择min(t1_a.Date1)作为Date1           从                (选择ID,Date1,OPS                   从test_t1                  其中OPS ='A')t1_a内部联接                (选择max(Date1)作为Date1                   从test_t1                   其中OPS ='B')t1_max_b                 在t1_a.Date1> = t1_max_b.Date1上        ) ;