SQL Server Order SELECT List with condition
我想訂購帶有條件的選擇列表。例如; 我有
t1
桌子,它3 columns
有6 rows
Table t1: +----+---+---+ | id | x | y | +----+---+---+ | 1 | a | 1 | | 2 | b | 3 | | 3 | c | 2 | | 4 | d | 2 | | 5 | e | 1 | | 6 | f | 3 | +----+---+---+
無條件排序選擇列表,選擇查詢很容易:
SELECT y FROM t1 ORDER BY y
結果:1,1,2,2,3,3
SELECT y FROM t1 ORDER BY y DESC
結果:3,3,2,2,1,1
如果我想要那個結果
2,2,1,1,3,3
,2,2,3,3,1,1
我該如何使用選擇查詢或 c# 實體框架來做到這一點?
對於僅基於一個 ‘y=2’ 值(根據評論)的簡單解決方案,建議的
order by case ...
構造就足夠了。但是,如果要求能夠按不同數量的“y”值排序,或者可能按列組合排序……
想到的一個想法……使用表值建構子(TVC)來建構您想要的排序順序的“內聯”表;然後,我們將把這個 TVC 連接回您的原始數據集,以提供所需的排序順序。
我們將從創建表並填充一些範例數據開始:
drop table if exists t1; create table t1 (id int ,x varchar(30) ,y int); insert into t1 (id,x,y) values (1,'a',1), (2,'b',3), (3,'c',2), (4,'d',2), (5,'e',1), (6,'f',3);
對於我們的 TVC,我們將生成一個名為的單列派生表
dt(y)
,其中包括按y
所需排序順序列出的值。我們將添加row_number()
函式來提供我們實際訂購的列。最後,為了便於參考,我們將所有這些都包含在一個公共表表達式 (CTE) 中。-- order by 'y' values 2, 1, 3: with myorder as (select row_number() over (order by (select 1)) orderid, y from (values (2),(1),(3) ) as dt(y) -- desired sort order is 2, 1, 3 ) select * from myorder order by orderid; orderid | y ------- | -- 1 | 2 2 | 1 3 | 3 -- order by 'y' values 2, 3, 1: with myorder as (select row_number() over (order by (select 1)) orderid, y from (values (2),(3),(1) ) as dt(y) -- desired sort order is 2, 3, 1 ) select * from myorder order by orderid; orderid | y ------- | -- 1 | 2 2 | 3 3 | 1
我們現在可以將我們的 TVC 與原始數據集(
t1
在本例中為表)連接以生成所需的排序順序:-- sort solely on the TVC's 'y' column: with myorder as (select row_number() over (order by (select 1)) orderid, y from (values (2),(3),(1) ) as dt(y) ) select t1.id, t1.x, t1.y from t1 join myorder mo on mo.y = t1.y order by mo.orderid; id | x | y -- | -- | -- 3 | c | 2 4 | d | 2 2 | b | 3 6 | f | 3 1 | a | 1 5 | e | 1 -- sort by TVC's 'y' column (ascending order), then by t1's 'x' column (descending order): with myorder as (select row_number() over (order by (select 1)) orderid, y from (values (2),(3),(1) ) as dt(y) ) select t1.id, t1.x, t1.y from t1 join myorder mo on mo.y = t1.y order by mo.orderid, t1.x desc id | x | y -- | -- | -- 4 | d | 2 3 | c | 2 6 | f | 3 2 | b | 3 5 | e | 1 1 | a | 1
要記住的關鍵事項是確保 TVC 的記錄按與所需排序順序匹配的順序列出。
一個潛在的問題是,如果你不知道你有多少個 ‘y’ 值,或者你只需要按少數已知的 ‘y’ 值排序(並且不關心其他 ‘y’ 值的排序), 你可以:
- 將 TVC 限制為您感興趣的那些“y”值,並且…
- 通過外部連接將主數據集連接到 TVC 並…
- 然後將缺少的 TVC 的“orderid”列預設為足夠大的數字,以確保它們在排序順序中的位置不會影響感興趣的“y”值
例如,假設我們希望首先列出 ‘y=2’ 值,並且我們不關心其餘的 ‘y’ 值:
with myorder as (select row_number() over (order by (select 1)) orderid, y from (values (2) ) as dt(y) -- only interested in 'y=2' records ) select t1.id, t1.x, t1.y from t1 -- left join w/ TVC/CTE left join myorder mo on mo.y = t1.y order by isnull(mo.orderid, 100), -- default missing TVC.orderid's to 100 t1.x desc id | x | y -- | -- | -- 4 | d | 2 -- 'y=2' records show up 3 | c | 2 -- first in our output 6 | f | 3 -- while we let the database engine 5 | e | 1 -- determine the order of the rest 2 | b | 3 -- of the result set; granted, for this 1 | a | 1 -- example we also had 't1.x desc'
顯然,您仍然可以在“order by”子句中添加其他列來影響最終排序。
這是上述所有內容的dbfiddle。
雖然範例查詢(上面)基於對“y”列的排序順序進行硬編碼,但可以擴展此方法以允許對任何列組合的排序順序進行硬編碼。
例如,假設您想要基於 ‘y=2’ 和 ‘x in (‘a’,‘b’,‘c’)’ 的硬編碼排序順序,CTE/TVC 如下所示:
with myorder as (select row_number() over (order by (select 1)) orderid, x y from (values (2,'a'),(2,'b'),(2,'c') ) as dt(x,y) )
然後可以(外部)
myorder
在x
andy
列上加入主查詢:with myorder as(...) select ... from t1 left join myorder mo on mo.x = t1.x and mo.y = t1.y order by isnull(mo.orderid, 100);
同樣,如果您不需要靈活性,那麼更簡單的
order by case ...
構造就足夠了。