Reputation: 43013
Here is my data:
INT CHAR(2) CHAR(4)
+------+--------------+------------+
| ID | SHORT_CODE | LONG_CODE |
+------+--------------+------------+
| 1 01 0100
| 2 01 0110
| 3 01 0120
| 4 02 0200
| 5 02 0212
| 6 02 0299
| 7 02 0211
I'm looking for a query that will output this result:
+--------------+------------+-------------+
| SHORT_CODE | LONG_CODE | IS_FIRST |
+--------------+------------+-------------+
| 02 0200 false
| 02 0211 true
| 02 0212 false
| 02 0299 false
Here is what I tried
SELECT
short_code,
long_code,
CASE
WHEN long_code LIKE '021%'
THEN 'true'
ELSE 'false'
END as is_first
FROM
MY_TABLE
WHERE
short_code='02'
ORDER BY
long_code ASC;
This query will print also true
for 0212
. I want true
for only the first matching row.
How can I achieve that ?
The sample code in this question is available here.
Oracle 10gR2
Upvotes: 4
Views: 1968
Reputation: 1932
SELECT m.*,
(CASE WHEN b.Id IS NOT NULL THEN 'True' ELSE 'False' END) as First
FROM MY_TABLE m
LEFT JOIN
(
SELECT Id FROM
(
SELECT Id
FROM MY_TABLE
WHERE Long_Code LIKE '021%'
AND Short_Code = '02'
ORDER BY Long_Code
) C
WHERE RowNum = 1
) B
ON b.Id = m.Id
WHERE m.Short_Code = '02';
Upvotes: 0
Reputation: 310993
You could jimmy-rig row_number()
to do this, but it may be a bit cumbersome.
The best idea I could find was to create a pseudo-column prefix
so I could sort all the matching rows first, and then sort by long_code
:
SELECT short_code,
long_code,
CASE row_number() over (order by prefix desc, long_code asc)
WHEN 1 THEN 'true'
ELSE 'false'
END AS is_first
FROM (SELECT short_code,
long_code,
CASE
WHEN long_code LIKE '021%' THEN 1
ELSE 0
END as prefix
FROM my_table
WHERE short_code='02'
)
ORDER BY long_code ASC;
Results also shown in this SQLFiddle.
Upvotes: 1
Reputation: 238048
You can create an extra column is_match
that shows if the row matches the like '021%'
condition. Then you can assign an ascending row number rn
within both the partition of rows that match and the partition of rows that do not match. The row that matches and has row number one is the row you're looking for.
SELECT short_code
, long_code
, CASE
WHEN is_match = 1 and rn = 1 THEN 'true'
ELSE 'false'
END as is_first
FROM (
SELECT short_code
, long_code
, is_match
, row_number() over (
partition by is_match
order by long_code) as rn
FROM (
SELECT short_code
, long_code
, case
when long_code like '%021%' then 1
else 0
end as is_match
FROM MY_TABLE
WHERE short_code = '02'
) s1
) s2
ORDER BY
long_code;
Upvotes: 1