按键分组并仅返回一个结果行

时间:2012-08-20 14:57:20

标签: sql oracle

我在一个简单的表格中有以下数据:

ID | TYPE
---------
1  | 1
1  | 2
2  | 1
3  | 2
4  | 1
4  | 2
4  | 3
5  | 1
5  | 3
6  | 3

我现在需要以下列方式查询此数据:

  • 对于每个ID,只应返回一行
    • 如果ID只有一行,则返回它。
    • 如果ID有多行,则返回TYPE = 2的行。如果不存在,则返回TYPE = 3的那一行。
  • TYPE可以是1,2或3
  • ID和TYPE具有复合唯一索引,这意味着每个ID最多可以有三行。

问题:如何将此逻辑放入查询中?


预期结果:

ID | TYPE
---------
1  | 2
2  | 1
3  | 2
4  | 2
5  | 3
6  | 3

8 个答案:

答案 0 :(得分:2)

Oracle在所有最新版本中都有分析功能。

WITH
  sequenced AS
(
  SELECT
    *,
    ROW_NUMBER() OVER (PARTITION BY id
                           ORDER BY CASE type WHEN 2 THEN 1
                                              WHEN 3 THEN 2
                                              WHEN 1 THEN 3 END) AS sequenced_id
  FROM
    yourTable
)
SELECT
  *
FROM
  sequenced
WHERE
  sequence_id = 1

使用此技术,您将返回表中的所有值,而不仅仅是PrimaryKey和搜索值。

修改

处理这种情况的最佳方法是让另一个表具有每种类型的首选顺序。

 type | preference_value
------+------------------
  2   |         1
  3   |         2
  1   |         3

这表明2是最优惠的,3是第二优先选择,1是第三优先选择。

因为它是一个如此小的组,所以也可以使用简单的CASE语句来完成。请参阅上面的修改后的查询。

答案 1 :(得分:2)

这是我的看法:http://www.sqlfiddle.com/#!4/9957d/4

select id, 
    case when sum(case when type = 2 then 1 end) = 1 then
       2
    else
       max(type)
    end   
from tbl
group by id
order by id

输出:

| ID | TYPE |
-------------
|  1 |    2 |
|  2 |    1 |
|  3 |    2 |
|  4 |    2 |
|  5 |    3 |
|  6 |    3 |

答案 2 :(得分:2)

另一种方法是最小化CASE WHEN分支:http://www.sqlfiddle.com/#!4/9957d/17

select id, 

    coalesce( sum(case when type=2 then 2 end), max(type) ) as type

from tbl
group by id
order by id

输出:

| ID | TYPE |
-------------
|  1 |    2 |
|  2 |    1 |
|  3 |    2 |
|  4 |    2 |
|  5 |    3 |
|  6 |    3 |

答案 3 :(得分:1)

由于您知道没有TYPE值大于2,您可以这样做:

select ID, max(TYPE) as TYPE
from MyTable
group by ID

答案 4 :(得分:1)

试试这个

select id, type from
(
   select *, ROW_NUMBER() over (partition by id order by abs(2.25-type) ) as rn
   from yourtable
)v
where rn=1

答案 5 :(得分:1)

我会用一点点黑客。

SELECT ID, IF(SUM(TYPE) IN (5, 6), 2, MAX(TYPE)) AS TYPE
FROM table
GROUP BY ID

答案 6 :(得分:1)

享受MOD()功能:

SELECT 
    id,
    MOD(MIN(MOD(type+1,3))+1,3)+1 AS type
FROM
    tableX
GROUP BY
    id ;

答案 7 :(得分:0)

根据podiluska和Dems的建议,我现在正在使用它:

with type_order as
(
    select 1 as type, 0 as prio from dual
    union all
    select 2 as type, 2 as prio from dual
    union all
    select 3 as type, 1 as prio from dual
)
select id, type from 
( 
   select yt.*, ROW_NUMBER() over (partition by id order by o.prio desc) as rn 
   from yourtable yt
   inner join type_order o on yt.type = o.type
)v 
where rn=1 

这是非常有意识的展示和简单的扩展。如果将来会有更多类型,则可以将此type_order内联视图重构为真实表格。