使用连接和解码在子选择中排序

Order By in subselect using concat and decode

假设我有两个表:

产品

product_id  (other fields are of no concern)

斯库

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 列表,其中包含与该产品关联的所有 colors/color ID 的逗号分隔列表。颜色 ids/names 在两个列表中的顺序必须相同。

期望的输出:

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 子句,但查询出错,说缺少右括号 - 奇怪的是似乎没有不匹配的括号。欢迎提出任何建议。

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

这可能对你有用:

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 ...

这样会达到distinct的效果(distinct不能和listagg一起使用):

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 table and/or 中的列,您希望在 product table 上显示产品而不是 sku table 你可以使用:

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 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;