2

3 つのテーブルがあるという問題に直面しています。供給倉庫にその品目がない (削除された) 場合、または設定さえない場合は表示されますが、ソース マトリックスによると供給倉庫である必要があります。

単純化されたレイアウトはそのように見えるはずです。

テーブルのメインデータ

  • Field ItemNo - 個別の識別子、重複なし (PK)
  • Field ItemType - 特定の選択があり、特定の値をフィルタリングする必要があります。

テーブルWarehouseData

  • Field ItemNo - MainData に関連付けられていますが、PK は次のフィールドと結合されています
  • Field ItemLocation - ItemNo で記述されたそのようなアイテムの特定の場所を与える
  • フィールドItemCategory - SourceWHMatrix に参加する必要があります
  • Field ItemDeleted - char フィールドです (エクスポートされたデータのため)。アイテムが「削除」された場合、値は「X」、それ以外の場合は Null (空ではありません!)

テーブルソースWHMatrix

  • フィールドItemLocation - 最初の 2 つのフィールドは主キーです
  • フィールドItemCategory
  • フィールドSourceLocation - 商品の配送先を指定する必要があります

以下を確認する必要があります: ItemNoが特定のItemType (MainData テーブル)に属し、かつ ItemDeletedが Null である場合、このItemNoSourceLocationにあるかどうか (これは、 ItemLocation AND ItemCategoryに基づいてSourceWHMatrixによって決定されます)。SourceLocationで「削除」されたすべてのItemNoをリストする必要があります(この場合、テーブルWarehouseDataフィールドのItemLocationで、返されたSourceLocation値がチェックされます)、またはそのような場所に設定されていません。

注:異なるItemLocationの同じItemNoの場合、ItemCategoryは常に一致するとは限りません。また、すべてのItemLocationには、ソース倉庫を決定するためのさまざまなItemCategoryがあります。

LEFT JOIN の多くの組み合わせを試してみましたが、どういうわけか、セットアップされていない値をリストできないようです。(WarehouseData の複製テーブルを作成することで、供給倉庫で削除されたアイテムをリストすることができました。) また、ADODB を使用して VBA でこれを行うこともできましたが、すべてを SQL コードに保持し、カスタム関数を使用することさえしたくありません。これは Access 2010 にあり、JET SQL エンジンで実行されています。

これは機能しない現在のクエリです

SELECT MD.itemno, 
       MD.itemtype, 
       WD.itemlocation, 
       SMat.sourcelocation, --this could be empty
       WD.itemdeleted AS "SourceWHDelFlag" 
FROM   maindata AS MD 
       INNER JOIN (warehousedata AS WD 
                   INNER JOIN (sourcewhmatrix AS SMat 
                               LEFT JOIN wd 
                                      ON SMat.sourcelocation = WD.itemlocation) 
                           ON ( WD.itemlocation = SMat.itemlocation 
                                AND WD.itemcategory = SMat.itemcategory ) ) 
               ON MD.itemno = WD.itemno 
WHERE  ( MD.itemtype = 'Value1' 
          OR MD.itemtype = 'Value2' ) 

これは、さらに考えた結果、私が思いついたものです。ただし、私の i5 では、クエリが 20 分間実行されています。したがって、これは最適ではありません。また、Access のいくつかの事前結果を確認できたときに、エイリアスのステートメントを where 句に追加すると、同じ where 句内の他のフィールドで適切にフィルター処理されなくなったため、バグが発生したように見えました。これが私の「解決策」です:

SELECT MD.ItemNo,
       MD.ItemType
       WD.itemlocation, 
       SMat.sourcelocation, --this could be empty
       (SELECT WD.ItemDeleted FROM WD WHERE WD.ItemNo = MD.ItemNo) AS "SourceWHDelFlag"
