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 である場合、このItemNoがSourceLocationにあるかどうか (これは、 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