在select语句中分类

时间:2016-09-19 06:33:02

标签: sql oracle group-by case categories

所以我有这张桌子

id     |   object    |     type
--------------------------------
1      |   blue      |     color
1      |   burger    |     food
2      |   sandwich  |     food
2      |   red       |     color
2      |   coke      |     beverage 
3      |   sprite    |     beverage
3      |   coke      |     beverage
3      |   red       |     color
4      |   bacon     |     food

我必须创建一个select语句,它将显示一个包含id,color,food和beverage列的表。由身份证安排,并附上指定的东西。

所以我的预期结果是

id       |   color   |   food   |  beverage
-------------------------------------------
1        |   blue    |   burger |
2        |   red     | sandwich |   coke
3        |   red     |          |   sprite
3        |           |          |   coke
4        |           |  bacon   |

截至目前我有这段代码

Select id as id,
Case When I.Type = 'color' Then I.Object End As color, 
Case When I.Type = 'food' Then I.Object End As food, 
Case When I.Type = 'beverage' Then I.Object End As beverage
From table I
order by id

但我的代码问题是它没有按ID分组,所以它为每个对象创建了多行。

TIA!

4 个答案:

答案 0 :(得分:1)

您正在寻找透视查询。对您的问题有挑战性的是,对于给定的id type,可能会有多个object存在。要处理此问题,您可以先使用GROUP BY对给定类型的CSV聚合对象进行LISTAGG查询:

SELECT id,
       MAX(CASE WHEN t.type = 'color'    THEN t.object ELSE NULL END) AS color,
       MAX(CASE WHEN t.type = 'food'     THEN t.object ELSE NULL END) AS food,
       MAX(CASE WHEN t.type = 'beverage' THEN t.object ELSE NULL END) AS beverage
FROM
(
    SELECT id,
           LISTAGG(object, ',') WITHIN GROUP (ORDER BY object) AS object,
           type
    FROM yourTable
    GROUP BY id, type
) t
GROUP BY t.id

内部查询首先聚合id type中的对象,外部查询是您可能期望的简单数据透视查询。

这是一个小提琴,在MySQL中显示几乎相同的查询(Oracle似乎永远被打破):

SQLFiddle

答案 1 :(得分:1)

您可以尝试使用以下内容:

with test(id, object, type) as
(
    select 1,'blue',    'color' from dual union all
    select 1,'burger',  'food' from dual union all
    select 2,'sandwich','food' from dual union all
    select 2,'red',     'color' from dual union all
    select 2,'coke',    'beverage' from dual union all 
    select 3,'sprite',  'beverage' from dual union all
    select 3,'coke',    'beverage' from dual union all
    select 3,'red',     'color' from dual union all
    select 4,'bacon',   'food' from dual
)
select id,
       max( case when type = 'color'    
              then object
              else null
            end
          ) as color,
       max( case when type = 'food'    
              then object
              else null
            end
          ) as food,
       max( case when type = 'beverage'    
              then object
              else null
            end
          ) as beverage
from (
        select id, object, type, row_number() over ( partition by id, type order by object) row_for_id
        from test
     )
group by id, row_for_id   
order by id, row_for_id

内部查询是主要部分,您可以在其中处理具有许多类型对象的单个id的情况;您可以通过编辑order by object来修改排序。 外部查询可以以不同的方式重写,例如使用PIVOT;我使用MAX希望明确表达。

答案 2 :(得分:0)

试试这个

我已经使用pivot子句

select id,object,type from yourtable
pivot
(
     LISTAGG(object, ',') WITHIN GROUP (ORDER BY object)
     for type IN
               (
                  'color'  AS "color",
                  'food'   AS "food",
                  'beverage' AS "beverage"
               )
)
order by id

答案 3 :(得分:0)

罗宾:我对你的评论(在Tim Biegeleisen的回答下)是不正确的。有一个基于枢轴的解决方案;但是,“群组”不是通过ID,而是通过ID和等级在您的三个“类别”中。对于此解决方案(或不使用动态SQL的任何解决方案),必须预先知道所有“类型”(及其名称),并且必须在SQL查询中对其进行硬编码。

注意:在此解决方案中,我假设对于每个id,同一“类型”中的“对象”基于其字母顺序彼此关联(例如,对于id = 3,“coke”与“red”关联,“sprite”与NULL关联,与示例输出不同)。我在你的问题下面问过你 - 如果你没有与我们分享其他规则,要求不同类型的对象配对,则可能会或可能不会调整解决方案以满足这些附加规则。 / p>

编辑:仔细看看,这几乎是Aleksej提供的内容,而不使用显式的pivot语法。他的解决方案的优势在于它可以在旧版本的Oracle中使用(在11.1之前pivot首次可用)。

QUERY(包括第一次CTE中的测试数据):

with
     inputs ( id, object, type ) as (
       select 1, 'blue'     , 'color'    from dual union all
       select 1, 'burger'   , 'food'     from dual union all
       select 2, 'sandwich' , 'food'     from dual union all
       select 2, 'red'      , 'color'    from dual union all
       select 2, 'coke'     , 'beverage' from dual union all
       select 3, 'sprite'   , 'beverage' from dual union all
       select 3, 'coke'     , 'beverage' from dual union all
       select 3, 'red'      , 'color'    from dual union all
       select 4, 'bacon'    , 'food'     from dual 
     ),
     r ( id, object, type, rn ) as (
       select id, object, type, row_number() over (partition by id, type order by object)
       from   inputs
     )
select id, color, food, beverage
from   r
  pivot ( max(object) for type in ( 'color'    as color, 'food' as food, 
                                    'beverage' as beverage))
order by id, rn
;

输出:

  ID COLOR    FOOD     BEVERAGE
---- -------- -------- --------
   1 blue     burger
   2 red      sandwich coke
   3 red               coke
   3                   sprite
   4          bacon