Reputation: 8276
I have to query specific order of string IDs example data:
| ID | RES |
---------------
| A_12 | 1.89 |
| B_27 | 4.53 |
| B_28 | 1.02 |
| C_23 | 2.67 |
A tool generated a specific order which does not follow any standard ordering rule, and I cannot change that order. I am getting ~20000 of these rows and the RES is misaligned. I'd like to make a simple query which would collect all needed records by a list IDs and would give me a custom defined ordered list of results.
Something like:
SELECT RES FROM TABLE1 WHERE ID IN ('A_12', 'C_23', 'B_28', 'B_27')
and I'd lke it to return
1.89
2.67
1.02
4.53
I understand IN
query would not follow order as under the hood it most likely gets translated to (ID = A OR ID = B OR ID = C)
query.
How do I enforce the result of the IN query to maintain my defined order? Do I need to create a temp table with one column for maintaining order? Any good solutions?
Upvotes: 2
Views: 1912
Reputation: 772
Just a different approach:
SELECT RES FROM TABLE1 WHERE ID IN ('A_12')
UNION ALL
SELECT RES FROM TABLE1 WHERE ID IN ('C_23')
UNION ALL
SELECT RES FROM TABLE1 WHERE ID IN ('B_28')
UNION ALL
SELECT RES FROM TABLE1 WHERE ID IN ('B_27')
I supposed that the JOIN
option is more efficent than this approach. If you want to automatize this option:
DROP TABLE #TABLE1
CREATE TABLE #TABLE1(ID NVARCHAR(4), RES FLOAT)
INSERT INTO #TABLE1 VALUES('A_12',1.89)
INSERT INTO #TABLE1 VALUES('B_27',4.53)
INSERT INTO #TABLE1 VALUES('B_28',1.02)
INSERT INTO #TABLE1 VALUES('C_23',2.67)
DECLARE @ID TABLE(ID NVARCHAR(4) not null);
--HERE HAVE TO INSERT IN ORDER YOU WANT TO RETURN THE RESULTS IN THE QUERY
insert into @ID VALUES('A_12')
insert into @ID VALUES('B_27')
insert into @ID VALUES('B_28')
insert into @ID VALUES('C_23')
DECLARE @UNIONALL NVARCHAR(10) = CHAR(13) + N'UNION ALL'
DECLARE @QUERY NVARCHAR(MAX) = NULL
DECLARE @ID_SEARCH NVARCHAR(4) = NULL
DECLARE C CURSOR FAST_FORWARD FOR SELECT ID FROM @ID
OPEN C
FETCH NEXT FROM C INTO @ID_SEARCH
SET @QUERY = N'SELECT RES FROM #TABLE1 WHERE ID = ''' + @ID_SEARCH + ''' '
FETCH NEXT FROM C INTO @ID_SEARCH
WHILE @@FETCH_STATUS = 0 BEGIN
SET @QUERY = @QUERY + @UNIONALL
SET @QUERY = @QUERY + N' SELECT RES FROM #TABLE1 WHERE ID = ''' + @ID_SEARCH + ''' '
FETCH NEXT FROM C INTO @ID_SEARCH
END
EXECUTE master..sp_executesql @QUERY
Upvotes: 0
Reputation: 8687
Instead of temp table you can use values
where you specify the desired order in the additional column, like this:
declare @table1 table(id varchar(10), res decimal(10,2));
insert into @table1 (id, res)
values
('A_12', 1.89),
('B_27', 4.53),
('B_28', 3.54),
('C_23', 2.67);
select t.*
from @table1 t
join (values(1, 'A_12'), (2, 'C_23'), (3, 'B_28'), (4, 'B_27')) v(id,val)
on t.id = v.val
order by v.id;
@Table1
here is a substitute of your physical Table1
.
Upvotes: 3
Reputation: 2191
Use JOIN
instead of using IN
and explicitly specify your order:
DECLARE @Test TABLE (
ID VARCHAR(32),
RES DECIMAL(5,2)
)
INSERT @Test (ID, RES)
VALUES
('A_12', 1.89),
('B_27', 4.53),
('B_28', 3.54),
('C_23', 2.67)
SELECT t.ID, t.RES
FROM @Test t
JOIN (
VALUES
('A_12', 1),
('C_23', 2),
('B_28', 3),
('B_27', 4)
) o(ID, OrderId) ON t.ID = o.ID
ORDER BY o.OrderId
Upvotes: 3
Reputation: 8276
Do I need to create a temp table with one column for maintaining order
This seems to be working:
create table #tmp
(
CustomOrder int,
ID varchar(100)
)
insert into #tmp values (1, 'A_12')
insert into #tmp values (2, 'C_23')
insert into #tmp values (3, 'B_28')
insert into #tmp values (4, 'B_27')
query:
SELECT RES FROM TABLE1 INNER JOIN #tmp ON TABLE1.ID = #tmp.ID WHERE TABLE1.ID IN ('A_12', 'C_23', 'B_28', 'B_27')
ORDER BY #tmp.CustomOrder
output:
1.89
2.67
1.02
4.53
Any better and easier solution?
Upvotes: 0
Reputation: 62157
There is no order to keep.
Returns of a select are NOT ORDERED by SQL basic definition, UNLESS YOU DEFINE AN ORDER.
So, there is no order to keep. Period.
If you want to keep one, use a temporary table / table variable for the valeus in IN (and obviously a join) and order by an order you also keep in a second field in said variable.
And no, this is not new - SQL is based on the SET theorem ever since Cobb published his famous paper back in the 1960s or so and never had order in returned results outside of side effects of implementation.
Upvotes: 1