组合非结构化表中的行

时间:2015-10-13 05:44:19

标签: sql oracle postgresql oracle11g

我有这个非结构化表,其中(1)itemID有多个与之关联的receptCodes。我需要做的是在一行中显示与不同orderID相关联的每个receptCode。当前的表结构与此类似:

    itemID  | receptString
=============================
    itemID1 | receptString1
    itemID1 | receptString2
    itemID1 | receptString3
    itemID1 | receptString4
    itemID2 | receptString5
    itemID2 | receptString6

期望的输出:

    itemID    | receptString | receptString  | receptString | receptString |
    ============================================================================
    itemID1  | receptString1 | receptString2 | receptString3 | receptString4 |
    itemID2  | receptString5 | receptString6 |

为此编写查询的正确方法是什么?我尝试使用多个CASE语句和GROUP BY,但我正在努力解决这个问题。每个orderID只能有(5)个MAXS(最大)个接收串,但可以在1-5个接收串之间变化。 receptStrings可以是字符,符号和数字的组合。如果出现NULL,我不担心。这只是我需要的一部分,但却是我正在努力的方向。我在PostgreSQL和Oracle SQL中都对它进行了测试。

*更新*

谢谢大家的建议。问题最终比我们原先预期的要重要得多(我提供的示例表是一小块非常大的馅饼)所以我们决定采取不同的方法。再次感谢。

3 个答案:

答案 0 :(得分:1)

以11g测试。

我在这里采用临时分隔符~。如果您认为字符串字符包含此字符,则可以使用|chr(10)chr(13)或任何其他分隔符。它会工作正常。

列名也不能与您想要的相同。我附上1,2,3等等。您可以根据需要更改它们。

    with tbl1 (itemID  , receptString) as(
    select 'itemID1','receptString1' from dual union all
    select 'itemID1','receptString2' from dual union all
    select 'itemID1','receptString3' from dual union all
    select 'itemID1','receptString4' from dual union all
    select 'itemID2','receptString5' from dual union all
    select 'itemID2','receptString6' from dual
    ), tbl2 as(
    select itemid,listagg(receptString,'~') within group (order by itemid) || '~' as concstr
    from tbl1
    group by itemid
    )
     SELECT  tbl2.itemid,REGEXP_SUBSTR(concstr ,'([^~]*)(\~)', 1, 1, NULL, 1 ) as receptString1,
      REGEXP_SUBSTR(concstr ,'([^~]*)(\~)', 1, 2, NULL, 1 ) as receptString2,
      REGEXP_SUBSTR(concstr ,'([^~]*)(\~)', 1, 3, NULL, 1 ) as receptString3,
      REGEXP_SUBSTR(concstr ,'([^~]*)(\~)', 1, 4, NULL, 1 ) as receptString4,
      REGEXP_SUBSTR(concstr ,'([^~]*)(\~)', 1, 5, NULL, 1 ) as receptString5
      from tbl2

首先,我使用listagg连接列并添加了分隔符。然后我使用regep_substr将它们分成列。对于不存在的列,根据此输出,它们将为null。

输出

 ITEMID     RECEPTSTRING1   RECEPTSTRING2   RECEPTSTRING3   RECEPTSTRING4  RECEPTSTRING5
 itemID1    receptString1   receptString2   receptString3   receptString4   
 itemID2    receptString5   receptString6           

答案 1 :(得分:0)

Oracle 11g R2 及更高版本上,您可以使用 LISTAGG 进行字符串聚合。

SELECT itemID  ,
  LISTAGG(receptString, ' | ') WITHIN GROUP (
ORDER BY receptString) AS receptString
FROM table_name
GROUP BY itemID
ORDER BY itemID;

有关不同数据库版本的其他方法,请查看Oracle String Aggregation Techniques

请记住,这是字符串聚合,而不是 PIVOT 。您将把行聚合到单个分隔的字符串行。

答案 2 :(得分:0)

<强>的PostgreSQL

考虑以下为例

create table ft (itemid text,receptstring text);
insert into ft values
('itemID1','receptString1'),
('itemID1','receptString2'),
('itemID1','receptString3'),
('itemID1','receptString4'),
('itemID2','receptString5'),
('itemID2','receptString6');

并使用WITH Queries (CTE)string_agg()regexp_split_to_array()

    WITH CTE
AS (
    SELECT itemid || ',' || string_agg(receptstring, ',' ORDER BY receptstring) col
    FROM ft
    GROUP BY itemid
    ORDER BY itemid          
    )
    ,cte1
AS (
    SELECT regexp_split_to_array(col, ',') AS a
    FROM cte
        )
SELECT a [1] AS itemid 
    ,a [2] receptString
    ,a [3] receptString
    ,a [4] receptString
    ,a [5] receptString -- you can add more if your condition exceed 1-5      
                        -- limit(ex.a [6] receptString  )
FROM cte1

输出:

itemid  receptstring  receptstring    receptstring   receptstring    receptstring
------- ------------- --------------- --------------- --------------- --------------- 
itemID1 receptString1 receptString2   receptString3   receptString4   NULL
itemID2 receptString5 receptString6   NULL            NULL            NULL

另一种方式

Maximum Columns per Table 250 - 1600 depending on column types如果某个itemID有超过1600或250个receptString的数字?所以我建议你做类似下面的事情

在PostgreSQL中使用string_agg()

 select "itemID"
       ,string_agg("receptString",',' ORDER BY "receptString") receptString 
 from tbl
 group by "itemID"

只有两列,第二列会存储特定receptString的所有itemID