如何在没有子查询的情况下在 SQL 中进行多个成员资格测试?

发布于 2024-10-14 07:32:55 字数 894 浏览 3 评论 0原文

我确信这是一个非常简单的 SQL 问题,但恐怕我的 SQL 能力还达不到我能够弄清楚的水平。

我有一张销售订单表和一张客户表。每个销售订单都有一个为其开票客户的 ID,以及一个为其发货客户的 ID(它们可能相同,但大多数情况下不同 - 之间存在一对多关系) “收单至”和“发货至”[例如,假设我要向 Google 出售某些东西,“收单至”将是 Google 的山景城总部,但“发货至”可能是 Google 的日内瓦办事处。)

所以我'有一个查询基本上询问以下问题: “请提供销售订单表中的总销售额,其中该客户的收单方与 John Doe 关联,或者该客户的收货方与 John Doe 关联,但也没有收单方。”

我的查询相当简单(读:天真)

    SELECT SUM(price) FROM salesOrders
    WHERE
    (
    ( salesOrders.BillTo IN (SELECT customerID FROM customers WHERE customers.salesman = 'JOHNDOE')

    OR

    (salesOrders.ShipTo IN (SELECT customerID FROM customers WHERE customers.salesman = 'JOHNDOE') 
AND 
salesOrders.BillTo NOT IN (SELECT customerID FROM customers WHERE customers.salesman = 'JOHNDOE')
    )
    )

查询有效,但它需要太长的时间(执行约 6 秒)。我几乎肯定有一种非常简单的方法可以提取子查询,这样我就不必将其重复三次,或者完全删除子查询并用联接替换它们,我只是不知道该怎么做。 :( 从好的方面来说,这对于其他人来说可能很容易:)

提前致谢。

I'm sure this is a very easy SQL question but I'm afraid my SQL-fu is still not up to snuff for me to be able to figure it out.

I have a table of sales orders and a table of customers. Each sales order has an ID for the customer to whom it will be billed, and an ID for the customer to whom it will be shipped (they may be the same, but most often not - there is a one-to-many relationship between a "bill to" and "ship to" [e.g. let's say I'm selling something to Google, the "bill to" would be Google's Mountain View headquarters, but the "ship to" might be Google's Geneva office.)

So I've got a query that basically asks the following question:
"Give me the total sales from the sales order table where this customer's Bill To is associated with John Doe or this customer's Ship To is associated with John Doe, but not the Bill To as well."

and the query I have is fairly straightforward (read: naive)

    SELECT SUM(price) FROM salesOrders
    WHERE
    (
    ( salesOrders.BillTo IN (SELECT customerID FROM customers WHERE customers.salesman = 'JOHNDOE')

    OR

    (salesOrders.ShipTo IN (SELECT customerID FROM customers WHERE customers.salesman = 'JOHNDOE') 
AND 
salesOrders.BillTo NOT IN (SELECT customerID FROM customers WHERE customers.salesman = 'JOHNDOE')
    )
    )

The query works, but it just takes way too long (~6 sec to execute). I'm almost positive there is a very easy way to either extract the subquery so I don't have it triplicated or remove the subqueries altogether and replace them with joins, I just don't know how to do it. :( On the plus side, this might be easy points for someone out there :)

Thanks in advance.

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

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

发布评论

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

评论(5

咿呀咿呀哟 2024-10-21 07:32:55
SELECT SUM(so.price) 
    FROM salesOrders so
        LEFT JOIN customers c1
            on so.BillTo = c1.customerID
                and c1.salesman = 'JOHNDOE'
        LEFT JOIN customers c2
            on so.ShipTo = c2.customerID
                and c2.salesman = 'JOHNDOE'
    WHERE c1.customerID IS NOT NULL
        OR (c2.customerID IS NOT NULL AND c1.customerID IS NULL)
SELECT SUM(so.price) 
    FROM salesOrders so
        LEFT JOIN customers c1
            on so.BillTo = c1.customerID
                and c1.salesman = 'JOHNDOE'
        LEFT JOIN customers c2
            on so.ShipTo = c2.customerID
                and c2.salesman = 'JOHNDOE'
    WHERE c1.customerID IS NOT NULL
        OR (c2.customerID IS NOT NULL AND c1.customerID IS NULL)
苏辞 2024-10-21 07:32:55
SELECT sum(s.price)
FROM salesOrders s
  inner join customers bt on s.billto = bt.customerID
  inner join customers st on s.ShipTo = st.customerID
WHERE
  s.billto <> s.shipto and 'JONHDOE' in (bt.salesman, st.salesman);
SELECT sum(s.price)
FROM salesOrders s
  inner join customers bt on s.billto = bt.customerID
  inner join customers st on s.ShipTo = st.customerID
WHERE
  s.billto <> s.shipto and 'JONHDOE' in (bt.salesman, st.salesman);
执着的年纪 2024-10-21 07:32:55

我不知道您使用的是什么数据库引擎,但如果它功能强大,将允许您创建临时/变量表。

我相信您已经注意到,您使用了相同的 select 3 次,如果执行一次,将结果保存到临时表并在使用后将其删除,可能会更有用。

I do not know what database engine you are using, but if it is powerful will allow you tocreate temporary/variable tables.

I'm sure you have noticed, you are useing the same select 3 times, it might be more useful if performed once, save results to a temporary table and delete it after use.

舂唻埖巳落 2024-10-21 07:32:55

最能提高性能的是拥有正确的索引。
你不会说你运行的是哪个 SQL 服务器,如果它是 SQL 2008,它会给你在查看查询计划时添加索引的提示。

我更喜欢使用存在,据我所知,使用它并没有太大的性能提升。您应该查看查询计划进行检查。

 SELECT SUM(price) FROM salesOrders
            WHERE
            EXISTS (SELECT * FROM customers WHERE 
                                customers.salesman = 'JOHNDOE'
                                and ( (salesOrders.ShipTo = customers.CustomerId  
                                        and not salesOrders.BillTo = customers.CustomerId)                  
                                or salesOrders.BillTo = customers.CustomerId
                             ) ) 

The thing that would do most performance boost is having the correct indexing.
You dont say which SQL server your running if it's SQL 2008 it will give you hints of index to add when looking at the query plan.

I Prefer using exists, there is not much performance gain using it as far as i have been able to tell. You should look at the queryplan to check.

 SELECT SUM(price) FROM salesOrders
            WHERE
            EXISTS (SELECT * FROM customers WHERE 
                                customers.salesman = 'JOHNDOE'
                                and ( (salesOrders.ShipTo = customers.CustomerId  
                                        and not salesOrders.BillTo = customers.CustomerId)                  
                                or salesOrders.BillTo = customers.CustomerId
                             ) ) 
も星光 2024-10-21 07:32:55

假设您在 salesOrders 中有一个 id 列(此处简称为 ID):

SELECT SUM(s.Price)
FROM (
  SELECT ID, Price, ShipTo AS CustomerID FROM salesOrders
  UNION
  SELECT ID, Price, BillTo FROM salesOrders
) s
  INNER JOIN customers c ON s.CustomerID = c.CustomerID
WHERE c.salesman = 'JOHNDOE'

UNION 消除了重复项,因此 BillTo 的情况code> 与 ShipTo 相同,不会计算两次。

This assumes that you have an id column(s) in salesOrders (here referred to just as ID):

SELECT SUM(s.Price)
FROM (
  SELECT ID, Price, ShipTo AS CustomerID FROM salesOrders
  UNION
  SELECT ID, Price, BillTo FROM salesOrders
) s
  INNER JOIN customers c ON s.CustomerID = c.CustomerID
WHERE c.salesman = 'JOHNDOE'

UNION eliminates the duplicates, so cases where BillTo is identical to ShipTo will not be calculated twice.

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