Próbuję zmodyfikować zapytanie użytkownika, aby zwrócić dodatkową kolumnę, INV1.WhsCode z następującego zapytania SQL:
SELECT T0.CardCode,
T2.CardName,
T0.CodeBars,
T0.ItemCode,
T0.ItemName,
T3.Price AS [POS Price],
T1.AvgPrice,
T1.OnHand,
T1.MinStock,
T1.MaxStock,
T0.NumInBuy AS Packsize,
T0.LstSalDate,
(
SELECT SUM(Quantity) AS Expr1
FROM dbo.INV1
INNER JOIN OINV
ON INV1.DocEntry = OINV.DocEntry
WHERE INV1.ItemCode = T0.ItemCode
AND INV1.WhsCode = [%2]
AND Month(OINV.DocDate) = month(GetDate())
) AS [Current Period],
(
SELECT SUM(Quantity) AS Expr1
FROM dbo.INV1
INNER JOIN OINV
ON INV1.DocEntry = OINV.DocEntry
WHERE INV1.ItemCode = T0.ItemCode
AND INV1.WhsCode = [%2]
AND Month(OINV.DocDate) = month(GetDate()) - 1
) AS [Previous Period],
(
SELECT SUM(Quantity) AS Expr1
FROM dbo.INV1
INNER JOIN OINV
ON INV1.DocEntry = OINV.DocEntry
WHERE INV1.ItemCode = T0.ItemCode
AND INV1.WhsCode = [%2]
AND Month(OINV.DocDate) = month(GetDate()) - 2
) AS [60-90],
(
SELECT TOP 1 OPDN.DocDate AS Expr1
FROM dbo.PDN1
INNER JOIN OPDN
ON PDN1.DocEntry = OPDN.DocEntry
WHERE PDN1.ItemCode = T0.ItemCode
ORDER BY OPDN.DocDate DESC
) AS LastGRNDate
FROM OITM T0
INNER JOIN OITW T1
ON T0.ItemCode = T1.ItemCode
INNER JOIN OCRD T2
ON T0.CardCode = T2.CardCode
INNER JOIN ITM1 T3
ON T0.ItemCode = T3.ItemCode
INNER JOIN OWHS T4
ON T1.WhsCode = T4.WhsCode
INNER JOIN OITB T5
ON T0.ItmsGrpCod = T5.ItmsGrpCod
WHERE T3.PriceList = '3'
AND T4.WhsName = [%0]
AND T5.ItmsGrpNam = [%1]
Jak to osiągnąć? (MS SQL Server 2008)
2 odpowiedzi
Jest wiele rzeczy błędnych/nieefektywnych w twoim zapytaniu, o których wiem, że nie pytałeś, ale i tak odpowiem, ponieważ pomoże to odpowiedzieć na pytanie, które zadałeś.
Należy unikać skorelowanych podzapytań tam, gdzie to możliwe, są chwile, że są one nieuniknione i są najlepszym rozwiązaniem, jednak tak często widzę je w miejscu, w którym JOIN wykonałby tę samą pracę, a optymalizator poradziłby sobie z dołączeniem o wiele lepiej. Na przykład masz:
SELECT (
SELECT TOP 1 OPDN.DocDate AS Expr1
FROM dbo.PDN1
INNER JOIN OPDN
ON PDN1.DocEntry = OPDN.DocEntry
WHERE PDN1.ItemCode = T0.ItemCode
ORDER BY OPDN.DocDate DESC
) AS LastGRNDate
FROM OITM T0
To ocenia podzapytanie dla każdego wiersza, podczas gdy w przypadku ponownego napisania w ten sposób:
SELECT LastGRN.LastGRNDate
FROM OITM TO
LEFT JOIN
( SELECT PDN1.ItemCode, [LastGRNDate] = MAX(OPDN.DocDate)
FROM dbo.PDN1
INNER JOIN OPDN
ON PDN1.DocEntry = OPDN.DocEntry
GROUP BY PDN1.ItemCode
) LastGRN
ON LastGRN.ItemCode = T0.ItemCode
Uzyskalibyście ten sam wynik, ale ocenilibyście w znacznie bardziej efektywny sposób.
Kolejną wadą jest Twoja metoda używania MONTH(GETDATE())
- 1, aby otrzymać 2 miesiące temu. W styczniu to oceni się na 0 i nie otrzyma żadnych dopasowań. Najlepszym sposobem na to jest przekonwertowanie każdej daty na pierwszy dzień każdego miesiąca, używając czegoś podobnego do jego:
SELECT [FirstOfThisMonth] = DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0),
[FirstOfLastMonth] = DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE() - 1), 0)
Ta sama zasada sprzężeń, a nie skorelowanych podzapytań może być również zastosowana do twoich kolumn ilościowych, a to daje dostęp do kolumn WhsCode
, nie jest to konieczne, ale użyłem wspólnego wyrażenia tabelowego do oczyszczenia zapytania ( używając logiki daty z góry)
WITH Quantities AS
( SELECT [DocMonth] = DATEADD(MONTH, DATEDIFF(MONTH, 0, IONV.DocDate),
Inv1.WhsCode,
ItemCode,
[Quantity] = SUM(Quantity)
FROM dbo.Inv1
INNER JOIN OINV
ON Inv1.DocEntry = OINV.DocEntry
GROUP BY DATEADD(MONTH, DATEDIFF(MONTH, 0, IONV.DocDate), WhsCode, itemCode
)
SELECT T0.ItemCode,
[Current Period] = COALESCE(Cur.Quantity, 0),
[Previous Period] = COALESCE(prev.Quantity, 0),
[60-90] = COALESCE(prev2.Quantity, 0)
FROM OITM T0
LEFT JOIN Quantities cur
ON cur.ItemCode = T0.ItemCode
AND cur.DocDate = DATEADD(MONTH, DATEDIFF(MONTH, 0, CURRENT_TIMESTAMP), 0)
AND Cur.WhsCode = [%2]
LEFT JOIN Quantities prev
ON prev.ItemCode = T0.ItemCode
AND prev.DocDate = DATEADD(MONTH, DATEDIFF(MONTH, 0, CURRENT_TIMESTAMP) - 1, 0)
AND prev.WhsCode = [%2]
LEFT JOIN Quantities prev2
ON prev2.ItemCode = T0.ItemCode
AND prev2.DocDate = DATEADD(MONTH, DATEDIFF(MONTH, 0, CURRENT_TIMESTAMP) - 2, 0)
AND prev2.WhsCode = [%2]
Połączenie tego wszystkiego w ostateczne zapytanie daje:
SELECT T0.CardCode,
T2.CardName,
T0.CodeBars,
T0.ItemCode,
T0.ItemName,
T3.Price,
T1.AvgPrice,
T1.OnHand,
T1.MinStock,
T1.MaxStock,
T0.NumInBuy AS Packsize,
T0.LstSalDate
[Current Period] = COALESCE(Cur.Quantity, 0),
[Previous Period] = COALESCE(prev.Quantity, 0),
[60-90] = COALESCE(prev2.Quantity, 0)
LastGRN.LastGRNDate
FROM OITM T0
INNER JOIN OITW T1
ON T0.ItemCode = T1.ItemCode
INNER JOIN OCRD T2
ON T0.CardCode = T2.CardCode
INNER JOIN ITM1 T3
ON T0.ItemCode = T3.ItemCode
INNER JOIN OWHS T4
ON T1.WhsCode = T4.WhsCode
INNER JOIN OITB T5
ON T0.ItmsGrpCod = T5.ItmsGrpCod
LEFT JOIN Quantities cur
ON cur.ItemCode = T0.ItemCode
AND cur.DocDate = DATEADD(MONTH, DATEDIFF(MONTH, 0, CURRENT_TIMESTAMP), 0)
AND Cur.WhsCode = [%2]
LEFT JOIN Quantities prev
ON prev.ItemCode = T0.ItemCode
AND prev.DocDate = DATEADD(MONTH, DATEDIFF(MONTH, 0, CURRENT_TIMESTAMP) - 1, 0)
AND prev.WhsCode = [%2]
LEFT JOIN Quantities prev2
ON prev2.ItemCode = T0.ItemCode
AND prev2.DocDate = DATEADD(MONTH, DATEDIFF(MONTH, 0, CURRENT_TIMESTAMP) - 2, 0)
AND prev2.WhsCode = [%2]
LEFT JOIN
( SELECT PDN1.ItemCode, [LastGRNDate] = MAX(OPDN.DocDate)
FROM dbo.PDN1
INNER JOIN OPDN
ON PDN1.DocEntry = OPDN.DocEntry
GROUP BY PDN1.ItemCode
) LastGRN
ON LastGRN.ItemCode = T0.ItemCode
WHERE T3.PriceList = '3'
AND T4.WhsName = [%0]
AND T5.ItmsGrpNam = [%1]
To wszystko nie zostało przetestowane, więc mogą wystąpić pewne literówki/niewielkie błędy składniowe, ale te same zasady powinny nadal obowiązywać.
Jeśli nadal myślisz o skorelowanych podzapytaniach, możesz użyć APPLY
, aby uzyskać z niego dostęp do wielu kolumn. np.
SELECT T0.Code, cur.WhsCode, cur.Expr1 AS [Current Period]
FROM OITM T0
OUTER APPLY
( SELECT INV1.WhsCode, SUM(Quantity) AS Expr1
FROM dbo.INV1
INNER JOIN OINV
ON INV1.DocEntry = OINV.DocEntry
WHERE INV1.ItemCode = T0.ItemCode
AND INV1.WhsCode = [%2]
AND MONTH(OINV.DocDate) = MONTH(GETDATE())
) cur
Wszystkie podzapytania zawierają w klauzuli WHERE następujące informacje: INV1.WhsCode = [%2]
Oznacza to, że zamiast INV1.WhsCode możesz po prostu zwrócić [%2] w ten sposób:
SELECT [%2] as WhsCode,
T0.CardCode,
T2.CardName,
T0.CodeBars,
......
Zakłada się, że [%2] i inne podobne tokeny zostaną zastąpione przez aplikację czymś, co rozumie SQL Server, zanim zostanie wysłany do wykonania.
Podobne pytania
Nowe pytania
sql
Structured Query Language (SQL) to język służący do wykonywania zapytań w bazach danych. Pytania powinny zawierać przykłady kodu, strukturę tabeli, przykładowe dane i znacznik używanej implementacji DBMS (np. MySQL, PostgreSQL, Oracle, MS SQL Server, IBM DB2 itp.). Jeśli Twoje pytanie dotyczy wyłącznie konkretnego DBMS (używa określonych rozszerzeń / funkcji), użyj zamiast tego tagu tego DBMS. Odpowiedzi na pytania oznaczone tagiem SQL powinny używać standardu SQL ISO / IEC.