如何优化嵌套的SELECT

问题描述 投票:0回答:3

我有以下需要优化的SQL(在以下代码中,“属性”的名称已更改为更通用):

它在Azure SQL中运行

SELECT ContactValueA, ContactValueB, SUM(X.Price) as Price, SUM(X.ValueX) AS ValueX, SUM(X.ValueY) AS ValueY, Count (*) As [Count]
FROM
    (
        SELECT OL.id, O.ContactValueA, O.ContactValueB,
        OL.Price,
        OL.ValueX,
        OL.ValueY
        FROM [OrderLines] AS OL
        JOIN [Orders] AS O
        ON OL.OrderId = O.Id
        WHERE O.Id in 
            (
                SELECT MIN(SO.Id) AS OID
                FROM [Orders] AS SO
                WHERE SO.[Type] = 'cake'
                AND SO.Created >= @begin  and SO.Created < @end
                AND NOT EXISTS
                (
                    SELECT 1
                    FROM [3Orders] AS SOA
                    WHERE SOA.ExtOrderId = SO.ExtOrderId
                    AND SOA.[Type] = 'cake'
                    AND SOA.Created < @begin
                )
                GROUP BY SO.ExtOrderId
            )   
    ) X
GROUP BY X.ContactValueA, X.ContactValueB

@begin和@end都是DateTimeOffset

如果我们看一下代码的这一部分:

                SELECT MIN(SO.Id) AS OID
                FROM [Orders] AS SO
                WHERE SO.[Type] = 'cake'
                AND SO.Created >= @begin  and SO.Created < @end
                AND NOT EXISTS
                (
                    SELECT 1
                    FROM [3Orders] AS SOA
                    WHERE SOA.ExtOrderId = SO.ExtOrderId
                    AND SOA.[Type] = 'cake'
                    AND SOA.Created < @begin
                )
                GROUP BY SO.ExtOrderId

关于订单表 - 每个订单都有唯一的ID和非唯一的ExtOrderId - 因为订单表中的条目可以是部分订单(部分订单共享相同的ExtOrderId)

在上面的代码中,我需要查看两个datetimeoffsets之间的所有订单(部分订单) - 并获取具有最低ID的部分订单 - 但是部分订单ID(ExtOrderId)在开始日期之前不得有订单。

有什么建议如何优化?

sql sql-server tsql
3个回答
0
投票

使用row_number()解析函数获取最小id

with cte as
(

SELECT OL.id, O.ContactValueA, O.ContactValueB,
        OL.Price,
        OL.ValueX,
        OL.ValueY,
        row_number()over(partition by O.type order by o.id) rn
        FROM [OrderLines] AS OL
        JOIN [Orders] AS O
        ON OL.OrderId = O.Id
) ContactValueA, ContactValueB, SUM(Price) as Price, SUM(ValueX) AS ValueX, SUM(ValueY) AS ValueY, Count (*) As [Count] from cte where rn=1
group by ContactValueA, ContactValueB

0
投票

试试吧

WITH T AS (
    SELECT MIN(SO.Id) AS OID
    FROM [Orders] AS SO
    WHERE SO.[Type] = 'cake' AND SO.Created < @end
    GROUP BY SO.ExtOrderId 
    HAVING MIN(SO.Created) >= @begin
), T1 AS (
    SELECT OL.id, O.ContactValueA, O.ContactValueB,
        OL.Price,
        OL.ValueX,
        OL.ValueY
    FROM [OrderLines] AS OL
    INNER JOIN T ON T.OID = OL.OrderId
    INNER JOIN [Orders] AS O ON T.OID = O.Id
) SELECT ContactValueA, ContactValueB, SUM(T1.Price) as Price, SUM(T1.ValueX) AS ValueX, SUM(T1.ValueY) AS ValueY, Count (*) As [Count]
FROM T1 
GROUP BY T1.ContactValueA, T1.ContactValueB

0
投票

我将使用左连接并返回没有找到先前订单的行,而不是使用子查询。

您的查询 :

        SELECT MIN(SO.Id) AS OID
        FROM [Orders] AS SO
        WHERE SO.[Type] = 'cake'
        AND SO.Created >= @begin  and SO.Created < @end
        AND NOT EXISTS
        (
            SELECT 1
            FROM [3Orders] AS SOA
            WHERE SOA.ExtOrderId = SO.ExtOrderId
            AND SOA.[Type] = 'cake'
            AND SOA.Created < @begin
        )
        GROUP BY SO.ExtOrderId

将会 :

            SELECT MIN(SO.Id) AS OID
            FROM [Orders] AS SO
                 LEFT JOIN [3Orders] AS SOA ON     SOA.ExtOrderId = SO.ExtOrderId
                                               AND SOA.[Type] = 'cake'
                                               AND SOA.Created < @begin
            WHERE     SO.[Type] = 'cake'
                  AND SO.Created >= @begin  and SO.Created < @end
                  AND SOA.Id IS NULL -- Here we ensure that it has no previous orders
            GROUP BY SO.ExtOrderId
© www.soinside.com 2019 - 2024. All rights reserved.