SQL / PLSQL合并多列表值

时间:2017-06-08 10:02:20

标签: sql oracle

我有两个表名table1和table2。

enter image description here

从第一个表我得到number,id和value.ID列是多列表,因此该列中的值用逗号分隔,例如:3799952,3799953。对于每个ID,table2中都有一些值。例如,对于3799952值是汇编,对于3799953值是Indiviual。我必须用逗号分隔来获取这些值。在多列表中,截至目前我只有两个值,所以我使用序列到2,明天我将获得多个值。任何人都可以帮助我程序或用户定义的功能。

select id,item_number,max(decode(seq,1,entry_id))||','||max(decode(seq,2,entry_id)) entry_id,
  max(decode(seq,1,entryvalue))||','||max(decode(seq,2,entryvalue)) entryvalue
  from (

  select a.id,a.item_number,a.entry_id,list.entryvalue,row_number() over (partition by item_number order by entry_id) seq
  from  (SELECT i.id,i.item_number,
 trim(regexp_substr(i.product_lines, '[^,]+', 1, lines.column_value)) entry_id
  FROM item i,
     TABLE (CAST (MULTISET
     (SELECT LEVEL FROM dual CONNECT BY LEVEL <= regexp_count(i.product_lines, ','))AS sys.odciNumberList)) lines   ORDER BY i.id)a , listentry list where a.entry_id=list.entryid and a.entry_id is not null)
  group by id,item_number;

这是我的查询和输出,如下所示,

**ID    ITEM_NUMBER ENTRY_ID             ENTRYVALUE**
6024065 P00008           3799953,            Individual,
6024607 U00024          3799952,3799953       Assembly,Individual
6024886 U00154      3799952,3799953       Assembly,Individual
6015685 INK_PEN         3799952,              Assembly,
6036877 P0000020    3799952,3799953       Assembly,Individual

截至目前,我只有两个入门值,所以使用max(decode(seq,1,entry_id))||','||max(decode(seq,2,entry_id)) entry_id可以告诉我如何修改多个值。

提前致谢

2 个答案:

答案 0 :(得分:0)

您的问题不是很清楚您要实现的目标 - 但是,您似乎有两个逗号分隔的列表要分开,以便值保持相关。您可以使用递归子查询分解子句。像这样(未经测试):

WITH data ( id, item_number, entity_id, entryvalue,
            entity_start, entity_end, entry_start, entry_end ) AS (
  SELECT id,
         item_number,
         entity_id,
         entryvalue, 
         1,
         INSTR( entity_id, ',', 1 ),
         1,
         INSTR( entryvalue, ',', 1 )
  FROM   your_table
UNION ALL
  SELECT id,
         item_number,
         entity_id,
         entryvalue, 
         entity_end + 1,
         INSTR( entity_id, ',', entity_end + 1 ),
         entry_end + 1,
         INSTR( entryvalue, ',', entry_end + 1 )
  FROM   data
  WHERE  entity_end > 0 AND entry_start > 0
)
SELECT id,
       item_number,
       CASE entity_end
         WHEN 0
         THEN SUBSTR( entity_id, entity_start )
         ELSE SUBSTR( entity_id, entity_start, entity_end - entity_start )
       END AS entity_id,
       CASE entry_end
         WHEN 0
         THEN SUBSTR( entryvalue, entry_start )
         ELSE SUBSTR( entryvalue, entry_start, entry_end - entry_start )
       END AS entryvalue
FROM   data;

答案 1 :(得分:0)

使用函数listagg()两次:

select id, item_number, 
       listagg(entry_id, ',') within group (order by seq) entry_id,
       listagg(entryvalue, ',') within group (order by seq) entryvalue
  from your_inner_query
  group by id, item_number

测试数据:

create table item (id number(8), item_number varchar2(10), product_lines varchar2(20));
insert into item values (6024065, 'P00008',   '3799953,');
insert into item values (6024607, 'U00024',   '3799952,3799953,');
insert into item values (6024886, 'U00154',   '3799952,3799953,');
insert into item values (6015685, 'INK_PEN',  '3799952,');
insert into item values (6036877, 'P0000020', '3799952,3799953,');

create table listentry(entryid number(8), entryvalue varchar2(10));
insert into listentry values (3799952, 'Assembly');
insert into listentry values (3799953, 'Individual');

完整查询:

with t as (
    select a.id, a.item_number, a.entry_id, list.entryvalue,
                row_number() over (partition by item_number order by entry_id) seq
      from (select i.id,i.item_number,
                   trim(regexp_substr(i.product_lines, '[^,]+', 1, lines.column_value)) entry_id
              from item i,
                   table (cast (multiset ( select level 
                                             from dual 
                                             connect by level <= regexp_count(i.product_lines, ',')) 
                            as sys.odcinumberlist)) lines   
              order by i.id) a
           join listentry list on a.entry_id = list.entryid and a.entry_id is not null )
select id, item_number, 
       listagg(entry_id, ',') within group (order by seq) entry_id,
       listagg(entryvalue, ',') within group (order by seq) entryvalue
  from t
  group by id, item_number
  order by id;

输出:

       ID ITEM_NUMBER ENTRY_ID           ENTRYVALUE
--------- ----------- ------------------ ----------------------
  6015685 INK_PEN     3799952            Assembly
  6024065 P00008      3799953            Individual
  6024607 U00024      3799952,3799953    Assembly,Individual
  6024886 U00154      3799952,3799953    Assembly,Individual
  6036877 P0000020    3799952,3799953    Assembly,Individual

编辑:解释

子查询a将表item中的数据划分为单独的行。分层查询connect by根据id中每个,计数逗号product_lines生成所需数量的行。 函数regexp_substr将所需的entry_id切割为单独的行。

ID       ITEM_NUMBER   ENTRY_ID
-------  ------------  --------
6015685  INK_PEN        3799952
6024065  P00008         3799953
6024607  U00024         3799952
6024607  U00024         3799953
6024886  U00154         3799953
6024886  U00154         3799952
6036877  P0000020       3799952
6036877  P0000020       3799953

这样的表接下来与您的查找表listentry连接在一起。每行都以row_number()编号。所以我们有这个:

ID       ITEM_NUMBER   ENTRY_ID  ENTRYVALUE   SEQ
-------  ------------  --------  -----------  ---
6015685  INK_PEN        3799952  Assembly       1
6036877  P0000020       3799952  Assembly       1
6036877  P0000020       3799953  Individual     2
6024065  P00008         3799953  Individual     1
6024607  U00024         3799952  Assembly       1
6024607  U00024         3799953  Individual     2
6024886  U00154         3799952  Assembly       1
6024886  U00154         3799953  Individual     2

现在我们可以使用listagg()对相同ID的数据进行分组。它们按SEQ排序。

请注意,我没有更改您的原始内部查询,仅使用select而不是listagg()添加了最后decode您试过。