Reputation: 54
I have a query in where I need to return only one row from a table based on a descending order of predicate preference. For Example:
SELECT *
FROM Tbl
WHERE col = 1
OR col = 2
OR col = 3;
In the above scenario, if col = 1, I don't want to return data where col = 2 or 3, only data where col = 1.
If col != 1 but col = 2 or 3, i only want to return data for col = 2 and so on.
Is there an easy way to achieve this? Apologies in advance if the way I have explained this is confusing.
EDIT
To clear up the confusion, please see the following sample data:
With tbl As (
Select 1 As RECORD_ID, 'This is the string I want to return' str, 'FIRST' priority From dual Union All
Select 1, 'This is the string i want to return, if CONDITION1 does not exist', 'SECOND' From dual Union All
Select 1, 'this is the string i will return if i find no others', 'DEFAULT' From dual Union All
Select 2, 'This is the string i want to return, if CONDITION1 does not exist', 'SECOND' From dual Union All
Select 2, 'this is the string i will return if i find no others', 'DEFAULT' From dual
)
Select RECORD_ID,
str
From tbl
Where xxx;
So in the above example, if I queried for RECORD_ID 1 I would want FIRST string returned, and if I queried for RECORD_ID 2, I should get SECOND.
At the moment, all three strings will return.
Upvotes: 1
Views: 341
Reputation: 11581
Depending on the selectivity of each predicate, you may get benefits by separating the query out into individual components, ie,
SQL> select * from
2 ( select x
3 from t1
4 where x = :b1 -- first condition
5 union all
6 select x
7 from t1
8 where y = :b1 -- second condition
9 )
10 where rownum = 1
11 /
If the first query in the UNION ALL finds a row, then we can avoid the second query altogether.
You can find a worked example proving the "short circuit" processing here
https://connor-mcdonald.com/2016/03/14/the-first-matching-row/
Upvotes: 0
Reputation: 1269633
One method uses ordering:
select t.*
from (select t.*
from t
where col in (1, 2, 3)
order by (case col when 1 then 1 when 2 then 2 when 3 then 3 end)
) t
where rownum = 1;
Obviously, in your case, the order by
could be order by col
, but the general situation is to use case
.
Upvotes: 1
Reputation: 17915
A standard and common way of doing this is with ROW_NUMBER()
. Oracle ROWNUM
is not portable:
WITH data AS (
SELECT t.*, ROW_NUMBER() OVER (ORDER BY LENGTH(priority)) AS rn
FROM Tbl t WHERE col in (1, 2, 3)
)
SELECT * FROM data WHERE rn = 1;
Here's are other variations, essentially identical, that use min()
instead. EDIT: With updated requirements these would tweaks to get the correct ordering but in principle they could still work.
SELECT * FROM Tbl
WHERE col = (SELECT MIN(col) FROM Tbl);
More like the first one:
WITH data AS (
SELECT t.*, MIN(col) OVER () AS mn
FROM Tbl t WHERE col in (1, 2, 3)
)
SELECT * FROM data WHERE col = mn;
You might want to look at the query plans to determine which one is the best for you although I suspect your table only has a few rows.
Upvotes: 0
Reputation: 132570
You could try:
SELECT t1.*
FROM Tbl t1
WHERE t1.col in (1,2,3)
ORDER BY t1.col
FETCH FIRST 1 ROWS ONLY;
Upvotes: 0