2017-08-26 16 views
1

私はアクセスが非常に新しいので、次の要件で誰かが私を助けてくれるのだろうかと思っていました。テーブル値を抽出するクエリを作成しようとすると、それらを一意の識別子(ID)でグループ化された同じ行に結合します。複数の行を一意のキーで列に変換

クロス集計クエリを使用しようとしましたが、計算を実行したり、PIVOT機能を使用しているように見えますが、要件を満たしていないようです。

本当にありがとうございました。以下のデータの例を参照してください。

マイデータは、ハリケーンを待って、次のフォーマット

屋内
ID EMAIL     COMMENTS 
1  [email protected]  <TEXT> 
1  [email protected]  <TEXT> 
2  [email protected]  <TEXT> 
2  [email protected]  <TEXT> 
2  [email protected]  <TEXT> 

所望の出力

ID COL1    COL2 COL3    COL4 COLN     COLN+1 
1 [email protected] <TEXT> [email protected] <TEXT> 
2 [email protected] <TEXT> [email protected] <TEXT> [email protected]  <TEXT> 
+0

あなたのデータにはNがありますか?アクセスには255列の本来の制限があります。 –

+0

元のデータには他の固有のキーがありますか? IDは一意ではないが、電子メールアドレスとコメントのソースには別の固有のキーがあるのだろうか? –

+0

Nothing/255に達してはいけません。私の現在のソースを調べると最高のものは155です。私はデータを使って新しいテーブルを作成し、新しい行を作成するために新しい自動生成キーを追加できます。これは役に立ちますか? –

答えて

1

今日を持っているので、私は、私はこのカスタムソリューションを作成したい考え出し。これらのステップのすべての回答は他の場所にありますが、すべての考案されたソリューションを分類するのは簡単ではありませんでした。

行を列に変更する基本的な答えはhereです。しかし、この質問のデータとは異なり、その回答のサンプルデータはすでに適切に順序付けられていました。列値[ID]と[電子メール]が一意のペアを形成し、NULL値を持たない限り、集約サブクエリまたはAccess集計関数の呼び出しを使用して適切な順序を生成することが可能です。クエリの全体数を減らすために、私は先に進み、同じクエリで変換された列名を生成しました。値が一意でないか、またはヌル値を持つ場合、シーケンシングはオフになり、最終結果にはデータが欠落します。 Access SQL Transformステートメント(クロス集計クエリ)では、クエリごとに1つの変換列しか使用できません。 2つの別々のクエリを作成して結合するのは簡単ですが、クロス集計クエリでは動的な(つまり未定義の)数の列が生成されるため、各列を順番に選択することなく電子メールとコメントの列をインターリーブすることはできません。さらに、問合せにどの列が含まれているかを明示的に指定すると、クロス集計問合せの動的な側面が破壊され、追加の列が残されるか、全体の列数が減るとエラーが発生します。

UPDATE:ちょうど(今ソリューション2ラベル)元の溶液を掲示した後、私は実際に後方に一歩を行くことによって、列インターリーブ問題を解決することができることを実現... は最初以上の行 --one列を生成します最終的な変換の前に、それらを同じ行にまとめて配置します。

ソリューション1

次のクエリを保存し、[シーケンス・]という名前を付けます。[後方]

SELECT Data.ID, Data.Email, Data.Comments, 
    1 + DCount("[ID]","Data","[ID]=" & [ID] & " and [Email]<'" & Replace([Email],"'","''") & "'") AS SeqNum, 
    Format([SeqNum],"000") & ' Email' AS EmailColumn, 
    Format([SeqNum],"000") & ' Remark' AS CommentsColumn 
FROM Data 
ORDER BY Data.ID, Data.Email; 

保存し、次のクエリと名前それ::それは[メール]の後にソートしますので、最終的な出力で正しい列の順序を容易にするために、私は言葉の代わりに「コメント」の「備考」を使用

SELECT ID, EmailColumn AS ColumnName, Email AS [Value] 
FROM Sequenced 
UNION SELECT ID, CommentsColumn AS ColumnName, Comments AS [Value] 
FROM Sequenced 
ORDER BY [ID], [ColumnName]; 

保存し、次のクエリと[InterleavedCrosstab]という名前を付けます:

TRANSFORM First(Backwards.Value) AS FirstOfValue 
SELECT Backwards.ID 
FROM Backwards 
GROUP BY Backwards.ID 
ORDER BY Backwards.ID, Backwards.ColumnName 
PIVOT Backwards.ColumnName; 

ソリューション2

保存し、次のクエリと名前を付け、[Sequenced2]:

SELECT Data.ID, Data.Email, Data.Comments, 
    1 + DCount("[ID]","Data","[ID]=" & [ID] & " and [Email]<'" & Replace([Email],"'","''") & "'") AS SeqNum, 
    'Email' & Format([SeqNum],"000") AS EmailColumn, 
    'Comments' & Format([SeqNum],"000") AS CommentsColumn 
FROM Data 
ORDER BY Data.ID, Data.Email; 

保存し、次のクエリと名前を付け、[EmailCrosstab]:

