6

これに触れる複数のトピックがあることは知っています。しかし、私のニーズに対応するものは見つかりませんでした。(オンデマンドで) 選択したディープ テーブル データをワイド出力テーブルにピボットする必要があります。ここでの落とし穴は、出力で必要な応答を消費するため、ピボットで集計を使用できないことです。私は解決策に取り組みましたが、機能するには多数の左結合が必要になるため、それが最善だとは思いません。次のように、すべての試行とメモを含めました。

-- SQL Server 2008 データベース。
-- 深いテーブル構造 (変更の対象外) には、userId を持つ名前と値のペアが含まれています。
-  外部キー。多くの場合、ユーザーによって指定された複数の itemValue が
-- 人種を尋ねられた場合などの itemName は、白人 + ヒスパニックなどと答えることができます。それぞれの回答が保存されます。
-- 別のレコードとして - これは現在変更できません。

-- 目標: 結果を圧縮しながら、ディープ データをワイドにピボットする
――下ろす。userId ごとにすべてのアイテムを考慮し、複製する
-- 必要に応じて列の値 (null を表示するのではなく)

-- 単一回答と複数回答の両方のデータを格納するサンプル テーブル
DECLARE @testTable AS TABLE(userId int, itemName varchar(50), itemValue varchar(255))

@testTable に挿入
SELECT 1, 'q01', '1-q01 回答'
UNION SELECT 1、「q02」、「1-q02 アンサー」
UNION SELECT 1、「q03」、「1-q03 回答 1」
UNION SELECT 1、「q03」、「1-q03 回答 2」
UNION SELECT 1、「q03」、「1-q03 回答 3」
UNION SELECT 1、「q04」、「1-q04 ​​アンサー」
UNION SELECT 1, 'q05', '1-q05 アンサー'
UNION SELECT 2、「q01」、「2-q01 アンサー」
UNION SELECT 2、「q02」、「2-q02 アンサー」
UNION SELECT 2、「q03」、「2-q03 回答 1」
UNION SELECT 2、「q03」、「2-q03 回答 2」
UNION SELECT 2、「q04」、「2-q04 ​​アンサー」
UNION SELECT 2、「q05」、「2-q05 アンサー」

「生データ」を選択
SELECT * @TestTable から

SELECT 'Pivot を使用 - itemName ごとに itemValue の集計結果を表示 - 他を食べる'
; WITH データ AS (
    選択する
        [ユーザーID]
        、 [項目名]
        、[アイテム値]
    から
        @テストテーブル
)
選択する
    [ユーザーID]
    、[q02]
    、[q03]
    、[q05]
から
    データ
ピボット
(
    MIN(itemValue) -- 集計関数が必要な値を消費します。
    FOR itemName in ([q02]、[q03]、[q05])
) AS ピボットテーブル


SELECT 'グループ化による集計 - NULL 値の原因'
選択する
    DISTINCT ユーザー ID
    ,[q02] = Max(CASE WHEN itemName = 'q02' THEN itemValue END)
    ,[q03] = Max(CASE WHEN itemName = 'q03' THEN itemValue END)
    ,[q05] = Max(CASE WHEN itemName = 'q05' THEN itemValue END)
から
    @テストテーブル
どこ
    itemName in ('q02', 'q03', 'q05') -- 髪を速くします
グループ化
    userId -- userId のみの場合、1 行の PERIOD = BAD のみが返されます!!
    、 [項目名]
    、[アイテム値]


SELECT '複数の左結合 - 正常に動作しますが、175 列程度をピボットするとうまくいきません'
; WITH データ AS (
    選択する
        ユーザーID
        、[項目名]
        ,[アイテム値]
    から
        @テストテーブル
    どこ
        itemName in ('q02', 'q03', 'q05') -- 髪を速くします
)
選択する
    DISTINCT s1.userId
    ,[q02] = s2.[アイテム値]
    ,[q03] = s3.[アイテム値]
    ,[q05] = s5.[アイテム値]
から
    データ s1
    LEFT JOIN データ s2
        ON s2.userId = s1.userId
            AND s2.[アイテム名] = 'q02'
    LEFT JOIN データ s3
        ON s3.userId = s1.userId
            AND s3.[アイテム名] = 'q03'
    LEFT JOIN データ s5
        ON s5.userId = s1.userId
            AND s5.[アイテム名] = 'q05'

したがって、一番下のクエリは、必要なことを実行する (これまでのところ) 唯一のクエリですが、実際のアイテム名を使用してピボットすると、LEFT JOIN が手に負えなくなり、パフォーマンスの問題が発生します。任意の推奨事項をいただければ幸いです。

