2013-03-19 171 views
2

我遇到了一个问题,我们有3个表。 如果供应仓库没有该项目(删除),或者没有设置,它应该显示,但是根据源矩阵它应该是供应仓库。MS Access SQL连接问题在“重复”查询的情况下

简化布局应该看起来像这样。

MainData

  • 领域ITEMNO - 个人标识符,没有重复(PK)
  • 领域的ItemType - 有一定的选择,我必须过滤一些 特定值。

WarehouseData

  • 领域ITEMNO - 与MainData有关,但PK与下一个场组合
  • 领域ItemLocation - 给出具有货号描述的这样的物品的一个特定位置
  • 字段商品分类 - 需要加入SourceWHMatrix
  • ItemDeleted - 这是一个char场(因为出口数据),如果该项目被 “删除” 的值是 'X',否则空

SourceWHMatrix(不是空的!)

  • 领域ItemLocation - 前两个字段是主键
  • 领域ItemCategory
  • SourceLocation - 它应该给地方的项目将交付

我需要检查以下内容: 如果货号属于某些ItemType的(MainData表)ItemDeleted是空然后是否这商品编号是在来源地(这是由确定来源WHMa trix基于商品位置AND商品分类)。必须列出的所有货号这是“被删除”在SourceLocation(在这种情况下,表WarehouseDataItemLocation被检查返回SourceLocation值)OR甚至没有setupped这样的位置。

注:在同一情况下货号针对不同ItemLocationItemCategory并不总是一致的。并且每个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 

感谢您的帮助提前!

UPDATE 我做了一些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 
+0

它可能是你的一些有条件的地方,应放在LEFT JOIN。令人遗憾的是,您的要求的文字描述太难以解析。例如,那么是否很难遵循。也许你可以编辑你的问题,使它更简洁一些。例如一个项目符号列表。 – 2013-03-19 17:17:23

+0

感谢您的回复康莱德。 – szucsitg 2013-03-19 17:26:48

+0

它应该看起来像这样,希望我没有搞砸任何事情: SELECT MD.ItemNo,MD.ItemType,WD.ItemLocation,SMat.SourceLocation - >这可能是空的,WD.ItemDeleted AS“SourceWHDelFlag” - >这应该来自WD表检查时SourceLocation = ItemLocation 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。 – szucsitg 2013-03-19 17:41:22

回答

1

我只是想出了一些解决方案,昨天的想法是差不多好了,但是大约有速度的问题。因此,我尝试在我的测试数据库中设置所有这些字段的索引(我没有使用这个函数,因为我还遇到了有关2GB限制Access文件的问题,并且希望保留所有可能的空间)。除了我强制执行MD.ItemNoWD.ItemNo之间的参照完整性。主键和关系已经建立;索引允许重复,除了MD.ItemNo。结果是,它在几秒钟内运行,并返回正确的结果。

现在我只需要修改我的导入脚本来生成创建必要字段索引的XML。由于所有字段都是必需的,这也是一个问题,这就是整个导入脚本跳过其中三分之一(总共大约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