我面临一个问题,我们有 3 张桌子。它应该显示供应仓库是否没有该项目(已删除)或者甚至没有设置,但是根据源矩阵它应该是供应仓库。
简化的布局应该是这样的。
表MainData
- 字段ItemNo - 个人标识符,无重复 (PK)
- Field ItemType - 有一定的选择,我必须过滤一些特定的值。
表仓库数据
- Field ItemNo - 与 MainData 相关,但 PK 与下一个字段结合
- 字段ItemLocation - 给出使用 ItemNo 描述的此类项目的特定位置
- 字段ItemCategory - 需要加入 SourceWHMatrix
- Field ItemDeleted - 它是一个 char 字段(因为导出的数据),如果项目被“删除”,则值为“X”,否则为 Null(非空!)
表源WHMatrix
- Field ItemLocation - 前两个字段是主键
- 字段项目类别
- 字段SourceLocation - 它应该提供物品的交付地点
我需要检查以下内容:如果ItemNo属于某个ItemType(MainData 表)并且 ItemDeleted Is Null 那么这个 ItemNo 是否在SourceLocation (由SourceWHMatrix基于ItemLocation 和 ItemCategory确定)。需要列出在SourceLocation中“删除”的所有ItemNo(在这种情况下,在表WarehouseData字段ItemLocation中检查返回的SourceLocation值)或者甚至没有为此类位置设置。
注意:如果不同 ItemLocation 的ItemNo相同,ItemCategory并不总是匹配。而且每个ItemLocation都有很多不同的ItemCategory来确定源仓库。
我尝试了许多 LEFT JOIN 组合,但似乎我无法列出那些未设置的值。(通过创建 WarehouseData 的重复表,我能够在供应仓库中列出已删除的项目。)我也可以在 VBA 中使用 ADODB 执行此操作,但我想将所有内容保存在 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 千条记录需要 15 小时。我可以在 Excel 中使用一些 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