4

3 に答える 3

3

結合は、まさにあなたが求めているような結果を生み出す方法であるため、結合に固執する必要があると思います。結合の目的は、行セットを(条件付きまたは条件なしで)結合することであり、ターゲット出力は行のサブセットの組み合わせに他なりません。

ただし、質問の大部分が常に単一の回答である場合は、必要な結合の数を大幅に減らすことができます。アイデアは、複数の応答グループのみを個別の行セットとして参加させることです。シングルレスポンスアイテムに関しては、ターゲットアイテムのデータセット全体の一部としてのみ結合されます。

例は、私が口頭でうまく説明できないかもしれないことをよりよく説明するはずです。ソースデータに2つの潜在的に複数の応答グループがあると仮定すると'q03''q06'(実際には、ソーステーブルは次のとおりです。

DECLARE @testTable AS TABLE(
  userId int,
  itemName varchar(50),
  itemValue varchar(255)
);

INSERT INTO @testTable
SELECT 1, 'q01', '1-q01 Answer'
UNION SELECT 1, 'q02', '1-q02 Answer'
UNION SELECT 1, 'q03', '1-q03 Answer 1'
UNION SELECT 1, 'q03', '1-q03 Answer 2'
UNION SELECT 1, 'q03', '1-q03 Answer 3'
UNION SELECT 1, 'q04', '1-q04 Answer'
UNION SELECT 1, 'q05', '1-q05 Answer'
UNION SELECT 1, 'q06', '1-q06 Answer 1'
UNION SELECT 1, 'q06', '1-q06 Answer 2'
UNION SELECT 1, 'q06', '1-q06 Answer 3'
UNION SELECT 2, 'q01', '2-q01 Answer'
UNION SELECT 2, 'q02', '2-q02 Answer'
UNION SELECT 2, 'q03', '2-q03 Answer 1'
UNION SELECT 2, 'q03', '2-q03 Answer 2'
UNION SELECT 2, 'q04', '2-q04 Answer'
UNION SELECT 2, 'q05', '2-q05 Answer'
UNION SELECT 2, 'q06', '2-q06 Answer 1'
UNION SELECT 2, 'q06', '2-q06 Answer 2'
;

これは元の投稿の表と同じですが、'q06'項目が追加されています)、結果のスクリプトは次のようになります。

WITH ranked AS (
  SELECT
    *,
    rn = ROW_NUMBER() OVER (PARTITION BY userId, itemName ORDER BY itemValue)
  FROM @testTable
),
multiplied AS (
  SELECT
    r.userId,
    r.itemName,
    r.itemValue,
    rn03 = r03.rn,
    rn06 = r06.rn
  FROM ranked r03
    INNER JOIN ranked r06 ON r03.userId = r06.userId AND r06.itemName = 'q06'
    INNER JOIN ranked r ON r03.userId = r.userId AND (
      r.itemName = 'q03' AND r.rn = r03.rn OR
      r.itemName = 'q06' AND r.rn = r06.rn OR
      r.itemName NOT IN ('q03', 'q06')
    )
  WHERE r03.itemName = 'q03'
    AND r.itemName IN ('q02', 'q03', 'q05', 'q06')
)
SELECT userId, rn03, rn06, q02, q03, q05, q06
FROM multiplied
PIVOT (
  MIN(itemValue)  
  FOR itemName in (q02, q03, q05, q06)
) AS PivotTable
于 2011-10-25T17:43:46.780 に答える
3
; WITH SRData AS (
    SELECT -- このブロック内の単一の応答アイテムのみをクエリします
        [ユーザーID]
        、[q01]
        、[q02]
        、[q04]
        、[q05]
    から
        @テストテーブル
    ピボット
    (
        MIN(アイテム値)
        FOR itemName in ([q01]、[q02]、[q04]、[q05])
    ) AS ピボットテーブル
)
選択する
    sr.[ユーザーID]
    、シニア[q01]
    、シニア[q02]  
    、[q03] = mr03.[itemValue]
    、シニア[q04]      
    、シニア[q05]      
    、[q06] = mr06.[itemValue]
から
    SRData sr
    LEFT JOIN @testTable mr03 ON mr03.userId = sr.userId AND mr03.itemName = 'q03' -- q03 の Muli 応答
    LEFT JOIN @testTable mr06 ON mr06.userId = sr.userId AND mr06.itemName = 'q06' -- q06 の Muli 応答

于 2011-10-25T19:59:51.450 に答える