web-dev-qa-db-ja.com

Sqlitegroup_concatの順序

Sqliteでは、group_concatを使用して次のことを実行できます。

1...A
1...B
1...C
2...A
2...B
2...C

1...C,B,A
2...C,B,A

しかし、連結の順序はランダムです-ドキュメントによると。

Group_concatの出力を次のように並べ替える必要があります

1...A,B,C
2...A,B,C

これどうやってするの?

41
user230781

のorderby句で副選択を使用してから、値をグループ連結することはできませんか?

何かのようなもの

SELECT ID, GROUP_CONCAT(Val)
FROM (
   SELECT ID, Val
   FROM YourTable
   ORDER BY ID, Val
   )
GROUP BY ID;
66
Adriaan Stander

より正確には、 docs によると:

連結された要素の順序は任意です。

これは実際にはランダムを意味するのではなく、開発者が希望する順序を使用する権利を留保することを意味します。クエリごとに、またはSQLiteバージョンごとに異なる順序であっても使用できます。

現在のバージョンでは、この順序は、Adrian Standerのコードが機能しているように見えるため、AdrianStanderの回答によって暗示される順序である可能性があります。したがって、いくつかのユニットテストで身を守り、それを1日と呼ぶかもしれません。しかし、SQLiteのソースコードを詳しく調べないと、これが常に機能することを100%確信することはできません。

ソースからSQLiteをビルドする場合は、独自の ユーザー定義の集計関数 を作成することもできますが、もっと簡単な方法があります。

幸い、バージョン3.25.0以降、 ウィンドウ関数 があり、問題の解決策はやや醜いものの、動作が保証されています。

ドキュメントでわかるように、Windows関数には独自のORDER BY句があります。

上記の例では、ウィンドウフレームは、前の行( "1 PRECEDING")と次の行( "1 FOLLOWING")の間のすべての行で構成され、行はwindow-defnのORDERBY句に従って並べ替えられます。 (この場合は「ORDERBYa」)。

これだけでは、必ずしもすべての集計関数が順序を尊重することを意味するわけではないことに注意してくださいinsideウィンドウフレームですが、 ユニットテスト を見ると、これが実際に当てはまることがわかります。

do_execsql_test 4.10.1 {
  SELECT a, 
    count() OVER (ORDER BY a DESC),
    group_concat(a, '.') OVER (ORDER BY a DESC) 
  FROM t2 ORDER BY a DESC
} {
  6 1 6
  5 2 6.5
  4 3 6.5.4
  3 4 6.5.4.3
  2 5 6.5.4.3.2
  1 6 6.5.4.3.2.1
  0 7 6.5.4.3.2.1.0
}

だから、それを要約すると、あなたは書くことができます

SELECT ID, GROUP_CONCAT(Val) OVER (PARTITION BY ID ORDER BY Val) FROM YourTable;

その結果:

1|A
1|A,B
1|A,B,C
2|A
2|A,B
2|A,B,C

残念ながら、これには目的の集計のすべてのプレフィックスも含まれています。代わりに、常に全範囲を含むようにウィンドウフレームを指定してから、次のように冗長な値を破棄します。

SELECT DISTINCT ID, GROUP_CONCAT(Val)
OVER (PARTITION BY ID ORDER BY Val ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
FROM YourTable;

またはこのように:

SELECT * FROM (
    SELECT ID, GROUP_CONCAT(Val)
    OVER (PARTITION BY ID ORDER BY Val ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
    FROM YourTable
)
GROUP BY ID;
1
szmate1618