Выберите первую запись с rev_parent_id = 0 из объединенных таблиц - PullRequest
0 голосов
/ 18 февраля 2019

еще один на вечеринку # great-n-per-group!

Мой предыдущий код:

select count(*)
  from revisions join files on rev_file = file_id
 where rev_parent_id like 0
   and rev_timestamp between '20011231230000' and '20191231225959'
   and file_namespace like 0
   and file_is_redirect like 0

Проблема в том, что для некоторых файлов существует несколько записей с rev_parent_id= 0.Я хотел бы сосчитать только те из них, у которых был самый ранний rev_timestamp, но мои попытки использовать ответы в SQL выбирают только строки с максимальным значением в столбце и Выбрать самые ранние дату и время из списка отдельных пользовательских сессий дайте мне приблизительно 9 000 и 11 000 000. Правильное число должно быть примерно 422 000. Возможно, мне не удастся правильно соединить три таблицы, вот одна из моих попыток (эта с 9 000 результатов):

select count(r1.rev_file) 
  from revisions r1
  left outer join revisions r2 on (r1.rev_file = r2.rev_file
                              and r1.rev_timestamp < r2.rev_timestamp) 
  join files on r1.rev_file = file_id 
 where r2.rev_file is NULL
   and r1.rev_parent_id like 0 
   and r1.rev_timestamp between '20011231230000' and '20191231225959' 
   and file_namespace like 0
   and file_is_redirect like 0

Структуры таблиц:

files
file_id, file_namespace, file_is_redirect
1234, 0, 0
1235, 3, 1
1236, 3, 0

revisions
rev_file, rev_id, rev_parent_id, rev_timestamp
1234, 19, 16, 20170302061522
1234, 16, 0, 20170302061428
1234, 14, 12, 20170302061422
1234, 12, 0, 20170302061237
1235, 21, 18, 20170302061815
1235, 18, 13, 20170302061501
1235, 13, 8, 20170302061355
1235, 8, 3, 20170302061213
1235, 3, 0, 20170302061002
1236, 6, 0, 20170302061014

file_id = rev_file = id файла.file_namespace = mimetype файла, 0 является открытым текстом.rev_id = идентификатор ревизии.rev_parent_id = идентификатор родительской ревизии.rev_timestamp = метка времени ревизии

Единственный действительный файл - 1234, он был удален и воссоздан, поэтому он получил две записи rev_parent_id = 0.Я хочу считать файл только в том случае, если между выбранными временами была более ранняя версия rev_parent_id = 0.

Ответы [ 3 ]

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

Вы должны присоединиться к подзапросу для min rev_timestamp для файла rev_file

    select count(*) 
    from revisions 
    join files on rev_file = file_id 
    join  (

        select rev_file, min(rev_timestamp) min_time
        from revisions
        where rev_parent_id = 0 
        group  by rev_file

    ) t on t.min_time  = revisions.rev_timestamp 
            and t.rev_file = revisions.rev_file
    where rev_parent_id like 0 
    and rev_timestamp between '20011231230000' and '20191231225959' 
    and file_namespace like 0 
    and file_is_redirect like 0
0 голосов
/ 18 февраля 2019

Спасибо, ребята, @scaisedge и @ o-jones, наконец-то я воспользовался ядром обоих ваших ответов и удалил лишний код, и вот что у меня сработало в итоге:

select count(*)
  from (select rev_file, min(rev_timestamp) rev_timestamp from revision where rev_parent_id like 0 group by rev_file) revision
  join file on rev_file = file_id
 where rev_timestamp between '20011231230000' and '20191231225959'
   and file_namespace like 0
   and not file_is_redirect;

Возможно, яможет также сэкономить некоторое время выполнения, переместив условия file_namespace и file_is_redirect в другой подзапрос в объединении, но, возможно, нет, я не уверен.

Ответ scaisedge более краткий и лучше читаемый, поэтому я сразу понял его и предпочелЭто.scaisedge просто имел некоторые ошибки в коде (исправлено мной).Ответ o-jones более перегружен ненужными вещами, но он более подробный, если любому читателю понадобятся объяснения, и благодаря советам по улучшению я узнал некоторые проблемы с синхронизацией в своем коде.

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

Сначала давайте воспользуемся подзапросом, чтобы найти самые ранние отметки времени в revisions для каждого rev_file, соответствующие вашим критериям.

          SELECT MIN(rev_timestamp) rev_timestamp, rev_file
            FROM revisons
           WHERE rev_parent_id like 0 
             AND rev_timestamp between '20011231230000' and '20191231225959' 
           GROUP BY rev_file

Это дает вам виртуальную таблицу с самой ранней отметкой времени для каждого файлав соответствии с вашими критериями.

Далее, присоедините эту таблицу к другим вашим таблицам, как это

SELECT COUNT(*) count
  FROM revisions r1
  JOIN (
          SELECT MIN(rev_timestamp) rev_timestamp, rev_file
            FROM revisons
           WHERE rev_parent_id like 0 
             AND rev_timestamp between '20011231230000' and '20191231225959' 
           GROUP BY rev_file
       ) rmin ON r1.rev_timstamp = rmin.rev_timestamp
             AND r1.rev_file = rmin.rev_file
  JOIN files f ON r1.rev_file = file_id
   and f.file_namespace like 0
   and f.file_is_redirect like 0            

Совет Pro : форматирование запросов, чтобы они были читабельными, всегда стоит проблем.

Pro tip : Используйте COUNT(*) вместо COUNT(col), где это возможно.Это быстрееИ, если упомянутое вами col потенциально не содержит значений NULL, оно дает тот же результат.Это не относится к запросам в вопросе.

Pro tip : всегда квалифицируйте столбцы в операциях JOIN (f.file_is_redirect, а не file_is_redirect).Опять же, читаемость запросов является мотивацией.Если вам повезло, что ваш код однажды был поддержан кем-то другим, этот человек будет рад это увидеть.Это жизненно важная часть программирования для профессионалов и энтузиастов.

Pro tip : numeric_col LIKE 0 снижает производительность.Это для соответствующего текста (column LIKE '%verflo' соответствует Stack Overflow).Когда вы используете LIKE для числового столбца, он приводит тип данных каждого столбца к строке, а затем запускает на нем оператор LIKE, побеждая использование любого индекса, имеющегося у числового столбца.

...