简体   繁体   中英

Oracle 8i SQL - concatenate strings from different rows

I need to concatenate strings from different rows, as below.
The number of rows for each NAME is variable and its range is unknown.

NAME  COLOR
Bob   Red
Bob   Blue
Tom   Green
John  Red
John  Yellow
John  Purple

Desired output:

NAME  COLORS
Bob   RedBlue
Tom   Green
John  RedYellowPurple

The limitations I am facing are :

  • Oracle 8i (8.1.7.4.0) - I have no control over this and upgrading is not an option
  • read only access
  • can't create...

So basically :

  • no CREATE
  • no LISTAGG
  • no XMLAGG
  • no WM_CONCAT
  • no Ref Cursor
  • no SYS_CONNECT_BY_PATH

Am I SOL ?

Oracle 8i at least supports analytic functions, so you could assign each color value a nominal number with row_number() or dense_rank() (ordering by whatever makes sense to you):

select name, color,
  row_number() over (partition by name order by color) as rn
from your_table;

and then use a variation on a manual pivot with one max(decode()) per possible row number:

select name,
  max(decode(rn, 1, color))
  || max(decode(rn, 2, color))
  || max(decode(rn, 3, color))
  || max(decode(rn, 4, color))
  || max(decode(rn, 5, color))
  || max(decode(rn, 6, color))
  || max(decode(rn, 7, color))
  -- ...
  as colors
from (
  select name, color,
    row_number() over (partition by name order by color) as rn
  from your_table
)
group by name
order by name;

NAME       COLORS                                                                
---------- ----------------------------------------------------------------------
Bob        BlueRed                                                               
John       PurpleRedYellow                                                       
Tom        Green                                                                 

You said the range is unknown, but even if there are an unlimited number of rows for each name, you're still restricted by the final concatenated string having to be at most 4000 characters - from your knowledge of the actual color values that would give you a maximum usable number. (And you could generate the decode parts automatically as a one-off thing).

You could include delimiters the same way if you needed to:

select name,
  max(decode(rn, 1, color))
  || max(decode(rn, 2, ',')) || max(decode(rn, 2, color))
  || max(decode(rn, 3, ',')) || max(decode(rn, 3, color))
  || max(decode(rn, 4, ',')) || max(decode(rn, 4, color))
  || max(decode(rn, 5, ',')) || max(decode(rn, 5, color))
  || max(decode(rn, 6, ',')) || max(decode(rn, 6, color))
  || max(decode(rn, 7, ',')) || max(decode(rn, 7, color))
  || max(decode(rn, 8, ',')) || max(decode(rn, 8, color))
  -- ...
  as colors
from (
  select name, color,
    row_number() over (partition by name order by color) as rn
  from your_table
  where color is not null
)
group by name
order by name;

NAME       COLORS                                                                                 
---------- ---------------------------------------------------------------------------------------
Bob        Blue,Red                                                                               
John       Purple,Red,Yellow                                                                      
Tom        Green                                                                                  

I've included a is not null filter in the inner query just in case that column is nullable - that ought to prevent empty elements in the final list.

(Not tested in 8i as I can't find an instance that old to spin up, but I don't think this is using anything introduced later...)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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