Postgresql GROUP_CONCATと同等ですか?


247

テーブルがあり、フィールド値を連結して、IDごとに1行を取得したいと思います。

私のテーブルでは、たとえば、私はこれを持っています:

TM67 | 4  | 32556
TM67 | 9  | 98200
TM67 | 72 | 22300
TM99 | 2  | 23009
TM99 | 3  | 11200

そして私は出力したいと思います:

TM67 | 4,9,72 | 32556,98200,22300
TM99 | 2,3    | 23009,11200

MySQLでは集約関数を使用できましたGROUP_CONCATが、ここでは機能しないようです... PostgreSQLに相当するもの、またはこれを達成する別の方法はありますか?


答えではありませんが、postgresonline.com / journal / index.php?/ archives /…をチェックしてください。
Kuberchaun、2010



1
最良の答えはまだ別の質問にあると思います:stackoverflow.com/a/47638417/243233
Jus12

回答:


237

これはおそらく良い出発点です(バージョン8.4以降のみ):

SELECT id_field, array_agg(value_field1), array_agg(value_field2)
FROM data_table
GROUP BY id_field

array_aggは配列を返しますが、それをテキストにキャストして、必要に応じて編集できます(以下の説明を参照)。

バージョン8.4以前では、使用する前に自分で定義する必要があります。

CREATE AGGREGATE array_agg (anyelement)
(
    sfunc = array_append,
    stype = anyarray,
    initcond = '{}'
);

(PostgreSQLドキュメントから言い換え)

明確化:

  • 配列をテキストにキャストすると、結果の文字列は中括弧で開始および終了します。これらのブレースが不要な場合は、何らかの方法で削除する必要があります。
  • ANYARRAYをTEXTにキャストすると、CSV出力が最もよくシミュレートされます。埋め込まれたコンマを含む要素は、標準のCSVスタイルの出力で二重引用符で囲まれるからです。array_to_string()もstring_agg()(9.1で追加された「group_concat」関数)も埋め込まれたコンマで文字列を引用しないため、結果のリストの要素数が不正確になります。
  • 新しい9.1 string_agg()関数は、最初に内部結果をTEXTにキャストしません。したがって、「string_agg(value_field)」は、value_fieldが整数の場合にエラーを生成します。「string_agg(value_field :: text)」が必要になります。array_agg()メソッドは、(値ごとのキャストではなく)集計後に1つのキャストのみを必要とします。

1
そして9.0ではlistagg()
Scott Bailey

6
CSVを取得するには、クエリは次のようになります。SELECT id_field、array_to_string(array_agg(value_field1)、 '、')、array_to_string(array_agg(value_field2)、 '、')FROM data_table GROUP BY id_field
Nux

2
ここでは、すべての場合にarray_to_stringを使用することはできません。value_fieldに埋め込まれたコンマが含まれている場合、結果のCSVは正しくありません。array_agg()を使用してTEXTにキャストすると、埋め込まれたコンマで文字列が適切に引用されます。唯一の注意点は、開始と終了の波括弧も含まれているため、「必要に応じて編集する」という私の声明です。その点を明確にするために編集します。
マシューウッド、


255

9.0以降、これはさらに簡単になりました。

SELECT id, 
       string_agg(some_column, ',')
FROM the_table
GROUP BY id

32
構文はまた、(使用して、または、配列、文字列内の値の順序を指定することを可能にすること注array_agg)例えばstring_agg(some_column, ',' ORDER BY some_column)、あるいはstring_agg(surname || ', ' || forename, '; ' ORDER BY surname, forename)
IMSoP

8
これは、その素晴らしいですdistinct1を使用することができますので、string_aggと作品string_agg(distinct some_solumn, ',')
アルン

3
TEXT文字列化できない値(つまりuuid)の場合、列の値をキャストする必要があることに注意してください。これは次のようになりますstring_agg(some_column::text, ',')
ケンドール

48
SELECT array_to_string(array(SELECT a FROM b),', ');

同様に行います。


このコメントのように、特定の順序で集計することはできますか?1つの列によるグループ化と別の列による順序付けをどのように処理しますか(たとえば、縦方向のデータセット内の変数を連結するため)。
マイケルA

15

このようにしてみてください:

select field1, array_to_string(array_agg(field2), ',')
from table1
group by field1;

2

配列タイプで機能するバージョン:

select
  array_to_string(
    array(select distinct unnest(zip_codes) from table),
    ', '
);

重複答え、@max_spyは5年前に同じことを言った
エミールVikström

@EmilVikström:あなたは間違っている権利がありますが、注意深く読んでください。それは異なるだけでなく、配列タイプで動作する例を示しました-zip_codesのようにcharacter varying(5)[]。また、私は目的のためにネストを解除する必要があることを確認しましたERROR: cannot accumulate arrays of different dimensionality。それ以外の場合は、
SławomirLenart

1

postgresqlでの私の提案

SELECT cpf || ';' || nome || ';' || telefone  
FROM (
      SELECT cpf
            ,nome
            ,STRING_AGG(CONCAT_WS( ';' , DDD_1, TELEFONE_1),';') AS telefone 
      FROM (
            SELECT DISTINCT * 
            FROM temp_bd 
            ORDER BY cpf DESC ) AS y
      GROUP BY 1,2 ) AS x   

1
なぜORDER BY内部クエリで行うのですか?とにかく注文が失われませんか?
mypetlion 2018年

-1

以下のOracleクエリが機能することを願っています。

Select First_column,LISTAGG(second_column,',') 
    WITHIN GROUP (ORDER BY second_column) as Sec_column, 
    LISTAGG(third_column,',') 
    WITHIN GROUP (ORDER BY second_column) as thrd_column 
FROM tablename 
GROUP BY first_column

rextester.com/l/postgresql_online_compilerでテストしましたが動作しませんでした:42883:関数listagg(text、unknown、text)が存在しません
マヌエルロミロ

Oracleには、postgresとは異なる構文と機能があります。
Herman J. Radtke III
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.