【问题标题】:Optimize SQL query for canceled orders优化取消订单的SQL查询
【发布时间】:2009-11-20 16:26:27
【问题描述】:

这是我的表格的一个子集:

orders:
 - order_id
 - customer_id

order_products:
 - order_id
 - order_product_id (unique key)
 - canceled

我想为给定的客户 (customer_id) 选择所有订单 (order_id),其中订单中的所有产品都被取消,而不仅仅是部分产品。有没有比这更优雅或更有效的方法:

select order_id from orders
where order_id in (
    select order_id from orders
    inner join order_products on orders.order_id = order_products.order_id
    where order_products.customer_id = 1234 and order_products.canceled = 1
)
and order_id not in (
    select order_id from orders
    inner join order_products on orders.order_id = order_products.order_id
    where order_products.customer_id = 1234 and order_products.canceled = 0
)

【问题讨论】:

  • 你使用的是什么数据库引擎,即mysql、sql-server-2000、sql-server-2005、Oracle等

标签: sql database query-optimization


【解决方案1】:

如果所有订单在 order_products 中至少有一行,试试这个

 Select order_id from orders o
 Where Not Exists 
      (Select * From order_products 
       Where order_id = o.order_id
          And cancelled = 1)

如果上述假设不成立,那么你还需要:

 Select order_id from orders o
 Where Exists 
      (Select * From order_products
       Where order_id = o.order_id)
   And Not Exists 
      (Select * From order_products
       Where order_id = o.order_id
          And cancelled = 1)

【讨论】:

    【解决方案2】:

    最快的方法是这样的:

    SELECT  order_id
    FROM    orders o
    WHERE   customer_id = 1234
            AND
            (
            SELECT  canceled
            FROM    order_products op
            WHERE   op.order_id = o.order_id
            ORDER BY
                    canceled DESC
            LIMIT 1
            ) = 0
    

    当且仅当有一些产品并且它们都被取消时,子查询才会返回0

    如果根本没有产品,子查询将返回NULL;如果至少有一个未取消的产品,则子查询将返回1

    确保您在order_products (order_id, canceled) 上有一个索引

    【讨论】:

      【解决方案3】:

      这样的?这假定每个订单至少有一个产品,否则此查询也将返回没有任何产品的订单。

       select order_id 
       from orders o
       where not exists (select 1 from order_products op
                         where canceled = 0
                         and op.order_id = o.order_id
       )
       and o.customer_id = 1234
      

      【讨论】:

        【解决方案4】:
        SELECT customer_id, order_id, count(*) AS product_count, sum(canceled) AS canceled_count
        FROM orders JOIN order_products
        ON orders.order_id = order_products.order_id
        WHERE customer_id = <<VALUE>>
        GROUP BY customer_id, order_id
        HAVING product_count = canceled_count
        

        【讨论】:

          【解决方案5】:

          你可以试试这样的

          select  orders.order_id 
          from    @orders orders inner join 
                  @order_products order_products on orders.order_id = order_products.order_id
          where   order_products.customer_id = 1234 
          GROUP BY orders.order_id
          HAVING SUM(order_products.canceled) = COUNT(order_products.canceled)
          

          【讨论】:

            【解决方案6】:

            由于我们不了解数据库平台,这里有一个 ANSI 标准方法。请注意,这对架构没有任何假设(即取消字段的数据类型,取消标志的设置方式(即'YES',1等))并且不使用特定于给定数据库平台的任何内容(可能是如果您能给我们您正在使用的平台和版本,则更有效的方法):

            select  op1.order_id
            from    (
                        select  op.order_id, cast( case when op.cancelled is not null then 1 else 0 end as tinyint) as is_cancelled
                        from    #order_products op
                    ) op1
            group by op1.order_id
            having  count(*) = sum(op1.is_cancelled);
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-03-24
              • 2013-01-10
              • 2014-02-04
              • 2014-11-16
              • 2011-06-22
              相关资源
              最近更新 更多