2013-03-19 132 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