2015-11-09 3 views
1

Я немного новичок в SQL Server, и я пытаюсь выполнить очень простой запрос, который идет как:SQL Server макс Datetime

SELECT 
    ProductID, o.OrderID, o.CustomerID, CompanyName,OrderDate, Quantity 
FROM 
    o 
JOIN 
    [Order Details] od on o.OrderID = od.OrderID 
JOIN 
    Customers c on c.CustomerID = o.CustomerID 
WHERE 
    orderdate = (select max(OrderDate) 
       from o 
       where ProductID = od.ProductID) 

А потом я получил это.

ProductID  OrderID  CustomerID  CompanyName  OrderDate  Quantity 
2  11077  RATTC  Rattlesnake Canyon Grocery  1998-05-07 09:50:47.000  24 
3  11077  RATTC  Rattlesnake Canyon Grocery  1998-05-07 09:50:47.000  4 
4  11077  RATTC  Rattlesnake Canyon Grocery  1998-05-07 09:50:47.000  1 
6  11077  RATTC  Rattlesnake Canyon Grocery  1998-05-07 09:50:47.000  1 
7  11077  RATTC  Rattlesnake Canyon Grocery  1998-05-07 09:50:47.000  1 
8  11077  RATTC  Rattlesnake Canyon Grocery  1998-05-07 09:50:47.000  2 
10  11077  RATTC  Rattlesnake Canyon Grocery  1998-05-07 09:50:47.000  1 
12  11077  RATTC  Rattlesnake Canyon Grocery  1998-05-07 09:50:47.000  2 
13  11077  RATTC  Rattlesnake Canyon Grocery  1998-05-07 09:50:47.000  4 
14  11077  RATTC  Rattlesnake Canyon Grocery  1998-05-07 09:50:47.000  1 
16  11077  RATTC  Rattlesnake Canyon Grocery  1998-05-07 09:50:47.000  2 
20  11077  RATTC  Rattlesnake Canyon Grocery  1998-05-07 09:50:47.000  1 
23  11077  RATTC  Rattlesnake Canyon Grocery  1998-05-07 09:50:47.000  2 
32  11077  RATTC  Rattlesnake Canyon Grocery  1998-05-07 09:50:47.000  1 

, но я хочу получить самый новый заказ на каждый идентификатор продукта. Как это:

enter image description here

Так что я должен сделать, чтобы получить это?

ответ

1

Это должно вас начать. Я предполагаю, что у Order Details есть позиции заказа.

SELECT 
    p.ProductID, 
    o.OrderID, 
    o.CustomerID, 
    o.CompanyName, 
    o.OrderDate 
FROM 
    dbo.Products p 
    CROSS APPLY (
     SELECT TOP 1 * 
     FROM dbo.Orders o 
     WHERE EXISTS (
      SELECT * 
      FROM dbo.[Order Details] od 
      WHERE 
       o.OrderID = od.OrderID 
       AND p.ProductID = od.ProductID 
     ) 
     ORDER BY o.OrderDate DESC 
    ) o 
    INNER JOIN dbo.Customers c 
     ON o.CustomerID = c.CustomerID 
; 

Я предположил, что [Order Details] строки могут иметь один и тот же OrderID дважды, что делает вещи немного более сложным, чтобы получить Quantity (который я ушел из). Вы хотите, чтобы это количество суммировалось или отображалось два ряда? В зависимости от того, какой результат вы хотите и как реализуется эта таблица, это может быть решением, которое вы хотите:

SELECT 
    p.ProductID, 
    odq.OrderID, 
    odq.CustomerID, 
    odq.CompanyName, 
    odq.OrderDate, 
    odq.Quantity 
FROM 
    dbo.Products p 
    CROSS APPLY (
     SELECT TOP 1 * 
     FROM dbo.Orders o 
     CROSS APPLY (
      SELECT TotalQuantity = Sum(Quantity) 
      FROM dbo.[Order Details] od 
      WHERE 
       o.OrderID = od.OrderID 
       AND p.ProductID = od.ProductID 
     ) odq 
     ORDER BY o.OrderDate DESC 
    ) odq 
    INNER JOIN dbo.Customers c 
     ON o.CustomerID = c.CustomerID 
; 

Этот запрос должен выполнять хорошо до тех пор, пока у вас есть соответствующие индексы таблиц (Order Details должны иметь индекс ProductID, OrderID и Orders должен иметь индекс, начинающийся с ProductID, OrderDate). Его производительность должна оставаться неизменной по мере роста данных системы.

