简体   繁体   English

带有计数的Oracle独特的listagg

[英]Oracle distinct listagg with count

I need to display a comma-separated description per table row but I need the list to be distinct and have counts for some of the descriptions available. 我需要在每个表行中显示一个逗号分隔的描述,但我需要使列表与众不同,并且要对一些可用的描述进行计数。

every_description     needs_count
---------------------------------
Bred                          yes
From Vendor                   yes
Grouped                        no
Removed                       yes
Separated                      no
Weaned                        yes

So in a day, the description could be something like Bred, Grouped, Weaned and I have this working now using LISTAGG and removing the duplicates using the solution mentioned here but I need to add counts for some of the descriptions like 5 Bred, Grouped, 2 Weaned . 因此,一天之内的描述可能像Bred, Grouped, Weaned ,现在我可以使用LISTAGG进行此工作,并使用此处提到的解决方案删除重复项但是我需要为5 Bred, Grouped, 2 Weaned

Here's my current query where I'm stuck: 这是我目前遇到的问题:

WITH cages AS (
        SELECT 1234 AS id FROM DUAL
  UNION SELECT 5678 AS id FROM DUAL
  UNION SELECT 9012 AS id FROM DUAL
  UNION SELECT 3456 AS id FROM DUAL
), cage_comments AS (
        SELECT 1234 AS cage_id, 'Bred' AS description, TO_DATE('11/14/2017', 'MM/DD/YYYY') AS event_date FROM DUAL
  UNION SELECT 5678 AS cage_id, 'Grouped' AS description, TO_DATE('11/14/2017', 'MM/DD/YYYY') AS event_date FROM DUAL
  UNION SELECT 9012 AS cage_id, 'Weaned' AS description, TO_DATE('11/14/2017', 'MM/DD/YYYY') AS event_date FROM DUAL
  UNION SELECT 3456 AS cage_id, 'Weaned' AS description, TO_DATE('11/14/2017', 'MM/DD/YYYY') AS event_date FROM DUAL
  UNION SELECT 3456 AS cage_id, 'Bred' AS description, TO_DATE('11/02/2017', 'MM/DD/YYYY') AS event_date FROM DUAL
  UNION SELECT 3456 AS cage_id, 'Grouped' AS description, TO_DATE('11/14/2017', 'MM/DD/YYYY') AS event_date FROM DUAL
), calendar AS (
  SELECT dt
  FROM (
    SELECT TRUNC(LAST_DAY(TO_DATE(&month || '/01/' || &year, 'MM/DD/YYYY')) - ROWNUM + 1) dt
    FROM DUAL CONNECT BY ROWNUM <= 31
  )
  WHERE dt >= TRUNC(TO_DATE(&month || '/01/' || &year, 'MM/DD/YYYY'), 'MM')
  ORDER BY dt ASC
)

SELECT
  cal.dt,
  (
    SELECT
      CASE
        WHEN COUNT(cc.cage_id) > 0 THEN RTRIM(
          REGEXP_REPLACE(
            (LISTAGG(cc.description, ',') WITHIN GROUP (ORDER BY cc.description)),
            '([^,]*)(,\1)+($|,)',
            '\1\3'
          ),
          ','
        )
        ELSE NULL
      END
    FROM cages c
    LEFT JOIN cage_comments cc ON cc.cage_id = c.id
    WHERE cc.event_date = cal.dt
  ) AS description
FROM calendar cal
ORDER BY cal.dt

In short - I'm just having difficulties adding the COUNT for some of the descriptions for that day. 简而言之-我很难为当天的某些说明添加COUNT In the case above I would like to say 1 Bred for November 2, 2017 and 1 Bred, Grouped, 2 Weaned for November 14, 2017 . 在上述情况下我想说的1 BredNovember 2, 20171 Bred, Grouped, 2 WeanedNovember 14, 2017

Currently you are aggregating all the descriptions (without DISTINCT) and then you remove the duplicate descriptions with a regular expression replace. 当前,您正在汇总所有描述(不使用DISTINCT),然后使用正则表达式replace删除重复的描述。 This is very inefficient - it would be better to select distinct and then apply LISTAGG. 这是非常低效的-选择不重复然后应用LISTAGG会更好。

This becomes even more important if you need to add the count. 如果您需要添加计数,这将变得更加重要。 Take the result of your join and GROUP BY description. 获取您的加入和GROUP BY描述的结果。 (In particular, this will take care of DISTINCT). (特别是,这将处理DISTINCT)。 In the SELECT for this aggregate step, include the count. 在此聚合步骤的“选择”中,包括计数。 Then join the result to the additional table at the top of your question, and re-write the argument to LISTAGG to include a CASE expression, equal to the count (and a space) when the needs_count value is 'yes' . 然后将结果连接到问题顶部的其他表中,并将参数重写为LISTAGG以包括CASE表达式,该表达式等于needs_count值为'yes'时的计数(和空格)。

You could use: 您可以使用:

SELECT
  cal.dt,
  ( 
      SELECT LISTAGG(CASE WHEN COUNT(*)=1 THEN '' 
            ELSE CAST(COUNT(*) AS VARCHAR2(10)) || ' ' END  || description, ', ')
            WITHIN GROUP (ORDER BY description) 
      FROM cages c
      LEFT JOIN cage_comments cc ON cc.cage_id = c.id
      WHERE cc.event_date = cal.dt
      GROUP BY cc.event_date, cc.description
  ) AS description
FROM calendar cal
ORDER BY cal.dt;

DBFiddle Demo DBFiddle演示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM