Question

All,

My Oracle Database is version 10g Enterprise Edition Release 10.2.0.5.0 - 64bit

I have the following statement which usefully gets me the max (or min or count etc) values in each case as expected however what I would like is to get and to concatenate all of the values rather than the max, min or count - is there an elegant way to do this please ?

SELECT lla.id, 
       max(decode(lla.attrid, 2, lla.valstr, null)) "Attribute Name 2",
       min(decode(lla.attrid, 3, lla.valstr, null)) "Attribute Name 3",
       count(decode(lla2.attrid, 5, lla2.valstr, null)) "Attribute Name 5"
FROM llattrdata lla, llattrdata lla2
WHERE lla.id = lla2.id 
      AND lla.defid = 111111 --category id 1
      AND lla2.defid = 222222 --category id 2
      AND lla.id = 48212327 and lla2.id = 48212327
      GROUP BY lla.id

Hoping for a row that looks something like this:

12121212 | fred, jack, gill | 56 | 29,10

To be clearer it is the values that the 'Attribute Name 3' (for example) contains that I want to see all of and not just the max or the minimum. In other words for that attribute I can get the max or the min value or even the count but cannot see a way to get all of the values ? In other words I can get 10 as the min and 29 as the max - even 2 as the count but not 29 and 10 in the same column !

Many thanks in advance,

No correct solution

OTHER TIPS

SELECT e.department_id,
       listagg(e.first_name) within group (order by e.department_id) "Attribute Name 2"
FROM employees e join
     departments d
     on e.department_id = d.department_id 
GROUP BY e.department_id;

you can use above example and alter your query

Try this:

SELECT lla.id || ' | ' ||
       max(decode(lla.attrid, 2, lla.valstr, null)) || ' | ' ||
       min(decode(lla.attrid, 3, lla.valstr, null)) || ' | ' ||
       count(decode(lla2.attrid, 5, lla2.valstr, null))
FROM llattrdata lla, llattrdata lla2
WHERE lla.id = lla2.id 
      AND lla.defid = 111111 --category id 1
      AND lla2.defid = 222222 --category id 2
      AND lla.id = 48212327 and lla2.id = 48212327
      GROUP BY lla.id

Use wmsys.wm_concat function learn more here about it. This is a non-documented function in Oracle 10.

It returns you comma-separated list, you can use replace function to replace comma with the thing you need.

Unfortunately this function does not have order clause so you cannot specify the order in the list.

EDIT:

As far as this function is not available for you, you can simply create it:

CREATE OR REPLACE TYPE wm_concat_impl
   AUTHID CURRENT_USER
AS OBJECT (
   curr_str   VARCHAR2 (32767),
   STATIC FUNCTION odciaggregateinitialize (sctx IN OUT wm_concat_impl)
      RETURN NUMBER,
   MEMBER FUNCTION odciaggregateiterate (
      SELF   IN OUT   wm_concat_impl,
      p1     IN       VARCHAR2
   )
      RETURN NUMBER,
   MEMBER FUNCTION odciaggregateterminate (
      SELF          IN       wm_concat_impl,
      returnvalue   OUT      VARCHAR2,
      flags         IN       NUMBER
   )
      RETURN NUMBER,
   MEMBER FUNCTION odciaggregatemerge (
      SELF    IN OUT   wm_concat_impl,
      sctx2   IN       wm_concat_impl
   )
      RETURN NUMBER
);
/

CREATE OR REPLACE TYPE BODY wm_concat_impl
IS
   STATIC FUNCTION odciaggregateinitialize (sctx IN OUT wm_concat_impl)
      RETURN NUMBER
   IS
   BEGIN
      sctx := wm_concat_impl (NULL);
      RETURN odciconst.success;
   END;
   MEMBER FUNCTION odciaggregateiterate (
      SELF   IN OUT   wm_concat_impl,
      p1     IN       VARCHAR2
   )
      RETURN NUMBER
   IS
   BEGIN
      IF (curr_str IS NOT NULL)
      THEN
         curr_str := curr_str || ',' || p1;
      ELSE
         curr_str := p1;
      END IF;

      RETURN odciconst.success;
   END;
   MEMBER FUNCTION odciaggregateterminate (
      SELF          IN       wm_concat_impl,
      returnvalue   OUT      VARCHAR2,
      flags         IN       NUMBER
   )
      RETURN NUMBER
   IS
   BEGIN
      returnvalue := curr_str;
      RETURN odciconst.success;
   END;
   MEMBER FUNCTION odciaggregatemerge (
      SELF    IN OUT   wm_concat_impl,
      sctx2   IN       wm_concat_impl
   )
      RETURN NUMBER
   IS
   BEGIN
      IF (sctx2.curr_str IS NOT NULL)
      THEN
         SELF.curr_str := SELF.curr_str || ',' || sctx2.curr_str;
      END IF;

      RETURN odciconst.success;
   END;
END;
/

CREATE OR REPLACE FUNCTION wm_concat (p1 VARCHAR2)
   RETURN VARCHAR2
   AGGREGATE USING wm_concat_impl;
/

The query is taken from this website, it is, unfortunately, in Russian, but just use this custom aggregate function for your purposes.

I had the same problem and used the STRAGG ( as in STRing AGGregate) function created by Tom Kyte.

https://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:15637744429336

create or replace type stragg_type as object
(
  string varchar2(4000),
  static function ODCIAggregateInitialize
    ( sctx in out stragg_type )
    return number ,
  member function ODCIAggregateIterate
    ( self  in out stragg_type ,
      value in     varchar2
    ) return number ,
  member function ODCIAggregateTerminate
    ( self        in  stragg_type,
      returnvalue out varchar2,
      flags in number
    ) return number ,
  member function ODCIAggregateMerge
    ( self in out stragg_type,
      ctx2 in     stragg_type
    ) return number
);
/

create or replace type body stragg_type
is
  static function ODCIAggregateInitialize
  ( sctx in out stragg_type )
  return number
  is
  begin
    sctx := stragg_type( null ) ;
    return ODCIConst.Success ;
  end;
  member function ODCIAggregateIterate
  ( self  in out stragg_type ,
    value in     varchar2
  ) return number
  is
  begin
    self.string := self.string || ',' || value ;
    return ODCIConst.Success;
  end;
  member function ODCIAggregateTerminate
  ( self        in  stragg_type ,
    returnvalue out varchar2 ,
    flags       in  number
  ) return number
  is
  begin
    returnValue := ltrim( self.string, ',' );
    return ODCIConst.Success;
  end;
  member function ODCIAggregateMerge
  ( self in out stragg_type ,
    ctx2 in     stragg_type
  ) return number
  is
  begin
    self.string := self.string || ctx2.string;
    return ODCIConst.Success;
  end;
end;
/

create or replace function stragg
  ( input varchar2 )
  return varchar2
  deterministic
  parallel_enable
  aggregate using stragg_type
;
/

Run the three create statements one after the other in sqlplus or sqldev. Now the stragg() function is created in your user schema. Then you can do:

SELECT lla.id, 
       max(decode(lla.attrid, 2, lla.valstr, null)) "Attribute Name 2",
       STRAGG(decode(lla.attrid, 3, lla.valstr, null)) "Attribute Name 3 List",
       count(decode(lla2.attrid, 5, lla2.valstr, null)) "Attribute Name 5"
FROM llattrdata lla, llattrdata lla2
WHERE lla.id = lla2.id 
      AND lla.defid = 111111 --category id 1
      AND lla2.defid = 222222 --category id 2
      AND lla.id = 48212327 and lla2.id = 48212327
GROUP BY lla.id
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top