| Groupid | アイテム |
|---|---|
| 1 | AAA |
| 2 | IS |
| 5 | あー |
| 2 | なに |
| 2 | THE |
| 1 | これ |
| Groupid | アイテムリスト |
|---|---|
| 1 | AAA、これ |
| 2 | ある、何、 |
| 5 | あー |
SELECT GroupId、GROUP_CONCAT(Item SEPARATOR "、")AS ItemList アイテムから
MS SQL Server'eにはそのような機能はないので、倒錯する必要があります。 開始する前に、テストテーブルを作成するスクリプトを作成します。
CREATE TABLEアイテム(GroupId INT、アイテムNVARCHAR(10)) INSERT INTO Items(GroupId、Item) SELECT 1 AS GroupId、 'AAA' AS Item UNION ALL SELECT 2、「IS」 UNION ALL 選択5、「OMG」 UNION ALL 選択2、「何」 UNION ALL SELECT 2、「THE」 UNION ALL SELECT 1、「これ」
それでは始めましょう。
最も愚かな簡単な方法は、一時テーブルを作成し、その中に集計の中間結果を収集し、Itemsテーブル上でカーソルを実行することです。 このメソッドの動作は非常に遅く、そのコードは恐ろしいものです。 感心する:
DECLARE @Aggregated TABLE(GroupId INT、ItemList NVARCHAR(100))
DECLARE ItemsCursor CURSOR READ_ONLY
FOR SELECT GroupId、アイテム
アイテムから
DECLARE @CurrentGroupId INT
DECLARE @CurrentItem NVARCHAR(10)
DECLARE @CurrentItemList NVARCHAR(100)
アイテムを開くカーソル
ItemsCursorから次をフェッチ
INTO @ CurrentGroupId、@ CurrentItem
@@ FETCH_STATUS = 0の場合
開始
SET @CurrentItemList =(SELECT ItemList
FROM @Aggregated
WHERE GroupId = @CurrentGroupId)
IF @CurrentItemList IS NULL
INSERT INTO @Aggregated(GroupId、ItemList)
値(@ CurrentGroupId、@ CurrentItem)
その他
UPDATE @Aggregated
SET ItemList = ItemList + '、' + @CurrentItem
WHERE GroupId = @CurrentGroupId
ItemsCursorから次をフェッチ
INTO @ CurrentGroupId、@ CurrentItem
終了
アイテムを閉じるカーソル
アイテムの割り当て解除カーソル
SELECT GroupId、ItemList
FROM @Aggregated
一時テーブルを使用しない、より美しい方法があります。 SELECTトリックvar = var + '、' + col FROM smwhereに基づいています。 はい、可能であり、機能します。
CREATE FUNCTION ConcatItems(@GroupId INT)
戻り値NVARCHAR(100)
として
開始
DECLARE @ItemList varchar(8000)
SET @ItemList = ''
SELECT @ItemList = @ItemList + '、' +アイテム
アイテムから
WHERE GroupId = @GroupId
部分文字列を返す(@ ItemList、2、100)
終了
行く
SELECT GroupId、dbo.ConcatItems(GroupId)ItemList
アイテムから
GROUP BY GroupId
少し良くなりましたが、それでも松葉杖です。 集約された行の最大数が制限されていることがわかっている場合、次の方法を使用できます(このクエリは、4つを超える要素を持つグループがないという仮定に基づいています)。
SELECT GroupId、
ケースItem2 WHEN '' THEN Item1
その他のケースItem3 WHEN '' THEN Item1 + '、' + Item2
その他のケースItem4 WHEN '' THEN Item1 + '、' + Item2 + '、' + Item3
ELSE Item1 + '、' + Item2 + '、' + Item3 + '、' + Item4
END END END AS ItemList
FROM(
SELECT GroupId、
MAX(ケースItemNo WHEN 1 THEN Item ELSE '' END)AS Item1
MAX(アイテム2の場合、アイテムELSE ''終了)の場合、アイテム2、
MAX(ケースItemNo WHEN 3 THEN Item ELSE '' END)AS Item3、
MAX(ケースItemNo WHEN 4 THEN Item ELSE '' END)AS Item4
FROM(
SELECT GroupId、
アイテム、
ROW_NUMBER()OVER(PARTITION BY GroupId ORDER BY Item)ItemNo
アイテムから
)AS OrderedItems
GROUP BY GroupId
)AS AlmostAggregated
はい、たくさんのコード。 ただし、データベース内の単一の余分なオブジェクトは、1つの純粋な選択ではありません。 これは時々重要です。
ただし、単一のリクエストのフレームワーク内に留まりながら、グループサイズの制限を回避する方法があります。 グループのすべての要素をXMLフィールドに収集し 、それを文字列型に変換して、要素間のタグをコンマに置き換えます。
SELECT GroupId、
REPLACE(SUBSTRING(ItemListWithTags、4、LEN(ItemListWithTags)-7)、
'<a>'、
'、')AS ItemList
FROM(
SELECT GroupId、
CAST(XmlItemList AS NVARCHAR(200))ItemListWithTags
FROM(
SELECT GroupId、
(SELECT AS AS A
FROMアイテムii
WHERE ii.GroupId = GroupIds.GroupId
FOR XML PATH( ''))AS XmlItemList
FROM(SELECT DISTINCT GroupId FROM Items)AS GroupIds
)AS subq1
)AS subq2
一般に、それは非常に高速ではありませんが、常に動作します。 そして、もちろん、2000以上のSQL Serverが必要です。
はい、 CLR Aggregate Functionsを介して行を集計する方法はまだありますが、これは一般的に恐ろしいことです。なぜなら、死は遅く、タスクの複雑さにとって重要ではないからです。 そのような記事に十分な需要がある場合は、後で書きます。
コメントと批判を楽しみにしています。 そしてもう1つ、私が家でやったようなコードを強調表示する方法を誰かが知っているなら、教えてください 。 私は、スクリーンショットを挿入する方法を除いて、これまでの別の方法を参照してください。