如何使用子查询修改SQL查询以获取额外的列

时间:2012-10-18 13:20:04

标签: sql sql-server-2008

我正在尝试修改用户查询,以便从以下SQL查询中返回一个额外的列INV1.WhsCode:

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]

我如何实现这一目标? (MS SQL Server 2008)

2 个答案:

答案 0 :(得分:1)

所有子查询都在where子句中包含以下内容:INV1.WhsCode = [%2]

这意味着您可以像这样返回[%2]而不是INV1.WhsCode:

SELECT  [%2] as WhsCode,
        T0.CardCode,
        T2.CardName,
        T0.CodeBars,
......

这假定[%2]和其他类似的令牌被应用程序替换为SQL Server可以理解的内容,然后再发送执行。

答案 1 :(得分:1)

您的查询存在许多错误/效率低下的问题我知道您没有问过,但无论如何我都会回答,因为这有助于回答您提出的问题。

你需要在可能的情况下避免使用相关的子查询,有时它们是不可避免的并且是最好的解决方案,但是我经常在JOIN执行相同工作的地方看到它们,而优化器会处理这么多的连接更好。例如,你有:

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

这会计算每一行的子查询,而如果你重写如此:

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

你会得到相同的结果,但要以更有效的方式进行评估。

下一个错误是你使用MONTH(GETDATE()) - 1获得2个月前的方法。在1月份,这将被宣布为0并且没有比赛。最好的方法是使用类似于他的东西将每个日期转换为每月的第一个日期:

SELECT  [FirstOfThisMonth] = DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0),
        [FirstOfLastMonth] = DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE() - 1), 0)

连接而不是相关子查询的相同原则也可以应用于您的数量列,这样可以访问WhsCode列,这不是必需的,但我使用了公用表表达式来清理查询(使用上面的日期逻辑)

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]

将所有这些结合到最终查询中会给出:

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]

这都是未经测试的,因此可能存在一些拼写错误/轻微语法错误,但仍应适用相同的主体。

如果您仍然对相关子查询有所了解,可以使用APPLY来允许您从中访问多个列。 e.g。

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