2013-04-18 51 views
2

我正在尋找最簡單的方法來返回分組的select語句的多個列結果中最常見的值。我在網上找到的所有東西都指向RANK中選擇的單個項目,或者在GROUP BY之外單獨處理每個列。SQL函數返回一個組中多個列的「最常見值」按

樣本數據:

SELECT 100 as "auser", 
'A' as "instance1", 'M' as "instance2" 
union all select 100, 'B', 'M' 
union all select 100,'C', 'N' 
union all select 100, 'B', 'O' 
union all select 200,'D', 'P' 
union all select 200, 'E', 'P' 
union all select 200,'F', 'P' 
union all select 200, 'F', 'Q' 

樣本數據結果:

auser instance1 instance2 
100  A   M 
100  B   M 
100  C   N 
100  B   O 
200  D   P 
200  E   P 
200  F   P 
200  F   Q 

查詢邏輯(我看到它在我的頭上):

SELECT auser, most_common(instance1), most_common(instance2) 
FROM datasample 
GROUP BY auser; 

期望的結果:

100  B   M 
200  F   P 
+2

使用 –

+0

如果什麼有一搭請註明您的RDBMS? –

+0

SQL Server。如果有領帶,我想用MIN()包裝它,但是我想看看這是否可能首先。 –

回答

3

解決此問題的方法使用了嵌套窗口函數。最裏面的子查詢計算每列的計數。下一個子查詢將這些排序(使用row_number())。外部查詢然後使用條件聚合得到你想要的結果:

select auser, MAX(case when seqnum1 = 1 then instance1 end), 
     MAX(case when seqnum2 = 1 then instance2 end) 
from (select t.*, 
      ROW_NUMBER() over (partition by auser order by cnt1 desc) as seqnum1, 
      ROW_NUMBER() over (partition by auser order by cnt2 desc) as seqnum2 
     from (select t.*, 
        count(*) over (partition by auser, instance1) as cnt1, 
        COUNT(*) over (partition by auser, instance2) as cnt2 
      from t 
      ) t 
    ) t 
group by auser 
+0

+1 ...頭髮也快。 –

+0

任何想法如何在Sqlite上做到這一點?我得到一個'SQL邏輯錯誤或數據庫附近缺少'(「:syntax error' – Tyson

+0

@Tyson ... SQLite不支持與SQL Server相同的功能集,您可以提出另一個問題,標記SQLite來解決 –

1

我不知道如果我能找到的東西更優雅,但如果你在SQL這可能做2005+(因爲我使用ranking functionCTEs):

with instance1 as (
    select auser, instance1 
     , row_number() over (partition by auser order by count(*) desc, instance1) as row_num 
    from datasample 
    group by auser, instance1 
), instance2 as (
    select auser, instance2 
     , row_number() over (partition by auser order by count(*) desc, instance2) as row_num 
    from datasample 
    group by auser, instance2 
) 
select a.auser, a.instance1, b.instance2 
from instance1 as a 
    join instance2 as b on a.auser = b.auser 
where a.row_num = 1 
    and b.row_num = 1 
order by a.auser; 

我m不知道你希望如何處理空值,並且將row_num等同性移動到連接條件不會更改我的框中的執行計劃。

如果您使用的是SQL Server 2000,那麼可以使用count和"triangular join"來替換這些帶有派生表的CTE,並僞造row_number()。

+0

是的,希望能有更優雅的東西,就像你說的那樣。我簡化了我的實際工作。 「auser」實際上是一組大約10列的組,考慮到這個問題,所以這就增加了難度(每個用戶在這裏都會列出大約10個項目)。此外,我的數據示例實際上是50行查詢的結果。這就是爲什麼我希望得到一個簡單的嵌套函數類型解決方案,但我不認爲這會發生在這裏。 –

+0

@FreshPrinceOfSO謝謝你是唯一拒絕不必要的代碼格式編輯的人。 –