За последние 24 часа нас посетили 22417 программистов и 1148 роботов. Сейчас ищут 707 программистов ...

Задачка: сравнить первую и вторую записи в группе

Тема в разделе "MySQL", создана пользователем artoodetoo, 22 янв 2020.

Метки:
  1. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.072
    Симпатии:
    1.237
    Адрес:
    там-сям
    Взято с одного популярного ресурса, пока не буду спойлерить.

    Дано: Есть таблицы люди (person) и опросы (survey). Где в survey хранятся данные анкетирования людей на какой-то момент времени. Пусть в нём будут колонки адрес (address) и семейное положение (marriage_status). На каждого человека может приходиться любое количество записей в опроснике.

    Требуется: Выбрать тех людей, чей адрес или семейное положение изменилось с момента предыдущего опроса. То есть для каждого товарища надо сравнить самую свежую запись опросника с предыдущей.

    Не упомянутые здесь колонки, а также тип данных можете придумывать на своё усмотрение, как вам удобнее.
     
    #1 artoodetoo, 22 янв 2020
    Последнее редактирование: 22 янв 2020
    Valick нравится это.
  2. retvizan

    retvizan Активный пользователь

    С нами с:
    27 дек 2013
    Сообщения:
    68
    Симпатии:
    22
    неясная постановка задачи:
    "сравненить первую и вторую записи в группе" - это выбрать N записей из каждой группы, где N = 2
    "тех людей, чей адрес или семейное положение изменилось с момента предыдущего опроса" - это сравнить каждую последовательную пару опросов для каждого человека (тут, имхо, только WITH или через хранимую процедуру)
     
  3. runcore

    runcore Старожил

    С нами с:
    12 окт 2012
    Сообщения:
    3.625
    Симпатии:
    158
  4. Valick

    Valick Активный пользователь

    С нами с:
    12 авг 2018
    Сообщения:
    1.911
    Симпатии:
    328
    нет
     
  5. retvizan

    retvizan Активный пользователь

    С нами с:
    27 дек 2013
    Сообщения:
    68
    Симпатии:
    22
    согласен, переменными и оконными ф-ями тоже можно
     
  6. Valick

    Valick Активный пользователь

    С нами с:
    12 авг 2018
    Сообщения:
    1.911
    Симпатии:
    328
  7. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.072
    Симпатии:
    1.237
    Адрес:
    там-сям
    Загляни, ибо уже понятно что сам ты ничего не предложишь. :)
    --- Добавлено ---
    Я поправил 1 и 2 на "самую свежую" и "предыдущую". Может быть так будет понятнее.
     
  8. Valick

    Valick Активный пользователь

    С нами с:
    12 авг 2018
    Сообщения:
    1.911
    Симпатии:
    328
    в реализации @runcore есть один минус (кто догадается какой?), я мыслю в ином направлении но сначала работа, потом удовольствия))
     
  9. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.072
    Симпатии:
    1.237
    Адрес:
    там-сям
    Сам я придумал через Common Table Expression т.е. через "WITH", будет работать с MySQL v8
    Код (SQL):
    1. WITH
    2.   cte1 AS (
    3.     SELECT MAX(n1.id) AS id, n1.person_id
    4.     FROM survey AS n1
    5.     GROUP BY n1.person_id),
    6.  
    7.   cte2 AS (
    8.     SELECT MAX(n2.id) AS id, n2.person_id
    9.     FROM survey n2 JOIN cte1 ON cte1.person_id = n2.person_id AND cte1.id > n2.id
    10.     GROUP BY n2.person_id)
    11.  
    12. SELECT p.*, s1.address, s2.address address2, s1.marriage_status, s2.marriage_status marriage_status2
    13. FROM person AS p
    14. JOIN ( cte1 JOIN survey s1 ON s1.id = cte1.id ) ON cte1.person_id = p.id
    15. JOIN ( cte2 JOIN survey s2 ON s2.id = cte2.id ) ON cte2.person_id = p.id
    16. WHERE
    17.    (s1.address <> s2.address)
    18. OR (s1.marriage_status <> s2.marriage_status)
    если решить, что "последнюю" надо искать по таймштампу, а не по айди, то будет немного другой джойн. Что-то вроде
    SELECT MAX(n1.dt)AS dt, n1.person_id
    и потом
    cte2 JOIN survey s2 USING(person_id, dt)
    https://stackoverflow.com/q/59853031/272885
    там есть и другие варианты
     
    #9 artoodetoo, 22 янв 2020
    Последнее редактирование: 22 янв 2020
  10. runcore

    runcore Старожил

    С нами с:
    12 окт 2012
    Сообщения:
    3.625
    Симпатии:
    158
    это успешно можно заменить на
    CREATE temporary TABLE cte1 AS
    SELECT MAX(n1.id) AS id, n1.person_id ....
    :)
     
  11. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.072
    Симпатии:
    1.237
    Адрес:
    там-сям
    а надо? :)
    --- Добавлено ---
    всё-таки это больше похоже на view, чем на temporary table
     
  12. runcore

    runcore Старожил

    С нами с:
    12 окт 2012
    Сообщения:
    3.625
    Симпатии:
    158
    это на случай, если надо чтоб работало на версии ниже 8-ки