I guess this is a long shot but, is there a way to list the sql query without sorting...
eg. I have
select * from items
where manufacID = 2
or manufacID = 1
or manufacID = 4
and I don't want them to be listed in the asc or decs order, but as i typed in... so 2,1,4.
So, can i do that?
You could add an extra column in the select as your sort column then order by that:
SELECT
*,
CASE manufacID
WHEN 2 THEN 1
WHEN 1 THEN 2
WHEN 4 THEN 3
END AS sortOrder
FROM
items
ORDER BY
sortOrder
Yes, use this:
SELECT * FROM items
WHERE manufacID IN (2, 1, 4)
ORDER BY (manufacID = 2) ASC,
(manufacID = 1) ASC,
(manufacID = 4) ASC
The results are sorted in the order that the conditions match. Change ASC to DESC to reverse the order. This only works on databases which allow conditions in the sort clauses.
(Side note: why would you want to do this?)
As you haven't specified the sorting, the records will be sorted in the natural order, which depends on the RDBMS you are using. In SQL Server for example the order is undefined.
You can create a value to order by from the values:
select * from items
where manufacID in (2, 1, 4)
order by case manufacID
when 2 then 1
when 1 then 2
when 4 then 3
end
SELECT * FROM
(
select 1 as sort, * from items
where manufacID = 2
union all
select 2 as sort, * from items
where manufacID = 1
union all
select 3 as sort, * from items
where manufacID = 4
)
order by sort
select * from items where manufacID = 2
union all
select * from items where manufacID = 1
union all
select * from items where manufacID = 4
Related
Let's say I am returning the following table from a select
CaseId
DocId
DocumentTypeId
DocumentType
ExpirationDate
1
1
1
I797
01/02/23
1
2
2
I94
01/02/23
1
3
3
Some Other Value
01/02/23
I want to select ONLY the row with DocumentType = 'I797', then if there is no 'I797', I want to select ONLY the row where DocumentType = 'I94'; failing to find either of those two I want to take all rows with any other value of DocumentType.
Using SQL Server ideally.
I think I'm looking for an XOR clause but can't work out how to do that in SQL Server or to get all other values.
Similar to #siggemannen answer
select top 1 with ties
case when DocumentType='I797' then 1
when DocumentType='I94' then 2
else 3
end gr
,docs.*
from docs
order by
case when DocumentType='I797' then 1
when DocumentType='I94' then 2
else 3
end
Shortest:
select top 1 with ties
docs.*
from docs
order by
case when DocumentType='I797' then 1
when DocumentType='I94' then 2
else 3
end
Something like this perhaps:
select *
from (
select t.*, DENSE_RANK() OVER(ORDER BY CASE WHEN DocumentType = 'I797' THEN 0 WHEN DocumentType = 'I94' THEN 1 ELSE 2 END) AS prioorder
from
(
VALUES
(1, 1, 1, N'I797', N'01/02/23')
, (1, 2, 2, N'I94', N'01/02/23')
, (1, 3, 3, N'Some Other Value', N'01/02/23')
, (1, 4, 3, N'Super Sekret', N'01/02/23')
) t (CaseId,DocId,DocumentTypeId,DocumentType,ExpirationDate)
) x
WHERE x.prioorder = 1
The idea is to rank rows by 1, 2, 3 depending on document type. Since we rank "the rest" the same, you will get all rows if I797 and I94 is missing.
select * from YourTable where DocumentType = 'I797'
union
select * from YourTable t where DocumentType = 'I94' and (not exists (select * from YourTable where DocumentType = 'I797'))
union
select * from YourTable t where (not exists (select * from YourTable where DocumentType = 'I797' or DocumentType = 'I94' ))
I have this data:
parent_id
comment_id
comment_level
NULL
0xB2
1
NULL
0xB6
1
NULL
0xBA
1
NULL
0xBE
1
NULL
0xC110
1
NULL
0xC130
1
123
0xC13580
2
456
0xC135AC
3
123
0xC13680
2
I want the result in such a way that rows where comment_level=1 should be in descending order by comment_id and other rows(i.e. where comment_level!=1) should be in ascending order by comment_id but the order of comment level greater than 1 should be inserted according to to order of comment level 1 (what I mean is that rows with comment_level=1 should remain in descending order and then rows with comment_level!=1 should be inserted in increasing order but it should be inserted following rows where comment_id is less than it)
Result should look like this
NULL 0xC130 1
123 0xC13580 2
456 0xC135AC 3
123 0xC13680 2
NULL 0xC110 1
NULL 0xBE 1
NULL 0xBA 1
NULL 0xB6 1
NULL 0xB2 1
Note the bold rows in above sort by comment_id in ascending order, but they come after their "main" row (with comment_level = 1), where these main rows sort DESC by comment_id.
I tried creating 2 tables for different comment level and used sorting for union but it didn't work out because 2 different order by doesn't work maybe I tried from this Using different order by with union but it gave me an error and after all even if this worked it still might not have given me the whole answer.
I think I understand what you're going for, and a UNION will not be able to do it.
To accomplish this, each row needs to match with a specific "parent" row that does have 1 for the comment_level. If the comment_level is already 1, the row is its own parent. Then we can sort first by the comment_id from that parent record DESC, and then sort ascending by the local comment_id within the a given group of matching parent records.
You'll need something like this:
SELECT t0.*
FROM [MyTable] t0
CROSS APPLY (
SELECT TOP 1 comment_id
FROM [MyTable] t1
WHERE t1.comment_level = 1 AND t1.comment_id <= t0.comment_id
ORDER BY t1.comment_id DESC
) parents
ORDER BY parents.comment_id DESC,
case when t0.comment_level = 1 then 0 else 1 end,
t0.comment_id
See it work here:
https://dbfiddle.uk/qZBb3YjO
There's probably also a solution using a windowing function that will be more efficient.
And here it is:
SELECT parent_id, comment_id, comment_level
FROM (
SELECT t0.*, t1.comment_id as t1_comment_id
, row_number() OVER (PARTITION BY t0.comment_id ORDER BY t1.comment_id desc) rn
FROM [MyTable] t0
LEFT JOIN [MyTable] t1 ON t1.comment_level = 1 and t1.comment_id <= t0.comment_id
) d
WHERE rn = 1
ORDER BY t1_comment_id DESC,
case when comment_level = 1 then 0 else 1 end,
comment_id
See it here:
https://dbfiddle.uk/me1vGNdM
Those varbinary values aren't arbitrary, they're hierarchyid values. And just a guess, they're probably typed that way in the schema (it's too much to be a coincidence). We can use this fact to do what we're looking to do.
with d_raw as (
select * from (values
(NULL, 0xC130 , 1),
(123 , 0xC13580, 2),
(456 , 0xC135AC, 3),
(123 , 0xC13680, 2),
(NULL, 0xC110 , 1),
(NULL, 0xBE , 1),
(NULL, 0xBA , 1),
(NULL, 0xB6 , 1),
(NULL, 0xB2 , 1)
) as x(parent_id, comment_id, comment_level)
),
d as (
select parent_id, comment_id = cast(comment_id as hierarchyid), comment_level
from d_raw
)
select *,
comment_id.ToString(),
comment_id.GetAncestor(comment_id.GetLevel() - 1).ToString()
from d
order by comment_id.GetAncestor(comment_id.GetLevel() - 1) desc,
comment_id
Note - the CTEs that I'm using are just to get the data into the right format and the last SELECT adds additional columns just to show what's going on; you can omit them from your query without consequence. I think the only interesting part of this solution is using comment_id.GetAncestor(comment_id.GetLevel() - 1) to get the root-level node.
One way to do this and possibly the only one is create two separate queries and union them together. Something like:
(select * from table where comment_level = 1 order by comment_id desc)
union
(select * from table where not comment_level = 1 order by comment_id asc)
I have this query
select name,
surname,
age
from user
order by idcard asc
but I want that if idcard has values 3 those values to be shown together in the end of the list while the rest 1, 2, 4, 5, 6, to order by asc
is it possible to do?
You can try using case:
select ...
order by case
when idcard = 3 then 1
else 0
end,
idcard
I want to get the price of an article for a specific customer.
There are several levels of prices which i ranked in my query.
So Article A has a price on rank 1, 4, 6. The result should always be the lowest ranked price.
Article B rank 3 ,5
So article A price is ranked 1 and Article b is price ranked 3.
My query is below .
SELECT p2.* FROM(
SElect ART_ID, MIN(RANG) RANG FROM (
Select p.ART_ID, p.betrag ,
CASE p.PREIS_EBENE WHEN 'KA' THEN 1 WHEN 'KW' THEN 2 WHEN 'W' THEN 7 WHEN 'A' THEN 6 ELSE 99 END RANG
FROM MDART a
INNER JOIN MDPRSVK p ON (a.KLIENT_ID = p.KLIENT_ID AND a.ART_ID = p.ART_ID)
WHERE ICP_KZ.IS_SET(KENNUNG_USER, 'P') = 1
ORDER BY RANG)
GROUP BY ART_ID) T
INNER JOIN MDPRSVK p2 ON (p2.ART_ID = T.ART_ID AND p2.PREIS_EBENE = p.PREIS_EBENE)
i want to have every article appearing only once in the result
You have tagged your request PL/SQL, so I guess your DBMS may be Oracle.
If I understand correctly, the table MDPRSVK contains several prices per ART_ID. And you want to select each ART_ID's best price (best to worst: 'KA' -> 'KW' -> 'A' -> 'W' -> any other PREIS_EBENE).
You can use a window function (ROW_NUMBER, RANK or DENSE_RANK) for this:
select *
from mdprsvk
order by row_number()
over (partition by art_id
order by decode(preis_ebene, 'KA', 1, 'KW', 2, 'A', 3, 'W', 4, 5))
fetch first row with ties;
This is standard SQL. In Oracle, FETCH FIRST is available as of version 12c. In earlier versions you'd use a subquery instead:
select *
from
(
select
mdprsvk.*,
row_number() over (partition by art_id
order by decode(preis_ebene, 'KA', 1, 'KW', 2, 'A', 3, 'W', 4, 5))
as rn
from mdprsvk
)
where rn = 1;
Or use OraclesKEEP FIRST`:
select art_id, max(betrag)
keep (dense_rank first
order by decode(preis_ebene, 'KA', 1, 'KW', 2, 'A', 3, 'W', 4, 5))
from mdprsvk
group by art_id;
It is not clear, how MDART comes into play. It looks like you want to restrict your results to articles for certain clients and KENNUNG_USER is the column in MDART to check. If so, add a WHERE clause:
where exists
(
select *
from mdart
where mdart.klient_id = mdprsvk.klient_id
and mdart.art_id = mdprsvk.art_id
and icp_kz.is_set(mdart.kennung_user, 'p') = 1
)
Or with IN instead of EXISTS:
where (klient_id, art_id) in
(
select klient_id, art_id
from mdart
where icp_kz.is_set(kennung_user, 'p') = 1
)
I want the server to give me the results of a query in the order I send it.
So if I write:
SELECT * FROM table WHERE column in (9,1,8)
I would like it to give me the results in the order: 9,1,8
One method uses left join:
select t.*
from (select 9 as c, 1 as priority union all select 1, 2 union all select 8, 3
) vals left join
table t
on t.column = vals.c
order by vals.priority;
Note: This is generic syntax. The specific syntax for the subquery may differ depending on the database.
Another method uses case in the order by:
select t.*
from table t
where t.column in (9, 1, 8)
order by (case column when 9 then 1 when 1 then 2 when 8 then 3 end);
Once again, this can be simplified in some databases, say by using special functions.
You could use CASE expression in order you want, something like:
select *
from table_name
where column_name in (9,1,8)
order by case column_name
when 9 then 1
when 1 then 2
when 8 then 3 end
, column_name -- optional, but here could go another column if you want to have custom order
You can do in Oracle SQL if you have
SELECT Column_name
FROM user_tab_columns
where table_name = 'MY_TABLE'
and Column_id in (9,1,8)
SELECT *
FROM table
WHERE column IN (9, 1, 8)
ORDER BY CASE WHEN column = 9 THEN 1
WHEN column = 1 THEN 2
WHEN column = 8 THEN 3
END