針對distinct疑問引發的一系列思考

2022-09-21 23:27:12 字數 1778 閱讀 6882

假設有如下這樣一張**:

這裡的資料,具有如下的特徵:在乙個departmentid中,可能會有多個name,反之也是一樣。就是說name和departmentid是多對多的關係。

現在想實現這樣乙個查詢:按照departmentid排完序之後(第一步),再獲取name列的不重複值(第二步),而且要保留在第一步後的相對順序。以本例而言,應該返回三個值依次是:acb

我們hyvve首先會想到下面這樣乙個寫法

select distinct name from shyvveample order by departmentid

從語義上說,這是很自然的。但是很可惜,這個語句根本無法執行,錯誤訊息是:

這個錯誤的意思是,如果使用了distinct(去重複值),則出現在orderby後面的字段,必須也出現在select後面,但如果departmentid如果也真的出現在select後面,顯然是不會有重複值的,所以結果肯定也是不對的。

select distinct name,departmentid from sample order by departmentid

那麼,既然disinct 與orderby結合起來用會有這個的乙個問題,我們是否有可能變通一下,例如下面這樣:

select distinct a.name

from (select top 100 percent name from sample order by departmentid) a

想比較之前的寫法,我們用到了子查詢技術。同樣從語義上看,仍熱是很直觀明了的。我想先按照departmentid進行排序, 然後再去重複值。但是返回到結果是下面這樣的:

雖然確實去除了重複值,但返回的順序卻是不對的。我們希望是先按照departmentid排序之後,然後去除重複值,並且保留排序後的相對順序。

為什麼會出現上面這個結果呢?其實是因為distinct本身是會做排序的,而且這個行為是無法更改的(下圖的執行計畫中可以看到這一點)。所以其實我們之前做的order by在這裡會失去意義。【實際上,如果觀察ado.net entity framework等orm工具中生成的類似的乙個查詢,它會自動丟棄order by的設定】

那麼,這樣的情況下,是不是就不可能實現需求了呢?雖然說,這個需求並不多見,絕大部分時候,distinct作為最後乙個操作,做一次排序是合乎情理的。

我是這樣考慮到,既然distinct的這個程式設計客棧行為是內建的,那麼是否可以繞過這個操作呢?最終我用的乙個解決方案是:我能不能把每個name都編上乙個編號,例如有兩個a的話,第乙個a我為它編號為1,第二個編號為2,以此類推。然後,查詢的時候,我先排程式設計客棧序,然後篩選那些編號為1的name,這樣其實也就實現了去重複值了。

sql server 2005開始提供了乙個row_number的功能,結合這個功能,我實現了下面這樣的查詢:

select a.name from

(select top 100 percent

name,departmentid,row_number() over(partition by name order by departmentid) row

from sample order by departmentid) a

where a.row=1

order by a.departmentid

然後,我得到了下面這樣的結果,我推敲下來,這應該是符合了之前提到的這個需求的

相比較而言,這個查詢的效率會低一些,這個是可以預見的(可以通過下圖看出一點端倪)。但如果需求是硬性的,那麼犧牲一些效能也是不奇怪的。當然,我們可以再研究看看程式設計客棧是否有更優的一些寫法。無論如何,使用內建標準的實現,通常都是相對較快的。

Hive針對distinct的優化 二

之前一篇針對單個count distinct 的優化,本文來講講對多個count distinct 的優化。優化是在之前單個count的基礎上,通過使用union all以及視窗分析函式lag的結合來進行的。具體思路如下。select pid,c1,c2 from select pid,c1,lag...

乙個distinct問題引發的記錄

今天被人問到這樣乙個問題,整理出來給大家也參考一下 假設有如下這樣一張 這裡的資料,具有如下的特徵 在乙個departmentid中,可能會有多個name,反之也是一樣。就是說name和departmentid是多對多的關係。現在想實現這樣乙個查詢 按照departmentid排完序之後 第一步 再...

匿名物件的Distinct

在使用linq distinct集合的時候,匿名物件和非匿名物件的區別非常有趣。匿名物件自動實現了gethashcode和equals方法,distinct可以自動去重。如果使用非匿名物件,則需要該類override gethashcode 和equals object obj 方法,或者新增乙個實...