Я предположил, что у вас есть таблица dbo.Products, и, изменив с CROSS APPLY на OUTER APPLY (первый), вы можете показывать товары, у которых нет заказов. С другой стороны, есть еще один возможный запрос:

WITH OrderSequences AS (
    SELECT 
     Sequence = Rank() OVER (PARTITION BY od.ProductID ORDER BY o.OrderDate DESC), 
     o.*, 
     od.ProductID, 
     od.Quantity 
    FROM 
     dbo.Orders o 
     INNER JOIN dbo.[Order Details] od 
     ON o.OrderID = od.OrderID 
) 
SELECT 
    o.OrderID, 
    o.CustomerID, 
    o.CompanyName, 
    o.OrderDate, 
    o.ProductID, 
    o.Quantity 
FROM 
    OrderSequences o 
    INNER JOIN dbo.Customers c 
     ON o.CustomerID = c.CustomerID 
WHERE 
    Sequence = 1 
; 

Опять же, если вы можете иметь один и тот же OrderID на более чем одной линии в порядке (очень вероятно, вещь, на мой взгляд), то вам нужно сделать какой-то суммирования или допускать повторяющиеся строки, которые он будет генерировать (так как он будет показывать BOTH строк в том же порядке, если они были вместе, в последний раз, когда ProductID был заказан).

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

+0

спасибо! я понял! –

0
WITH X AS 
(SELECT ProductID 
     , o.OrderID 
     , o.CustomerID 
     , CompanyName 
     ,OrderDate 
     , Quantity 
     ,ROW_NUMBER() OVER (PARTITION BY od.productid ORDER BY o.OrderDate DESC) rn 
FROM [Orders] o 
JOIN [Order Details] od on o.OrderID = od.OrderID 
join Customers c  on c.CustomerID=o.CustomerID 
) 
SELECT ProductID 
     , OrderID 
     , CustomerID 
     , CompanyName 
     , OrderDate 
     , Quantity 
FROM X 
WHERE rn = 1 

ИЛИ

SELECT ProductID 
     , OrderID 
     , CustomerID 
     , CompanyName 
     , OrderDate 
     , Quantity 
FROM 
(SELECT ProductID 
     , o.OrderID 
     , o.CustomerID 
     , CompanyName 
     ,OrderDate 
     , Quantity 
     ,ROW_NUMBER() OVER (PARTITION BY od.productid ORDER BY o.OrderDate DESC) rn 
FROM [Orders] o 
JOIN [Order Details] od on o.OrderID = od.OrderID 
join Customers c  on c.CustomerID=o.CustomerID 
)x 
WHERE rn = 1 
+0

Что делать, если один заказ может иметь несколько строк в 'Order Details' с тем же« ProductID »? Кроме того, этот запрос будет довольно тяжелым, потому что он вычисляет «ROW_NUMBER» вместе с соединением, а не вычисляет его перед присоединением. – ErikE

+0

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

+0

Я не думаю, что вы исправили проблему. Две строки в «Детали заказа» для тех же «OrderID» и «ProductID» не будут учитываться. Этот метод запроса также будет медленнее, так как таблица заполняет данные, поскольку в значительной степени требуется сканирование. – ErikE

0

Использование MAX(OrderDate) в подзапроса, нет ничего, чтобы соотнести максимум (дата) с ProductID в родительском запросе. Таким образом, вы всегда получите все заказы, в которых есть Макс (дата) , первый ProductID из заявки-продукта.

Лучший способ сделать этот фильтр - присоединиться к таблице заказов o.

SELECT ProductID, o.OrderID, o.CustomerID, CompanyName,OrderDate, Quantity 
FROM o 

LEFT JOIN o2 ON o.ProductID = o2.ProductID AND o2.OrderDate > o.OrderDate 

JOIN [Order Details] od on o.OrderID = od.OrderID 
join Customers c on c.CustomerID=o.CustomerID 

WHERE o2.OrderDate IS NULL 

Итак, мы присоединяемся все заказы продукта со всеми другими порядками того же продукта, которые имеют большую OrderDate, а затем фильтрации для одного, который не имеет не больше даты заказа, так что o.OrderDate будет быть MAX(OrderDate) для каждого ProductID

(Отказ от ответственности: Вышеуказанный SQL не тестируется и может потребовать модификации для того, чтобы должным образом работать на вашей базе данных, но идея должна работать для ваших нужд.)

+0

благодарим за ответ! –