テーブルにこのようなデータがあります
NAME PRICE
A 2
B 3
C 5
D 9
E 5
すべての値を 1 行に表示したい。例えば:
A,2|B,3|C,5|D,9|E,5|
Oracle でこのような文字列を取得するクエリを作成するにはどうすればよいですか? 何かにプログラムする必要はありません。その行を結果に表示して、コピーして単語文書に貼り付ける方法が欲しいだけです。
私の Oracle バージョンは 10.2.0.5 です。
テーブルにこのようなデータがあります
NAME PRICE
A 2
B 3
C 5
D 9
E 5
すべての値を 1 行に表示したい。例えば:
A,2|B,3|C,5|D,9|E,5|
Oracle でこのような文字列を取得するクエリを作成するにはどうすればよいですか? 何かにプログラムする必要はありません。その行を結果に表示して、コピーして単語文書に貼り付ける方法が欲しいだけです。
私の Oracle バージョンは 10.2.0.5 です。
-Oracle10g-
SELECT deptno, WM_CONCAT(ename) AS employees
FROM scott.emp
GROUP BY deptno;
Output:
10 CLARK,MILLER,KING
20 SMITH,FORD,ADAMS,SCOTT,JONES
30 ALLEN,JAMES,TURNER,BLAKE,MARTIN,WARD
通常、そのようなものがすぐに必要になり、PL/SQL を使用せずに SQL にとどまりたい場合は、以下のハックに似たものを使用します。
select sys_connect_by_path(col, ', ') as concat
from
(
select 'E' as col, 1 as seq from dual
union
select 'F', 2 from dual
union
select 'G', 3 from dual
)
where seq = 3
start with seq = 1
connect by prior seq+1 = seq
これは、親から子への「パス」を取得するように設計された「sys_connect_by_path」特殊関数を使用する階層クエリです。
ここで行っているのは、seq=1 のレコードが seq=2 のレコードの親であり、4 番目であることをシミュレートし、最後の子 (この場合は seq = 3 のレコード) のフル パスを取得することです。事実上、すべての「col」列の連結になります
あなたのケースに適応:
select sys_connect_by_path(to_clob(col), '|') as concat
from
(
select name || ',' || price as col, rownum as seq, max(rownum) over (partition by 1) as max_seq
from
(
/* Simulating your table */
select 'A' as name, 2 as price from dual
union
select 'B' as name, 3 as price from dual
union
select 'C' as name, 5 as price from dual
union
select 'D' as name, 9 as price from dual
union
select 'E' as name, 5 as price from dual
)
)
where seq = max_seq
start with seq = 1
connect by prior seq+1 = seq
結果は次のとおりです。|A,2|B,3|C,5|D,9|E,5
Oracle 10g を使用しているため、優れたlistagg()
. ただし、他にも多数の文字列集約手法があります。
すべての複雑なものは特に必要ありません。次の表を想定
create table a ( NAME varchar2(1), PRICE number);
insert all
into a values ('A', 2)
into a values ('B', 3)
into a values ('C', 5)
into a values ('D', 9)
into a values ('E', 5)
select * from dual
サポートされていない関数wm_concat
で十分です。
select replace(replace(wm_concat (name || '#' || price), ',', '|'), '#', ',')
from a;
REPLACE(REPLACE(WM_CONCAT(NAME||'#'||PRICE),',','|'),'#',',')
--------------------------------------------------------------------------------
A,2|B,3|C,5|D,9|E,5
ただし、上記のリンクにある Tom Kyte の を変更stragg
して、置換機能なしで行うこともできます。
model
句を使用した別のアプローチを次に示します。
-- sample of data from your question
with t1(NAME1, PRICE) as(
select 'A', 2 from dual union all
select 'B', 3 from dual union all
select 'C', 5 from dual union all
select 'D', 9 from dual union all
select 'E', 5 from dual
) -- the query
select Res
from (select name1
, price
, rn
, res
from t1
model
dimension by (row_number() over(order by name1) rn)
measures (name1, price, cast(null as varchar2(101)) as res)
(res[rn] order by rn desc = name1[cv()] || ',' || price[cv()] || '|' || res[cv() + 1])
)
where rn = 1
結果:
RES
----------------------
A,2|B,3|C,5|D,9|E,5|
次のようなものは、非常に非効率的でテストされていません。
create function foo returning varchar2 as
(
declare bar varchar2(8000) --arbitrary number
CURSOR cur IS
SELECT name,price
from my_table
LOOP
FETCH cur INTO r;
EXIT WHEN cur%NOTFOUND;
bar:= r.name|| ',' ||r.price || '|'
END LOOP;
dbms_output.put_line(bar);
return bar
)
xmlagg を使用してここまでたどり着くことができました: SQL フィドルから oracle 11G を使用します。
データ表:
COL1 COL2 COL3
1 0 0
1 1 1
2 0 0
3 0 0
3 1 0
SELECT
RTRIM(REPLACE(REPLACE(
XMLAgg(XMLElement("x", col1,',', col2, col3)
ORDER BY col1), '<x>'), '</x>', '|')) AS COLS
FROM ab
;
結果:
COLS
1,00| 3,00| 2,00| 1,11| 3,10|