在LISTAGG操作期间使用LIKE的CASE语句

时间:2017-04-10 14:41:45

标签: sql oracle sql-like listagg

+-----------+------------+-----------+-----------+
| Person_ID | First_Name | Last_Name | Igroup_ID |
+-----------+------------+-----------+-----------+
|         2 | Rick       | Hudson    |       100 |
|         2 | Rick       | Hudson    |        50 |
|         2 | Rick       | Hudson    |        28 |
|         2 | Rick       | Hudson    |        15 |
|         3 | John       | Hardy     |       150 |
|         3 | John       | Hardy     |       100 |
|         4 | Tom        | Johnson   |       200 |
|         4 | Tom        | Johnson   |       150 |
|         4 | Tom        | Johnson   |       100 |
+-----------+------------+-----------+-----------+

请参考上表使用LISTAGG操作背后的原因,因为我让每个人都与多个Group ID相关联,所以我获得了多个Person ID行,所以我想使用LISTAGG连接Group ID并分离值

由于每个人可以关联的IGROUP值有很多值,但我们担心前2个值,在截图中

什么东西返回100 | 50然后'GroupA' 什么东西返回150 | 100然后'GroupB' 什么东西返回200 | 150然后'GroupC'

(CASE LISTAGG(G.IGROUP_ID , '|') WITHIN GROUP (ORDER BY G.igroup_id) 
          WHEN  '100|50' THEN 'GroupA'
          WHEN  '150|100' THEN 'GroupB'
          WHEN  '200|150 THEN 'GroupC'
     END) AS SERVICES

但问题是,如果我使用上述方法,我必须在CASE语句中定义所有组合

我有什么方法可以使用WHEN LIKE '100|50%'那么GroupA

4 个答案:

答案 0 :(得分:3)

至于CASE + LIKE,你需要使用所谓的"搜索语法"案例:

CASE WHEN <condition> THEN <result>
    [WHEN <condition> THEN <result>
     ...]
    [ELSE <result>] 
END

如果你想保持默认的ELSE NULL但不想重复LISTAGG,你需要包装你的查询。 E.g。

SELECT CASE WHEN la LIKE '50|100%' THEN 'Yes'
            WHEN la LIKE '100|100%' THEN 'No
        END services
  FROM ( SELECT LISTAGG(G.IGROUP_ID , '|') WITHIN GROUP (ORDER BY G.igroup_id) la
          ....
       ) t

然而,使用LISTAGG测试组条件并不常见。在聚合中使用CASE更常见。例如。检查是否有一个组成员igroup_id = 50,请使用此条件

COUNT(CASE WHEN igroup_id = 50 THEN 1 END) = 1

要实现与LISTAGG方法相同的逻辑(恰好是一个50,至少一个100,没有其他值<100),您可以这样做:

CASE WHEN COUNT(CASE WHEN igroup_id = 50 THEN 1 END) = 1
      AND COUNT(CASE WHEN igroup_id = 100 THEN 1 END) >= 1
      AND COUNT(CASE WHEN igroup_id < 100 THEN 1 END) = 1 -- one for 50
     THEN 'Yes',

    WHEN COUNT(CASE WHEN igroup_id = 100 THEN 1 END) >= 2
     AND COUNT(CASE WHEN igroup_id < 100 THEN 1 END) = 0
    THEN 'No'
END

这可能看起来过于复杂,但很可能复杂性只是因为我重新实施了LISTAGG方法。知道边条件(例如,如果igroup_id恰好是唯一的)可能会使这种方法变得不那么笨重。

以下是我写的一些文章......

... CASE:http://modern-sql.com/feature/case

...在聚合中使用CASE的技巧:http://modern-sql.com/feature/filter

... LISTAGG:http://modern-sql.com/feature/listagg(但我认为使用listagg对你的目的不利)。

答案 1 :(得分:1)

为您感兴趣的每个值创建一个标志列 一旦你拥有它,你可以轻松地做任何你需要的分析。

select    person_id

         ,max (case when igroup_id =  15 then 1 else 0 end) as is_15
         ,max (case when igroup_id =  28 then 1 else 0 end) as is_28
         ,max (case when igroup_id =  50 then 1 else 0 end) as is_50
         ,max (case when igroup_id = 100 then 1 else 0 end) as is_100
         ,max (case when igroup_id = 150 then 1 else 0 end) as is_150
         ,max (case when igroup_id = 200 then 1 else 0 end) as is_200

from      mytable

group by  person_id

order by  person_id      
+-----------+-------+-------+-------+--------+--------+--------+
| PERSON_ID | IS_15 | IS_28 | IS_50 | IS_100 | IS_150 | IS_200 |
+-----------+-------+-------+-------+--------+--------+--------+
|         2 |     1 |     1 |     1 |      1 |      0 |      0 |
|         3 |     0 |     0 |     0 |      1 |      1 |      0 |
|         4 |     0 |     0 |     0 |      1 |      1 |      1 |
+-----------+-------+-------+-------+--------+--------+--------+

只需提取前两个值并检查它们

(
    CASE    regexp_substr
            (
                LISTAGG(G.IGROUP_ID , '|') WITHIN GROUP (ORDER BY G.igroup_id)
               ,'[^|]*\|[^|]*'
            )

        WHEN '50|100'  THEN 'Yes'
        WHEN '100|100' THEN 'No'
    END
) AS SERVICES

答案 2 :(得分:1)

您可以在子查询中获取该listagg值,并将其与主表连接,然后根据您的要求编写case语句。

Select t.*, case when list_value like '100|50%' THEN 'GroupA'
          WHEN list_value like '150|100%' THEN 'GroupB'
          WHEN  list_value like '200|150%' THEN 'GroupC' end as services
From 
(Select distinct Person_ID,First_Name,Last_Name from urtable) t
Join
(Select Person_ID,
LISTAGG(G.IGROUP_ID , '|') WITHIN GROUP (ORDER BY G.igroup_id desc) list_value from urtable group by Person_ID) g on (t.Person_ID=g.Person_ID)

答案 3 :(得分:0)

根据我的理解,我猜你需要每Person_Id一条记录以及根据你提供的案例得出的结果,即Group_A/Group_B/Group_C

WITH Test_Result AS 
(SELECT person_id,first_name,last_name,listagg(igroup_id,'|') within GROUP 
(ORDER BY rownum) list_agg_res FROM sof_3 GROUP BY 
person_id,first_name,last_name)

SELECT person_id,first_name,last_name,list_agg_res,
CASE WHEN list_agg_res LIKE '100|50%' THEN 'Group_A' 
WHEN  list_agg_res LIKE '150|100%' THEN 'Group_B' 
WHEN list_agg_res LIKE '200|150%' THEN 'Group_C' 
ELSE NULL END Final_Res FROM Test_Result;

希望以上查询有所帮助!!