I am building a custom document versioning system in my website.
For this, I have 2 tables "vrm_document
" and "vrm_document_active_document
".
The first table contains all documents on my website, while the second table tells me which document is the active version for which user, so the second table contains the vrm_document_id
field and a user_id
field. Active documents are indicated by the parent_vrm_document_id
being not NULL.
I have 2 kinds of documents:
- Default documents
- Documents uploaded by the users themselves
Each document that is uploaded contains versions, and min. 1 and max. 1 version has to be active at all times for the user. Thus the second table vrm_document_active_document
will always contain the vrm_document_id
combined with the user_id
for the documents uploaded by the user himself.
However, the problem resides in the fact that default documents are documents that are provided by my website and will always be available to everyone. When a user does not have its own version of a default document, the default document will become the active version for that user by default. This is implicated. For active documents we do NOT insert rows in the vrm_document_active_document
table. This means that if there are no versions of a default document active for the user, the default document becomes the active version by default for that user.
When displaying the documents with their versions to the user, I want to show all the versions in a list under each other, where the active version is displayed first, and then the others are sorted on the last modified time.
The following query gives me the correct results for documents that aren't default documents:
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
However, as can be seen from the query, if we imagine that document ID 1 to be a default document, all fields in the vrm_document_active_document
table will contain NULL, and thus it will sort based on the modified time.
The following is (in pseudo-code) what I need to achieve, is this possible using mariaDB SQL?
ORDER BY:
- if all values == NULL then value with default_document is first , then order by modified_utc
- else order by modified_utc
DB Fiddle: https://www.db-fiddle.com/f/71TUvdxFgFLhdncgo4BRre/1
EDIT: DB Fiddle added
In MariaDB you have the ifnull function and you can use it as
ifnull(expr1, expr2)
which effectively says:
evaluate expr1 and if it's null, then evaluate expr2
If I understand your problem well, then your solution looks like
order by ifnull(vdad.vrm_document_id, ifnull(vd.timestamp_modified_utc, someothervalue)) desc
In the clause above someothervalue represents any field that you may want to default to. The desirable criteria was unclear to me. However, if you want the default document to be the very first criteria, then
ORDER BY dv.is_default_document desc, vdad.vrm_document_id DESC, vd.timestamp_modified_utc DESC
or, if you want that to be the very last criteria, then
ORDER BY vdad.vrm_document_id DESC, vd.timestamp_modified_utc DESC, dv.is_default_document desc
EDIT
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
The query above uses case-when-else-end to check for the existence of some records. It is unclear for me what should be the exact criteria, but, even if the example above is not your exact match, then you can replace
AND not ((vdad2.vrm_document_id is null) AND (vdad2.user_id))
to what you need and it should work.
EDIT2
The current query sorts by the two criteria in the question by default, but if the first two columns are null, then the very first element will be the default document:
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