优化已取消订单的 SQL 查询

发布于 2024-08-11 22:31:32 字数 704 浏览 2 评论 0原文

这是我的表的子集:

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
)

Here is a subset of my tables:

orders:
 - order_id
 - customer_id

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

I want to select all orders (order_id) for a given customer(customer_id), where ALL of the products in the order are canceled, not just some of the products. Is there a more elegantly or efficient way of doing it than this:

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
)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

花开柳相依 2024-08-18 22:31:33

由于我们不知道数据库平台,这里有一个 ANSI 标准方法。请注意,这对模式没有任何假设(即已取消字段的数据类型、如何设置已取消标志(即“是”、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);

Since we don't know the database platform, here's an ANSI standard approach. Note that this assumes nothing about the schema (i.e. data type of the cancelled field, how the cancelled flag is set (i.e. 'YES',1,etc.)) and uses nothing specific to a given database platform (which would likely be a more efficient approach if you could give us the platform and version you are using):

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);
冷血 2024-08-18 22:31:32

如果所有订单在 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)

If all orders have at least one row in order_products, Try this

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

If the above assumption is not true, then you also need:

 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)
薯片软お妹 2024-08-18 22:31:32

最快的方法是这样的:

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,已取消) 上有索引

The fastest way will be this:

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

The subquery will return 0 if and only if there had been some products and they all had been canceled.

If there were no products at all, the subquery will return NULL; if there is at least one uncanceled product, the subquery will return 1.

Make sure you have an index on order_products (order_id, canceled)

左岸枫 2024-08-18 22:31:32

像这样的东西吗?这假设每个订单至少有一种产品,否则此查询还将返回没有任何产品的订单。

 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

Something like this? This assumes that every order has at least one product, otherwise this query will return also orders without any products.

 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
茶色山野 2024-08-18 22:31:32
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
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
旧时模样 2024-08-18 22:31:32

你可以尝试这样的事情

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)

You can try something like this

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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文