У меня есть это левое соединение правильно? - PullRequest
1 голос
/ 30 июня 2011

Мне нужно найти общее количество клиентов, созданных после определенной даты, которые еще не заказали.

У меня есть две таблицы:

| customers           |    // There's more to this but this is all
+----+------+---------+    // you need to answer this question
| ID | Name | Created |
+----+------+---------+

| orders           |    // There's more to this but this is all
+----+-------------+    // you need to answer this question
| ID | customer_id |
+----+-------------+

Мне нужно найти общее количествоколичество клиентов, созданных после определенной даты, которые еще не заказали.

Это то, что я сделал:

SELECT Count(*)
FROM customers
LEFT JOIN orders ON customers.ID = orders.customer_id
WHERE customers.Created > #arbitrary date#
AND orders.ID Is Null;

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

Так что я делаю это правильно?Если да, мне явно нужно посмотреть, что еще может быть причиной проблемы.Спасибо.

РЕДАКТИРОВАТЬ 1

Комментарий ниже предполагает, что orders.id не может быть обнуляемым.Это может иметь место, однако я получаю те же результаты, если проверяю, orders.customer_id Is Null.

РЕДАКТИРОВАТЬ 2

Я не хотел переусердствовать, но этоможет быть полезно, если вы знаете, что я делаю это в базе данных Access, поэтому я не могу использовать все вкусности, которые позволяет стандартный SQL.(Я редактировал теги)

Ответы [ 5 ]

3 голосов
/ 30 июня 2011

Ваш босс должен сказать вам, что он считал «хорошими ценностями».

Возможно, он имел обыкновение иметь отчет с фильтром других, чтобы посчитать этого клиента. Может быть, вам нужно проверить цену где-нибудь в таблице заказов и считать не реальные заказы, если цена = 0.

С информацией, которую вы нам предоставляете, ваш запрос абсолютно верен, может быть, я добавлю кое-что:

SELECT Count(DISTINCT customers.ID)
FROM customers
    LEFT JOIN orders 
        ON customers.ID = orders.customer_id
WHERE customers.Created > #arbitrary date#
AND orders.ID Is Null;

Для облегчения обслуживания и понимания (запрос должен быть немного медленнее, но не намного)

1 голос
/ 04 июля 2011

Мне интересно, не является ли это незначительной ошибкой, которая может произойти в вашем коде.

Спецификация гласит: "найдите общее количество клиентов".Присоединяясь к таблице orders, вы фактически рассчитываете на объединение.Конечно, в случае клиентов без заказов вы действительно считаете клиентов.Однако для клиентов с заказами вы будете считать их заказы.

Я бы предпочел конструкцию запроса, которая отражала бы количество клиентов, чтобы я (или даже более случайный пользователь) мог переключить антисоединение на полусоединение и получить ожидаемые результаты (с вашей конструкцией они получатвводящий в заблуждение счет), например

SELECT COUNT(*)
  FROM customers
 WHERE customers.Created > #specific date#
       AND NOT EXISTS (
                       SELECT *
                         FROM orders
                        WHERE orders.customer_id = customers.ID
                      );

Что касается принятого ответа, я предлагаю следующее «Для облегчения обслуживания и понимания» (запрос может быть немного медленнее, но, надеюсь, ненамного). "

0 голосов
/ 30 июня 2011

Возможно, где-то ваш код позволяет записывать заказы для клиентов (но не завершенные). Вы можете считать клиентов, которые заказали только заказы с 0 суммой.

SELECT COUNT(*)
FROM
  ( SELECT customers.id
    FROM customers
      INNER JOIN orders ON customers.ID = orders.customer_id
    WHERE customers.Created > #arbitrary date# 
    GROUP BY customers.id
    HAVING COUNT(IIF(orders.amount > 0, 1, NULL)) = 0  
  ) AS grp

В Access нет оператора CASE, но есть функция IIF().

И INNER JOIN требуется вместо JOIN.

0 голосов
/ 30 июня 2011

посмотрите на этот веб-сайт , он объясняет все различия между объединениями sql

0 голосов
/ 30 июня 2011

Нет, это не так.

Попробуйте вместо этого:

SELECT
SUM(CASE WHEN (SELECT COUNT(*) FROM orders WHERE customers.ID = orders.customer_id) = 0 
  THEN 1
  ELSE 0
END) 
FROM customers
WHERE customers.Created > #arbitrary date#
...