MySQL 5.5 - Выберите строки, где изменения записи - PullRequest
0 голосов
/ 01 февраля 2019

У меня есть эта таблица, и мне нужно создать строку с последним 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 голосов
/ 01 февраля 2019

если нам разрешены функции max и min, то довольно легко рассчитать эти 4 по отдельности и объединить отдельные результаты.

- чтобы выбрать последний A, выберите ID, Date1, OPS из test_t1, где test_t1.OPS = 'A' и test_t1.Date1 in (выберите 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) union </p>

- для выбора первого B

выберите ID, Date1, OPS из test_t1, где test_t1.OPS= 'B' и test_t1.Date1 in (выберите min (Date1) как Date1 из test_t1, где OPS = 'B') объединение / * Для выбора последнего B / выберите ID, Date1, OPS из test_t1, где test_t1.OPS ='B' и test_t1.Date1 in (выберите max (Date1) в качестве Date1 из test_t1, где OPS = 'B') объединение / Для выбора первого A * / выберите ID, Date1, OPS из test_t1, где test_t1.OPS = 'A 'и test_t1.Date1 in (выберите 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);

0 голосов
/ 01 февраля 2019

Вы можете использовать коррелированный подзапрос, который вычисляет минимальный и максимальный идентификаторы для каждой операции, например

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
0 голосов
/ 01 февраля 2019

Без LEAD и LAG и учитывая, что у вас есть несколько записей на дату, вы можете использовать ужасающее упрощенное решение , которое предполагает, что записи упорядочены по 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
    )
)

В основном для каждой строки, запрос ищет все предыдущие строки, где идентификаторы не совпадают, затем определяет, есть ли строка вмежду.Он также ищет вперед.

0 голосов
/ 01 февраля 2019

Попробуйте следующую логику, которая формулирует ваш вопрос, используя ряд союзов:

(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

Демо

Обратите внимание, что это проблема пробелов и островков.С ними очень трудно справиться без использования аналитических функций, которые, по-видимому, вам недоступны.Если бы вы использовали MySQL 8+, то мы могли бы сформулировать более понятный запрос.

...