使用concat和decode在subselect中排序

时间:2015-01-19 16:34:05

标签: sql oracle select oracle11g

说我有两张桌子:

产品

product_id  (other fields are of no concern)

SKU

product_id  sku_id   color_id   color_name  (other fields such as size but unimportant)
001         11       5          green
001         12       1          black
001         13       3          red
002         21       1          black
002         22       2          yellow
002         23       8          magenta
002         24       9          turquoise

我需要重写一个查询,该查询获取产品ID列表,其中包含与该产品关联的所有颜色/颜色ID的逗号分隔列表。两个列表中的颜色ID /名称必须具有相同的顺序。

期望的输出:

product_id  colorIds  colorNames
001         1,3,5     black,red,green
002         1,2,8,9   black,yellow,magenta,turquoise

请注意颜色ID的连续列表'订购地图到颜色名称顺序。

当前输出:

product_id  colorIds  colorNames
001         1,3,5     green,black,red  -- out of order sometimes
002         1,2,8,9   black,yellow,magenta,turquoise

目前使用的查询:

select distinct(p.product_id) as product_id, 
(select decode(dbms_lob.SubStr(wm_concat(DISTINCT color_name)),'NO COLOR','','No Color','','no color','',null,'',dbms_lob.SubStr(wm_concat(DISTINCT color_name))) as color_name from sku where product_id = p.product_id) as colorName, 
(select decode(dbms_lob.SubStr(wm_concat(DISTINCT color_code)),'000','',dbms_lob.SubStr(wm_concat(DISTINCT color_code))) from sku where product_id = p.product_id) as colorCode

from product p;

我在考虑只是在那些子选择中添加order by子句,但是查询只是错误输出,说缺少右括号 - 奇怪的是似乎没有不匹配的parens。欢迎任何建议。

编辑* 以上查询高度简化。实际上,它与十几个其他表连接以获得与产品相关的其他数据列,其中大多数是非聚合数据。解决方案在主查询中应该没有group by子句,或者建议一种合理的方式来满足这一要求。

3 个答案:

答案 0 :(得分:2)

这可能对您有用:

SELECT p.product_id
     , LISTAGG(s.color_id, ',') WITHIN GROUP ( ORDER BY s.color_id ) AS colorIds
     , LISTAGG(s.color_name, ',') WITHIN GROUP ( ORDER BY s.color_id ) AS colorNames
  FROM product p LEFT JOIN ( SELECT DISTINCT product_id, color_id, color_name FROM sku ) s
    ON p.product_id = s.product_id
 GROUP BY p.product_id
 ORDER BY product_id

LISTAGG()可以在WM_CONCAT()无法排序的情况下排序(并且它没有记录,等等。)

根据OP对非汇总数据的评论更新

WITH product_colors AS (
    SELECT p.product_id
         , LISTAGG(s.color_id, ',') WITHIN GROUP ( ORDER BY s.color_id ) AS colorIds
         , LISTAGG(s.color_name, ',') WITHIN GROUP ( ORDER BY s.color_id ) AS colorNames
      FROM product p LEFT JOIN ( SELECT DISTINCT product_id, color_id, color_name FROM sku ) s
        ON p.product_id = s.product_id
     GROUP BY p.product_id
)
SELECT t1.other_column, t2.other_column, etc.
  FROM table1 t1 JOIN table2 t2 ON ...
  JOIN product_colors pc ON ...

答案 1 :(得分:2)

这将实现distinct效果(您不能将distinctlistagg一起使用):

select product_id,
       listagg(color_id, ',') within group(order by color_id) as colorids,
       listagg(color_name, ',') within group(order by color_id) as colornames
  from (select distinct product_id, color_id, color_name from sku)
 group by product_id

如果您想显示product表格中的列和/或您希望在product表格上展示产品,而不是sku表格中的产品,则可以使用:

select p.product_id,
       listagg(s.color_id, ',') within group(order by s.color_id) as colorids,
       listagg(s.color_name, ',') within group(order by s.color_id) as colornames
  from product p
  left join (select distinct product_id, color_id, color_name from sku) s
    on p.product_id = s.product_id
 group by p.product_id

答案 2 :(得分:0)

嗨,这可能也有效。

select product_id,
       listagg(color_id,',') within group(order by color_names) as color_ids,
       listagg(color_names,',') within group (order by color_names) color_names

    from sku
    group by product_id;