Несколько операторов объединения не возвращают ожидаемый результат - PullRequest
4 голосов
/ 12 марта 2011

Мне нужно написать запрос со следующими требованиями:

Запрос должен возвращать список всех значений записи для клиента с именем «Стив» и для каждой показанной даты (если она доступна)последние сведения о статусе на эту дату.

Таблица клиентов

CustomerID | CustomerName
1          |    Steve
2          |    John

Таблица записей

CustomerID | EntryDate | EntryValue 
 1         | 5/4/2010  |    200.0  
 1         | 4/4/2010  |    100.0  
 1         | 3/4/2010  |    150.0
 1         | 2/4/2010  |    170.0
 2         | 5/4/2010  |    220.0

Таблица состояния

CustomerID | StatusDate | Detail
1          | 5/28/2010  | D
1          | 4/24/2010  | S
1          | 4/5/2010   | P
1          | 2/28/2010  | A

Ожидаемый результат:

CustomerName |   Date    |   OrderCost |   Detail 
  Steve      | 5/4/2010  |    200.0    |  S
  Steve      | 4/4/2010  |    100.0    |  A
  Steve      | 3/4/2010  |    75.0     |  A
  Steve      | 3/4/2010  |    75.0     |  <null>

Я думаю, что ожидаемый результат может быть неправильным, и он на самом деле должен быть:

CustomerName |   Date    |   OrderCost |   Detail 
  Steve      | 5/4/2010  |    200.0    |  S
  Steve      | 4/4/2010  |    100.0    |  A
  Steve      | 3/4/2010  |    150.0     |  A
  Steve      | 2/4/2010  |    170.0     |  <null>

Учитывая требование, я не понимаю, почему дата 3/4/2010 должна была бы произойти дважды, и во второй раз она будет иметь Детали.Я написал следующий запрос:

Я написал следующий запрос:

SELECT  Customers.CustomerName, Entries.EntryDate, Entries.EntryValue, Status.Detail
FROM   Customers
    INNER JOIN Entries ON Customers.CustomerID = Entries.CustomerID
    LEFT OUTER JOIN Status ON Status.CustomerID = Customers.CustomersID AND Status.StatusDate <= Entries.EntryDate
WHERE (Customers.CustomerName = 'Steve')

Результат моего запроса таков:

CustomerName| EntryDate |   EntryValue |   Detail
Steve      |  5/4/2010 |    200.00  |   S
Steve      |  5/4/2010 |    200.00  |   P
Steve      |  5/4/2010 |    200.00  |   A
Steve      |  4/4/2010 |    100.00  |   A
Steve      |  3/4/2010 |    150.00  |   A
Steve      |  2/4/2010 |    170.00  |   NULL

Любые намеки на то, что я 'я здесь не так?Я не могу понять ...

Обновление Я изменил заказ на запись, чтобы нас это не смущало.

Ответы [ 4 ]

1 голос
/ 13 марта 2011

Вы можете использовать подзапрос, чтобы получить статус.
Используйте TOP 1 для SQL Server или LIMIT 1 для SQLite / MySQL

SQL Server / SyBase

SELECT Customers.CustomerName, Entries.EntryDate, Entries.EntryValue,
   (SELECT top 1 Status.Detail From Status
    where Status.CustomerID = Customers.CustomersID AND Status.StatusDate <= Entries.EntryDate
    order by Status.StatusDate desc)
FROM   Customers
INNER JOIN Entries ON Customers.CustomerID = Entries.CustomerID
WHERE (Customers.CustomerName = 'Steve')

MySQL / SQLite

SELECT Customers.CustomerName, Entries.EntryDate, Entries.EntryValue,
   (SELECT Status.Detail From Status
    where Status.CustomerID = Customers.CustomersID AND Status.StatusDate <= Entries.EntryDate
    order by Status.StatusDate desc
    limit 1)
FROM   Customers
INNER JOIN Entries ON Customers.CustomerID = Entries.CustomerID
WHERE (Customers.CustomerName = 'Steve')
1 голос
/ 13 марта 2011

Вы получаете больше результатов, чем ожидаете, потому что второе условие JOIN удовлетворяется многими строками в таблице статусов (например, существует 3 dateDates ранее, чем 5/4, поэтому эта дата появляется в наборе результатов 3 раза).

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

DROP TABLE IF EXISTS temp;

CREATE TABLE temp AS  -- This temp table is basically the result set you got
 (SELECT c.CustomerName, e.EntryDate, e.EntryValue, s.Detail, s.StatusDate
  FROM Customers c
    INNER JOIN Entires e ON c.CustomerID = e.CustomerID
    LEFT OUTER JOIN Status s ON s.CustomerID = c.CustomersID
                    AND s.StatusDate <= e.EntryDate
  WHERE (c.CustomerName = 'Steve')
 );

SELECT t.CustomerName, t.EntryDate, t.EntryValue, t.Detail
FROM temp t
WHERE t.StatusDate = (SELECT MAX(t2.StatusDate) 
                      FROM temp t2 
                      WHERE t2.EntryDate = t.EntryDate);

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

SELECT t.CustomerName, t.EntryDate, t.EntryValue, t.Detail
FROM (SELECT c.CustomerName, e.EntryDate, e.EntryValue, s.Detail, s.StatusDate
      FROM Customers c
      INNER JOIN Entries e ON c.CustomerID = e.CustomerID
      LEFT OUTER JOIN Status s ON s.CustomerID = c.CustomersID
                      AND s.StatusDate <= e.EntryDate
      WHERE c.CustomerName = 'Steve') AS t
WHERE t.StatusDate = (SELECT MAX(t2.StatusDate)
                      FROM temp t2
                      WHERE t2.EntryDate = t.EntryDate);
0 голосов
/ 12 марта 2011

Ожидаемый вывод неверен.Последний ряд должен быть на дату 04.02.2010.Кроме того, их стоимость заказа также не правы.2/2/2010 должно возвращаться значение NULL, поскольку нет соответствующего статуса.

0 голосов
/ 12 марта 2011

Разве дата статуса не должна приходить после даты заказа? Что-то вроде:

SELECT  Customers.CustomerName, Orders.OrderDate, Orders.OrderCost, Status.Detail
FROM   Customers
    INNER JOIN Orders ON Customers.CustomerID = Orders.CustomerID
    LEFT OUTER JOIN Status ON Status.CustomerID = Customers.CustomersID 
WHERE Customers.CustomerName = 'Steve' AND Status.StatusDate >= Orders.OrderDate

Кроме того, CustomerID в таблице Status кажется немного странным, так как обычно заказы имеют статус, а не заказчик. Разве в таблице состояния не должно быть поля OrderID?

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