FROM MainData AS MD INNER JOIN (WarehouseData AS WD
                                LEFT JOIN SourceWHMatrix AS SMat
                                       ON (WD.ItemLocation = SMat.ItemLocation
                                           AND WD.ItemCategory = SMat.ItemCategory))
                                ON MD.ItemNo = WD.ItemNo
WHERE (MD.ItemType = 'Value1' OR MD.ItemType = 'Value2')
      AND WD.ItemDeleted Is Null
      AND WD.ItemCategory Is Not Null
      AND WD.ItemCategory Not Like '##' -- This is another filter value, and it seems to be buggy
                                        -- with SELECT clause in WHERE statement
      AND (SELECT WD.ItemDeleted FROM WD WHERE WD.ItemNo = MD.ItemNo) Is Not Null

事前にご協力いただきありがとうございます。

更新 私はいくつかの VBA を実行しましたが、このコードは実際に機能しています。コードに必要なすべての情報をコメントしましたが、それでも非常に遅いです。(合理的な時間枠内で実行を大幅に高速化するアイデアがある場合は、私はそれを受け入れます。) 200 レコードの実行には約 10 分かかりました。したがって、16 ~ 17,000 レコードで実行するには 15 時間かかるはずです。VLookupを使用すると、Excelでこれをはるかに高速に実行できます...

Private Sub Command0_Click()

'initialize variables
Dim connDB As ADODB.Connection
Dim filtRecSet As ADODB.Recordset
Dim tmpRecSet As ADODB.Recordset
Dim tmpLineText As String
Dim tmpCounter As Integer
Dim filePath As String
Dim tmpFSO As New FileSystemObject
Dim tmpStream As TextStream
Dim startTime, endTime As Double

'set values
Set connDB = New ADODB.Connection
Set connDB = CurrentProject.Connection
Set filtRecSet = New ADODB.Recordset
Set tmpRecSet = New ADODB.Recordset
filePath = "C:\data\output.txt"
Set tmpStream = tmpFSO.CreateTextFile(filePath, True)

startTime = Now()

'this is a test database
'I previously deleted all not required MD.ItemType to test speed of SQL queries
'it's the reason for no filtering on MD.ItemType

'open base recordset, which are not deleted (WD.ItemDeleted)
'and belong tospecific MD.ItemType values
'and can match certain filters on WD.ItemCategory
With filtRecSet
    .ActiveConnection = connDB
    .Source = "SELECT MD.ItemNo, WD.ItemLocation, MD.ItemType, WD.ItemCategory, SMat.SourceLocation FROM MainData As MD INNER JOIN (WarehouseData As WD LEFT JOIN SourcwWHMatrix As SMat ON (WD.ItemLocation = SMat.ItemLocation AND WD.ItemCategory = SMat.ItemCategory)) ON MD.ItemNo = WD.ItemNo WHERE WD.ItemCategory Is Not Null AND WD.ItemCategory Not Like '[0-9][0-9]' AND WD.ItemDeleted Is Null"
    .LockType = adLockOptimistic
    .CursorType = adUseClient
End With
'RecordCount: 16610

'open control recordset for all appropiate MD.ItemType
With tmpRecSet
    .ActiveConnection = connDB
    .Source = "SELECT MD.ItemNo, WD.ItemLocation, MD.ItemType, WD.ItemCategory, SMat.SourceLocation FROM MainData As MD INNER JOIN (WarehouseData As WD LEFT JOIN SourcwWHMatrix As SMat ON (WD.ItemLocation = SMat.ItemLocation AND WD.ItemCategory = SMat.ItemCategory)) ON MD.ItemNo = WD.ItemNo"
    .LockType = adLockOptimistic
    .CursorType = adUseClient
    .Filter = adFilterNone
End With
'RecordCount: 138713

