I have a table with 6 columns as follows:
x
CREATE TABLE `test_table` (
`id` bigint UNSIGNED NOT NULL,
`A` varchar(255) NOT NULL,
`B` varchar(2) NOT NULL,
`C` varchar(50) DEFAULT NULL,
`D` varchar(10) DEFAULT NULL,
`E` varchar(10) DEFAULT NULL
) ENGINE=InnoDB;
For searching I am providing target values for B/C/D and selecting columns A and E for a result set.
I would like to obtain a row if:
- B/C/D all match provided values => select it
- B/C match but D is NULL => select it
- B/D match but C is NULL => select it
- B matches and C/D are NULL as a final fallback.
Basically I would like to get a row if conditions are hit in order (eg: if I have a match for all 3, I don’t want a result from the next condition)
So far the closes I’ve come is this:
SELECT m.*
FROM test_table m
WHERE m.id IN (
SELECT o.id
FROM (
SELECT i.id, i.A, i.C, i.D, i.B
FROM test_table i
WHERE i.B=?
) o
WHERE m.A = o.A
ORDER BY o.A, -o.C ASC, -o.D ASC
) AND (
(m.C=? AND m.D=?) OR
(m.C=? AND m.D IS NULL ) OR
(m.C IS NULL AND m.D=? ) OR
(m.C IS NULL AND m.D IS NULL )
);
However, I do run into the issue that I get multiple records when C/D are both NULL + C has matching value and D is NULL.
Can someone suggest what I can do?
Thanks!
Advertisement
Answer
You can create a column for each of your conditions, sort the results by the priority of each condition and return the 1st row only:
select a, e
from (
select *,
coalesce(b = ?, 0) + coalesce(c = ?, 0) + coalesce(d = ?, 0) cond1,
coalesce(b = ?, 0) + coalesce(c = ?, 0) + (d is null) cond2,
coalesce(b = ?, 0) + (c is null) + coalesce(d = ?, 0) cond3,
coalesce(b = ?, 0) + (c is null) + (d is null) cond4
from test_table
) t
where 3 in (cond1, cond2, cond3, cond4)
order by (cond1 = 3) desc, (cond2 = 3) desc, (cond3 = 3) desc, (cond4 = 3) desc
limit 1
Or:
select a, e
from (
select *,
coalesce(b = ?, 0) and coalesce(c = ?, 0) and coalesce(d = ?, 0) cond1,
coalesce(b = ?, 0) and coalesce(c = ?, 0) and (d is null) cond2,
coalesce(b = ?, 0) and (c is null) and coalesce(d = ?, 0) cond3,
coalesce(b = ?, 0) and (c is null) and (d is null) cond4
from test_table
) t
where cond1 or cond2 or cond3 or cond4
order by cond1 desc, cond2 desc, cond3 desc, cond4 desc
limit 1