Как вы можете сделать несколько тестов членства в SQL без подзапросов? - PullRequest
1 голос
/ 27 января 2011

Я уверен, что это очень простой вопрос SQL, но я боюсь, что мой SQL-фу все еще не подходит, чтобы я смог разобраться.

У меня есть таблицазаказы на продажу и таблица клиентов.Каждый заказ на продажу имеет идентификатор клиента, которому будет выставлен счет, и идентификатор клиента, которому он будет отправлен (они могут быть одинаковыми, но чаще всего нет - существует связь один-ко-многим между«счет» и «груз» (например, скажем, я продаю что-то Google, «счет» будет штаб-квартирой Google в Маунтин-Вью, а «груз» - офисом Google в Женеве.)

Таким образом, у меня есть запрос, который в основном задает следующий вопрос: «Дайте мне общий объем продаж из таблицы заказов на продажу, где счет покупателя этого клиента связан с Джоном Доу, или документ получателя этого клиента связан с Джоном Доу, ноа не Билл. "

, и мой запрос довольно прост (читай: наивный)

    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сек, чтобы выполнить).Я почти уверен, что есть очень простой способ извлечь подзапрос, чтобы он не дублировался, или удалить подзапросы и заменить их на объединения, я просто не знаю, как это сделать.:( С положительной стороны, это может быть легким моментом для кого-то там:)

Заранее спасибо.

Ответы [ 5 ]

1 голос
/ 27 января 2011
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)
1 голос
/ 27 января 2011
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);
0 голосов
/ 27 января 2011

Предполагается, что у вас есть столбцы идентификаторов в salesOrders (здесь упоминается просто 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 идентичен ShipTo, не будут рассчитываться дважды.

0 голосов
/ 27 января 2011

Вещественное повышение производительности - правильная индексация. Вы не говорите, какой сервер 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
                             ) ) 
0 голосов
/ 27 января 2011

Я не знаю, какой механизм базы данных вы используете, но если он мощный, то вы сможете создавать временные / переменные таблицы.

Я уверен, что вы заметили, что вы используете один и тот же выбор 3 раза, это может быть более полезным, если выполнить его один раз, сохранить результаты во временную таблицу и удалить ее после использования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...