filtRecSet.Open
'tmp variable to see how many records have been processed
tmpCounter = 1
If Not filtRecSet.EOF Then
    'select first record
    filtRecSet.MoveFirst
    Do While Not filtRecSet.EOF
        'find SourceLocation
        tmpRecSet.Filter = "MATNR = '" & filtRecSet(0).Value & "' AND WERKS = '" & filtRecSet(5).Value & "'"
        tmpRecSet.Open
        'check how many records in recordset; there should not be more than one, that's why it considered as error
        If tmpRecSet.RecordCount = 1 Then
            tmpRecSet.MoveFirst
            tmpLineText = filtRecSet(0).Value & "|" & filtRecSet(1).Value & "|" & filtRecSet(2).Value & "|" & filtRecSet(3).Value & "|" & filtRecSet(4).Value & "|" & filtRecSet(5).Value & "|" & tmpRecSet(3).Value
        ElseIf tmpRecSet.RecordCount > 1 Then
            tmpLineText = "ERROR"
        'in case EOF is True -> no records
        Else
            tmpLineText = filtRecSet(0).Value & "|" & filtRecSet(1).Value & "|" & filtRecSet(2).Value & "|" & filtRecSet(3).Value & "|" & filtRecSet(4).Value & "|" & filtRecSet(5).Value & "|"
        End If
        Debug.Print "Record no.: " & tmpCounter
        'write out text file
        tmpStream.WriteLine tmpLineText
        filtRecSet.MoveNext
        tmpRecSet.Close
        tmpCounter = tmpCounter + 1
    Loop
End If

tmpStream.Close
endTime = Now()

Debug.Print "Elapsed time: " & CStr((endTime - startTime) * 24 * 60 * 60) & " seconds."

End Sub
4

1 に答える 1

1

昨日のアイデアはほぼ良かったのですが、速度に問題がありました。したがって、テストデータベースのこれらすべてのフィールドにインデックスを設定しようとしました (Access ファイルの 2 GB の制限に関する問題にも直面しており、可能なすべてのスペースを保持したかったため、この機能は使用しませんでした)。さらに、 MD.ItemNoWD.ItemNoの間の参照整合性を強制しました。主キーと関係が設定されました。索引付けにより、MD.ItemNoを除いて重複が許可されます。その結果、数秒で実行され、正しい結果が返されます。

あとは、インポート スクリプトを変更して、必要なフィールドにインデックスを作成する XML を生成するだけです。すべてのフィールドが必要であるため、これも問題になります。これが、インポート スクリプト全体でそれらの 3 分の 2 (合計約 800 フィールド) をスキップする理由です。

これにより、VBA コードの実行も高速化されますが、それでも非常に低速です。

これは機能するSQLです:

SELECT MD.ItemNo,
       MD.ItemType
       WD.ItemLocation, 
       WD.ItemDeleted
       SMat.SourceLocation, --this could be empty
       (SELECT WD.ItemDeleted
           FROM WD
           WHERE WD.ItemNo = MD.ItemNo
                 AND WD.ItemLocation = SMat.SourceLocation
       ) AS SourceDeleted
FROM MainData AS MD INNER JOIN (WarehouseData AS WD
                                LEFT JOIN SourceWHMatrix AS SMat
                                       ON (WD.ItemLocation = SMat.ItemLocation
                                           AND WD.ItemCategory = SMat.ItemCategory))
                                ON MD.ItemNo = WD.ItemNo
WHERE (MD.ItemType = 'Value1' OR MD.ItemType = 'Value2')
      AND WD.ItemDeleted Is Null
      AND WD.ItemCategory Is Not Null
      AND WD.ItemCategory Not Like '[0-9][0-9]' -- there's an issue about wildcards
      AND (SMat.SourceLocation Is Null -- to display not set up ItemNo on SourceLocation
           OR (SELECT WD.ItemDeleted
                  FROM WD
                  WHERE WD.ItemNo = MD.ItemNo
                        AND WD.ItemLocation = SMat.SourceLocation
              ) Is Not Null) -- check if ItemDeleted on SourceLocation
于 2013-03-20T13:03:35.507 に答える