TRANSFORM First(Sequenced2.Email) AS FirstOfEmail 
SELECT Sequenced2.ID 
FROM Sequenced2 
GROUP BY Sequenced2.ID 
ORDER BY Sequenced2.ID 
PIVOT Sequenced2.EmailColumn; 

保存し、次のクエリと名前を[CommentsCrosstab] :

TRANSFORM First(Sequenced2.Comments) AS FirstOfComments 
SELECT Sequenced2.ID 
FROM Sequenced2 
GROUP BY Sequenced2.ID 
ORDER BY Sequenced2.ID 
PIVOT Sequenced2.CommentsColumn; 

最後に、最も一般的な結果のクエリはすべての列を返しますが、それらはインターリーブされません。 [ID]列が重複します:

SELECT EmailCrosstab.*, 
     CommentsCrosstab.* 
FROM CommentsCrosstab INNER JOIN EmailCrosstab 
    ON CommentsCrosstab.ID = EmailCrosstab.ID; 

ここで清書版だが、わずか3電子メールやコメントの列まであります。私が持っていた

SELECT EmailCrosstab.ID, 
    EmailCrosstab.Email001,CommentsCrosstab.Comments001, 
    EmailCrosstab.Email002,CommentsCrosstab.Comments002, 
    EmailCrosstab.Email003,CommentsCrosstab.Comments003 
FROM CommentsCrosstab INNER JOIN EmailCrosstab 
    ON CommentsCrosstab.ID = EmailCrosstab.ID; 

ソリューション3

は、クエリのみのソリューションがかなり簡単であることを認識したときに、既に以下のVBAプロシージャを入力しています。

Public Sub CustomTransform() 
    '* This code assumes that the field values 
    '* [ID] and [Email] constitute a unique pair 
    '* and that there are NO NULL values. 

    Dim i As Integer, MaxIDRows As Integer 
    Dim IDSeq As Integer 
    Dim lastID As Long 
    Dim IDstring As String 
    Dim tbl As TableDef 
    Dim idx As Index 
    Dim db As Database 
    Dim rsSrc As Recordset2, rsResult As Recordset2 
    Const resultTable As String = "Customer Crosstab" 

    Set db = CurrentDb 

    MaxIDRows = db.OpenRecordset(_ 
     "SELECT Max(Counter.Rows) AS MaxRows" & _ 
     " FROM (SELECT Count(Data.[ID]) AS [Rows]" & _ 
     " FROM Data GROUP BY Data.[ID]) AS Counter" _ 
    ).Fields(0).Value 

    '* Column count <= 254 : ID + N * (Email + Comment columns) 
    If MaxIDRows = 0 Then 
    MsgBox "No data.", vbOKOnly Or vbExclamation, "No Data" 
    Exit Sub 
    ElseIf MaxIDRows >= 252/2 Then 
    MsgBox "Maximum number of columns exceeded.", _ 
     vbOKOnly Or vbExclamation, "Maximum Columns Exceeded" 
    Exit Sub 
    End If 

    On Error Resume Next 
    db.TableDefs.Delete resultTable 
    Err.Clear 
    On Error GoTo 0 

    Set tbl = db.CreateTableDef(resultTable) 
    With tbl 
    ' Create fields and append them to the new TableDef 
    ' object. This must be done before appending the 
    ' TableDef object to the TableDefs collection of the 
    ' Northwind database. 
    .Fields.Append .CreateField("ID", dbLong) 

    For i = 1 To MaxIDRows 
     IDstring = Format(i, "000") 
     .Fields.Append .CreateField("Email" & IDstring, dbText, 255) 
     .Fields.Append .CreateField("Comments" & IDstring, dbText, 255) 
    Next 

    Set idx = .CreateIndex("Primary Key") 
    idx.Fields.Append idx.CreateField("ID") 
    idx.Primary = True 
    .Indexes.Append idx 
    End With 
    db.TableDefs.Append tbl 

    Set rsResult = db.OpenRecordset(resultTable, dbOpenTable) 
    Set rsSrc = db.OpenRecordset(_ 
     "SELECT ID, Email, Comments" & _ 
     " FROM Data" & _ 
     " ORDER BY ID, Email") 

    lastID = -1 
    Do Until rsSrc.EOF 
    If rsSrc!id <> lastID Then 
     If lastID <> -1 Then 
     rsResult.Update 
     End If 

     IDSeq = 0 
     rsResult.AddNew 
     rsResult!id = rsSrc!id 
    End If 
    lastID = rsSrc!id 

    IDSeq = IDSeq + 1 
    IDstring = Format(IDSeq, "000") 

    rsResult.Fields("Email" & IDstring) = rsSrc!email 
    rsResult.Fields("Comments" & IDstring) = rsSrc!Comments 

    rsSrc.MoveNext 
    Loop 
    rsSrc.Close 

    If rsResult.EditMode <> dbEditNone Then 
    rsResult.Update 
    End If 
    rsResult.Close 

    Debug.Print "CustomTransform Done" 
End Sub 
関連する問題