LISTAGG 操作期间带有 LIKE 的 CASE 语句
CASE statement with LIKE during LISTAGG Operation
+-----------+------------+-----------+-----------+
| 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 |
+-----------+------------+-----------+-----------+
请参考上面table使用操作 LISTAGG 背后的原因,我得到了多行个人 ID,因为我让每个人都与多个组 ID 相关联,所以我想连接组 ID使用 LISTAGG 并分离值。
而且由于 IGROUP 值有很多每个人都可以关联的值,但我们担心前 2 个值,在屏幕截图中
什么时候 returns 100|50 然后 'GroupA'
当某事 returns 150|100 然后 'GroupB'
当某事 returns 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%'
THEN GroupA
至于CASE+LIKE,需要用到CASE的所谓"searched syntax":
CASE WHEN <condition> THEN <result>
[WHEN <condition> THEN <result>
...]
[ELSE <result>]
END
如果您想保留默认的 ELSE NULL 但不想重复 LISTAGG,则需要包装您的查询。例如
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 恰好是唯一的)可能会使这种方法不那么笨重。
这是我写的一些文章...
... 案例:http://modern-sql.com/feature/case
...在聚合中使用 CASE 的技巧:http://modern-sql.com/feature/filter
... LISTAGG:http://modern-sql.com/feature/listagg(但我认为使用 listagg 不利于您的目的)。
为您感兴趣的每个值创建一个标志列。
一旦你拥有它,你就可以轻松地做任何你需要的分析。
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 |
+-----------+-------+-------+-------+--------+--------+--------+
只需提取前 2 个值并检查它们
(
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
您可以在子查询中获取该 listagg 值并将其与主查询连接起来 table 然后根据您的要求编写 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)
根据我的理解,我猜你需要每个 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;
希望以上查询对您有所帮助!!
+-----------+------------+-----------+-----------+
| 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 |
+-----------+------------+-----------+-----------+
请参考上面table使用操作 LISTAGG 背后的原因,我得到了多行个人 ID,因为我让每个人都与多个组 ID 相关联,所以我想连接组 ID使用 LISTAGG 并分离值。
而且由于 IGROUP 值有很多每个人都可以关联的值,但我们担心前 2 个值,在屏幕截图中
什么时候 returns 100|50 然后 'GroupA' 当某事 returns 150|100 然后 'GroupB' 当某事 returns 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%'
THEN GroupA
至于CASE+LIKE,需要用到CASE的所谓"searched syntax":
CASE WHEN <condition> THEN <result>
[WHEN <condition> THEN <result>
...]
[ELSE <result>]
END
如果您想保留默认的 ELSE NULL 但不想重复 LISTAGG,则需要包装您的查询。例如
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 恰好是唯一的)可能会使这种方法不那么笨重。
这是我写的一些文章...
... 案例:http://modern-sql.com/feature/case
...在聚合中使用 CASE 的技巧:http://modern-sql.com/feature/filter
... LISTAGG:http://modern-sql.com/feature/listagg(但我认为使用 listagg 不利于您的目的)。
为您感兴趣的每个值创建一个标志列。
一旦你拥有它,你就可以轻松地做任何你需要的分析。
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 |
+-----------+-------+-------+-------+--------+--------+--------+
只需提取前 2 个值并检查它们
(
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
您可以在子查询中获取该 listagg 值并将其与主查询连接起来 table 然后根据您的要求编写 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)
根据我的理解,我猜你需要每个 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;
希望以上查询对您有所帮助!!