Sql-Server

SQL Server Order SELECT List with condition

  • May 14, 2018

我想訂購帶有條件的選擇列表。例如; 我有t1桌子,它3 columns6 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,32,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)
)

然後可以(外部)myorderxandy列上加入主查詢:

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 ...構造就足夠了。

引用自:https://dba.stackexchange.com/questions/187862