Skip to Main Content

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question.

Asked: January 31, 2017 - 5:17 pm UTC

Last updated: February 01, 2017 - 2:42 pm UTC

Version: 11g

Viewed 10K+ times! This question is

You Asked

Hello Tom.

I want to concat all columns of a row into one string.
select * from table

should bring out one colum per row, including all fieldvalues as one string.

The use auf || didn't work, because I want it for different tables with different (and perhaps unknown) fields.
Is that possible?

Thanks for your help.
Jörg

and Connor said...

Sounds to me like you want to *generate* the select statements you want. So you could something like this:

SQL> select 'select '||listagg(column_name,',') within group ( order by column_id )||' from '||table_name||';'
  2  from user_tab_columns
  3  group by table_name
  4  order by table_name;

'SELECT'||LISTAGG(COLUMN_NAME,',')WITHINGROUP(ORDERBYCOLUMN_ID)||'FROM'||TABLE_NAME||';'
------------------------------------------------------------------------------------------------------------
select M from JOB_LOG;
select JOBNO,EMPNO from JOB_PARAMS;
select PROD_CATEGORY,PROD_ID from PRODUCT;
select PROD_CATEGORY,PROD_ID from P_PRODUCT;
select X,Y,Z from T1;
select X,Y,Z from T2;


you could enhance this to cater for datatypes (eg put a 'to_char' around the dates etc). So to generate a concatenation, you can simply alter the second parameter of LISTAGG to suit whatever your need is.


Rating

  (6 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Generation X

Duke Ganote, January 31, 2017 - 8:19 pm UTC

LISTAGG is nicely versative. (For small tables, I've gone further so as to generate INSERT statements for another DBMS when it didn't understand Oracle dates and timestamps).

SQL> create table xx ( a varchar2(5), b number, c date, d timestamp );

Table created.

SQL> insert into xx values ( 'Arby', 5, sysdate, systimestamp );

1 row created.

select 'select '
     ||listagg(case when data_type like '%CHAR%'
                    then '''"''||'||column_name||'||''"'''
                    when data_type = 'DATE'
                    then 'TO_CHAR('||column_name||',''yyyy-mm-dd hh24:mi:ss'')'
                    when substr(data_type,1,4) = 'TIME'
                    then 'TO_CHAR('||column_name||',''yyyy-mm-dd hh24:mi:ss.ff'')'
                    else column_name
                end
          ,'||'',''||')within group(order by column_id)
     ||' from xx' as builder
  from user_tab_columns
 where table_name = 'XX';

SQL> /

BUILDER
-------------------------------------------------------------------------------------------------------------------------------
select '"'||A||'"'||','||B||','||TO_CHAR(C,'yyyy-mm-dd hh24:mi:ss')||','||TO_CHAR(D,'yyyy-mm-dd hh24:mi:ss.ff') from xx

SQL> select '"'||A||'"'||','||B||','||TO_CHAR(C,'yyyy-mm-dd hh24:mi:ss')||','||TO_CHAR(D,'yyyy-mm-dd hh24:mi:ss.ff') from xx;

'"'||A||'"'||','||B||','||TO_CHAR(C,'YYYY-MM-DDHH24:MI:SS')||','||TO_CHAR(D,'YYYY-MM-DDHH24:MI:SS.
--------------------------------------------------------------------------------------------------
"Arby",5,2017-01-31 13:51:19,2017-01-31 13:51:19.673299



Connor McDonald
January 31, 2017 - 11:43 pm UTC

One of my favourite things coming in 12.2

set markup csv

in sqlplus :-)

Another idea

Thomas Brotherton, January 31, 2017 - 8:48 pm UTC

If you wanted to write a function to do this generically, you could use a combination of dbms_sql to generate and run the dynamic query and pipelined functions to return the result.
Connor McDonald
January 31, 2017 - 11:44 pm UTC

Good point.

Concat all fieldvalues

Jörg, February 01, 2017 - 7:07 am UTC

Hello Connor,

thanks for your reply, but I want to concat the values of every row.

In detail:
I have two tables with the 'same' data content and want to compare them to find differences.
My idea was something like this:
select table1.keyfield
from   table1, table2
where  table1.keyfield   = table2.keyfield  
  and  concat(table1.*) <> concat(table2.*)

The result should only show the rows of table1 which differs from table2 in one ore more fieldvalues.

That's the reason why I want to concat the values, not the column_names.

Chris Saxon
February 01, 2017 - 2:35 pm UTC

Full Outer joins

Rajeshwaran, Jeyabal, February 01, 2017 - 2:36 pm UTC

....
I have two tables with the 'same' data content and want to compare them to find differences
....


The FULL OUTER JOINS would be the way to go.

demo@ORA12C> create table dept1 as select * from dept;

Table created.

demo@ORA12C> create table dept2 as select * from dept;

Table created.

demo@ORA12C> update dept2 set dname = lower(dname)
  2  where rownum = 1;

1 row updated.

demo@ORA12C> commit;

Commit complete.

demo@ORA12C> select * from dept1;

    DEPTNO DNAME          LOC
---------- -------------- -------------
        10 ACCOUNTING     NEW YORK
        20 RESEARCH       DALLAS
        30 SALES          CHICAGO
        40 OPERATIONS     BOSTON

4 rows selected.

demo@ORA12C> select * from dept2;

    DEPTNO DNAME          LOC
---------- -------------- -------------
        10 accounting     NEW YORK
        20 RESEARCH       DALLAS
        30 SALES          CHICAGO
        40 OPERATIONS     BOSTON

4 rows selected.

demo@ORA12C> select *
  2  from dept1 d1 full outer join dept2 d2
  3  on ( d1.deptno = d2.deptno and
  4   d1.dname = d2.dname and
  5   d1.loc = d2.loc )
  6  where d1.rowid is null or d2.rowid is null ;

    DEPTNO DNAME          LOC               DEPTNO DNAME          LOC
---------- -------------- ------------- ---------- -------------- -------------
                                                10 accounting     NEW YORK
        10 ACCOUNTING     NEW YORK

2 rows selected.

demo@ORA12C>

Chris Saxon
February 01, 2017 - 2:42 pm UTC

Yep, that's another way to do this.

DECODING the FULL OUTER

Duke Ganote, February 01, 2017 - 5:35 pm UTC

Assuming there's a primary key, I prefer the FULL OUTER coupled with DECODE in order to find the detailed discrepancies:

 select coalesce(d1.deptno,d2.deptno) as deptno
      , DECODE(d1.dname,d2.dname,'=',d1.dname||'<>'||d2.dname) as Dname
      , DECODE(d1.loc  ,d2.loc  ,'=',d1.loc  ||'<>'||d2.loc) as Dloc
   from dept1 d1
   full outer
   join dept2 d2
     on d1.deptno = d2.deptno
 order by 1, 2
 /

DEPTNO DNAME                          DLOC
------ ------------------------------ ----------------------------
    10 ACCOUNTING<>accounting         =
    20 =                              =
    30 =                              =
    40 =                              =

RE

GJ, February 02, 2017 - 3:01 am UTC

Another way would be to use UNION ALL with group by.

Check the following link on how to
https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:9531089900346576427#9531095900346064037