Почему этот запрос удваивает результаты? - PullRequest
0 голосов
/ 06 сентября 2011

У меня есть следующий запрос, который возвращает 4 результата, когда таблица FI_CurrentReceiptData имеет только 2 строки.Дополнительные строки являются точными дубликатами.Я могу использовать DISTINCT для исправления, но я понимаю, что это плохая практика, и мне лучше найти и исправить ошибку (ЭТО ПРАВИЛЬНО?).

Почему этот запрос удваивает результаты?

Все переменные объявляются в других местах хранимой процедуры, и этот запрос возвращает необходимые поля.

SELECT ( (Select Max(ReceiptNumber)
          from   Avanti_InventoryReceipts) + CR.Seq ),
       CR.ItemNumber,
       Convert(char(8), GETDATE(), 112),
       PONum,
       'FL-INV',
       PH.POVendor,
       0,
       0,
       'O',
       CR.QtyOrdered,
       QtyReceivedToday,
       QtyReceivedToday,
       Case @closePO
         When 'N' Then Case
                         When ( QtyOrdered - QtyReceivedToday ) < 0 Then 0
                         Else ( QtyOrdered - QtyReceivedToday )
                       End
         When 'Y' Then 0
         Else 0
       End,
       PD.TransCost * QtyReceivedToday,
       IH.PriceWholeSale,
       IH.CostLast,
       QtyReceivedToday,
       0,
       '',
       PODetailDescription /* , .... More columns...*/

FROM   FI_CurrentReceiptData CR
       LEFT JOIN Avanti_PODetails PD
         ON CR.PONum = PD.PONumber
       LEFT JOIN Avanti_POHeader PH
         ON CR.PONum = PH.PONumber
       LEFT JOIN Avanti_InventoryHeader IH
         ON CR.ItemNumber = IH.ItemNumber  

NEW WHERE CLAUSE SOLUTION:

FROM FI_CurrentReceiptData CR
inner JOIN Avanti_PODetails PD ON CR.PONum = PD.PONumber AND CR.ItemNumber = PD.TransItem AND CR.QtyOrdered = PD.TransQty
left JOIN Avanti_POHeader PH ON PD.PONumber = PH.PONumber
left JOIN Avanti_InventoryHeader IH ON CR.ItemNumber = IH.ItemNumber

Ответы [ 3 ]

3 голосов
/ 06 сентября 2011

Обычно, когда вы объединяете левые объединения, вы должны продолжать присоединяться к «левой» таблице - это не правило, а хорошая практика, поэтому вы не пропустите объединения. В вашей строке левых объединений она включает 4 таблицы, и вы только соединили первую и все три:


FROM   FI_CurrentReceiptData CR 
       LEFT JOIN Avanti_PODetails PD 
         ON CR.PONum = PD.PONumber 
       LEFT JOIN Avanti_POHeader PH 
         ON CR.PONum = PH.PONumber 
       LEFT JOIN Avanti_InventoryHeader IH 
         ON CR.ItemNumber = IH.ItemNumber   


Вы не присоединяете PD к IH к PH, но в основном оставляете соединение таблицы CR со всеми тремя - так что, по сути, она выполняет перекрестное соединение между PD и PH и IH (на основе любых полей, с которыми они сопоставляются). Я предполагаю, что POheader и POdetails имеют некоторые поля, по которым они совпадают .... и я предполагаю, что между таблицами есть отношение один ко многим? (на основании имен). Так что там должно быть какое-то ограничение ...

EDIT:

Так что вы можете попробовать, (основываясь на полевых отношениях)


FROM   FI_CurrentReceiptData CR 
       LEFT JOIN Avanti_PODetails PD 
         ON CR.PONum = PD.PONumber 
       LEFT JOIN Avanti_POHeader PH 
         ON CR.PONum = PH.PONumber AND PD.PONumber = PH.PONumber
       LEFT JOIN Avanti_InventoryHeader IH 
         ON CR.ItemNumber = IH.ItemNumber   


РЕДАКТИРОВАТЬ 2:

Итак, согласно тому, что вы говорите, CR имеет 2 строки, а CR имеет отношение 1 к 1 с PH, а PH имеет отношение 1-ко-многим с PD. И CR также имеет отношение «1 к т» к IH. В этом случае, при условии, что у вас есть ссылочная целостность, вы можете изменить свои объединения следующим образом:


FROM   FI_CurrentReceiptData CR 
       LEFT JOIN Avanti_POHeader PH ON CR.PONum = PD.PONumber 
       INNER JOIN Avanti_PODetails PD ON PH.PONumber = PD.PONUmber
       LEFT JOIN Avanti_InventoryHeader IH ON CR.ItemNumber = IH.ItemNumber

Давайте сделаем шаг назад - это ограничит строки PD и PH в зависимости от того, совпадают они или нет, и не получит нулевые значения, даже если они этого не делают (что и делают левые объединения).

Но теперь, если у вас есть 2 строки в CR, и у каждого из номеров PON есть 2 строки в POHeader, и у каждого POheader есть более 1 строки в POdetails, то у вас точно будут дубликаты. Там действительно нет способа избежать этого. Причина в следующем:

CR TABLE


PONum            ItemNumber
---------        ----------
123              ABC
456              DEF

PH TABLE


PONumber     
---------        
123              
456              

PD TABLE


PONumber     ItemNumber     
---------    -----------    
123          ABC    
123          ABC1
456          DEF
456          DEF1    

... если вы присоедините таблицу CR к таблице PH, вы получите только две строки. Если вы присоедините таблицы PH к PD, то у вас будет 4 строки. Если вы присоединитесь ко всем 3, то вы также получите 4 ряда. Природа объединения распространяется на всю таблицу, поэтому, когда вы переходите от таблицы CR к PH, он получает набор результатов из 2 строк ... и затем этот набор результатов получает соединение с PD, и там 4 строки. Если вы можете подтвердить, что ваши данные как таковые, то полученный набор результатов верен.

1 голос
/ 06 сентября 2011

Так как вы делаете LEFT JOINS, вы получите 1 строку, возвращенную для всех соответствующих записей. Таким образом, одна из таблиц, к которой вы присоединяетесь, возвращает более 1 строки.

Попробуйте временно изменить запрос, чтобы добавить первичный ключ других таблиц в список столбцов, и вы сможете быстро определить, какая таблица возвращает более 1 строки.

0 голосов
/ 06 сентября 2011

Одна из объединяемых таблиц имеет более одной подходящей строки. Я не могу сказать наверняка, какой из них, но на вашем месте я бы начал искать за столом Avanti_PODetails. Имеется ли более одной совпадающей записи для любого из двух чеков?

...