Запрос заказа только по указанному c полю, если все значения из набора результатов равны NULL - PullRequest
2 голосов
/ 03 апреля 2020

Я создаю систему управления версиями документов на своем веб-сайте.

Для этого у меня есть 2 таблицы "vrm_document" и "vrm_document_active_document". Первая таблица содержит все документы на моем веб-сайте, а вторая таблица сообщает мне, какой документ является активной версией для какого пользователя, поэтому вторая таблица содержит поле vrm_document_id и поле user_id. Активные документы обозначаются как parent_vrm_document_id не NULL.

У меня есть 2 вида документов:

  • Документы по умолчанию
  • Документы, загруженные самими пользователями

Каждый загруженный документ содержит версии и мин. 1 и макс. Для пользователя всегда должна быть активна 1 версия. Таким образом, вторая таблица vrm_document_active_document всегда будет содержать vrm_document_id в сочетании с user_id для документов, загруженных самим пользователем.

Однако проблема заключается в том, что документы по умолчанию - это документы, которые предоставляются моим веб-сайтом и всегда будут доступны всем. Если у пользователя нет собственной версии документа по умолчанию, документ по умолчанию станет активной версией для этого пользователя по умолчанию. Это замешано. Для активных документов мы НЕ вставляем строки в таблицу vrm_document_active_document. Это означает, что если нет версий документа по умолчанию, активных для пользователя, документ по умолчанию становится активной версией по умолчанию для этого пользователя.

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

Следующий запрос дает мне правильные результаты для документов, которые не являются документами по умолчанию:

SELECT vd.*
FROM `vrm_document` AS `vd`
LEFT JOIN vrm_document_active_document AS vdad ON (vd.vrm_document_id = vdad.vrm_document_id AND vd.user_id = vdad.user_id)
WHERE ((`vd`.`parent_vrm_document_id` = 1 AND `vd`.`user_id` IN (2,18,21)) OR (`vd`.`vrm_document_id` = 1  ) ) 
ORDER BY vdad.vrm_document_id DESC, vd.timestamp_modified_utc DESC

Однако, как видно из запроса, если мы представим, что идентификатор документа от 1 до быть документом по умолчанию, все поля в таблице vrm_document_active_document будут содержать NULL, и, таким образом, будут отсортированы по измененному времени.

Следующее (в псевдокоде) то, что мне нужно достичь, возможно ли это с помощью mariaDB SQL?

ORDER BY:

  • если все значения == NULL, то сначала значение с default_document, затем порядок поified_ut c
  • , в противном случае - по модифицированному_ut c

DB Fiddle: https://www.db-fiddle.com/f/71TUvdxFgFLhdncgo4BRre/1

EDIT: DB Fiddle добавлено

1 Ответ

1 голос
/ 03 апреля 2020

В MariaDB у вас есть функция ifnull , и вы можете использовать ее как

ifnull(expr1, expr2)

, что фактически говорит:

expr2

Если я хорошо понимаю вашу проблему, то ваше решение выглядит следующим образом:

order by ifnull(vdad.vrm_document_id, ifnull(vd.timestamp_modified_utc, someothervalue)) desc

В приведенном выше пункте someothervalue представляет любое поле, которое вы можете использовать по умолчанию. Желаемые критерии были неясны для меня. Однако, если вы хотите, чтобы документ по умолчанию был самым первым критерием, тогда

ORDER BY dv.is_default_document desc, vdad.vrm_document_id DESC, vd.timestamp_modified_utc DESC

или, если вы хотите, чтобы это был самый последний критерий, тогда

ORDER BY vdad.vrm_document_id DESC, vd.timestamp_modified_utc DESC, dv.is_default_document desc

РЕДАКТИРОВАТЬ

SELECT vdad.*, vd.*
FROM `vrm_document` AS `vd`
LEFT JOIN vrm_document_active_document AS vdad ON (vd.vrm_document_id = vdad.vrm_document_id AND vd.user_id = vdad.user_id)
WHERE ((`vd`.`parent_vrm_document_id` = 1 AND `vd`.`user_id` IN (2,18,21)) OR (`vd`.`vrm_document_id` = 1  ) ) 
ORDER BY 
CASE not exists (
    SELECT 1 as cnt
    FROM `vrm_document` AS `vd2`
    LEFT JOIN vrm_document_active_document AS vdad2 ON (vd2.vrm_document_id = vdad2.vrm_document_id AND vd2.user_id = vdad2.user_id)
    WHERE ((`vd2`.`parent_vrm_document_id` = 1 AND `vd2`.`user_id` IN (2,18,21)) OR (`vd2`.`vrm_document_id` = 1  ) ) 
    AND not ((vdad2.vrm_document_id is null) AND (vdad2.user_id))
)
WHEN 1 THEN vd.vrm_document_id
ELSE 0 END,
vdad.vrm_document_id DESC, 
vd.timestamp_modified_utc DESC

В приведенном выше запросе используется case-when-else-end для проверки существования некоторых записей. Для меня неясно, какими должны быть точные критерии, но даже если приведенный выше пример не является вашим точным соответствием, вы можете заменить

AND not ((vdad2.vrm_document_id is null) AND (vdad2.user_id))

на то, что вам нужно, и оно должно работать.

EDIT2

Текущий запрос по умолчанию сортируется по двум критериям в вопросе, но если первые два столбца имеют значение NULL, то самым первым элементом будет документ по умолчанию:

SELECT vdad.*, vd.*
FROM `vrm_document` AS `vd`
LEFT JOIN vrm_document_active_document AS vdad ON (vd.vrm_document_id = vdad.vrm_document_id AND vd.user_id = vdad.user_id)
WHERE ((`vd`.`parent_vrm_document_id` = 1 AND `vd`.`user_id` IN (2,18,21)) OR (`vd`.`vrm_document_id` = 1  ) ) 
ORDER BY 
CASE not exists (
    SELECT 1 as cnt
    FROM `vrm_document` AS `vd2`
    LEFT JOIN vrm_document_active_document AS vdad2 ON (vd2.vrm_document_id = vdad2.vrm_document_id AND vd2.user_id = vdad2.user_id)
    WHERE ((`vd2`.`parent_vrm_document_id` = 1 AND `vd2`.`user_id` IN (2,18,21)) OR (`vd2`.`vrm_document_id` = 1  ) ) 
    AND not ((vdad2.vrm_document_id is null) AND (vdad2.user_id))
)
WHEN 1 THEN vd.is_default_document
ELSE 0 END desc,
vdad.vrm_document_id DESC, 
vd.timestamp_modified_utc DESC
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...