2016-06-26 1 views
0

Я пробовал несколько решений, найденных на вашем сайте, и ничего совсем не совпадают с тем, что мне нужно. В SQL Server мне нужно сделать множественное соединение таблицы с помощью запроса GROUP BY и вернуть только строку TOP 1 из каждой группы. Вот базовый код, который возвращает нужные записи, но возвращает все записи, соответствующие критерии:Возврат TOP n строк из GROUP По запросу с INNER Соединения из нескольких таблиц

SELECT MIN(Maintenance_Log.Log_StartDate) As MaintDate 
    , Manufacturer.Manufacturer_Name 
    , GL_Inventory.Inventory_Model 
    , GL_Inventory.Inventory_SerialNr 
    , Maintenance_Log.Event_ID 
    , Maintenance_Log.Inventory_ID 
FROM Maintenance_Log 
INNER JOIN GL_Inventory ON Maintenance_Log.Inventory_ID = GL_Inventory.Inventory_ID 
INNER JOIN Manufacturer ON GL_Inventory.Manufacturer_ID = Manufacturer.Manufacturer_ID 
WHERE Maintenance_Log.Owner_ID = @OwnerID 
    AND Maintenance_Log.Log_CompletedDate Is Null 
GROUP BY Maintenance_Log.Inventory_ID 
     , Maintenance_Log.Log_StartDate 
     , Manufacturer.Manufacturer_Name 
     , GL_Inventory.Inventory_Model 
     , GL_Inventory.Inventory_SerialNr 
     , Maintenance_Log.Event_ID 

возвращаемых результатов являются:

2016-06-30 09:00:00.000 GLOCK G19 Gen 4 ABDE1234 2 6 
2016-07-28 09:00:00.000 GLOCK G19 Gen 4 ABDE1234 3 6 
2016-08-25 09:00:00.000 GLOCK G19 Gen 4 ABDE1234 4 6 
2016-09-29 09:00:00.000 GLOCK G19 Gen 4 ABDE1234 5 6 
2016-10-27 09:00:00.000 GLOCK G19 Gen 4 ABDE1234 6 6 
2016-11-24 09:00:00.000 GLOCK G19 Gen 4 ABDE1234 7 6 
2016-12-29 09:00:00.000 GLOCK G19 Gen 4 ABDE1234 8 6 
2016-07-01 09:00:00.000 S&W  642   WQ32De45 9 7 
2016-08-05 09:00:00.000 S&W  642   WQ32De45 10 7 
2016-09-02 09:00:00.000 S&W  642   WQ32De45 11 7 
2016-10-07 09:00:00.000 S&W  642   WQ32De45 12 7 
2016-11-04 09:00:00.000 S&W  642   WQ32De45 13 7 
2016-12-02 09:00:00.000 S&W  642   WQ32De45 14 7 

Я хочу вернуть только TOP 1 строку из каждой группы на основе последней цифры в строке, которая представляет собой номер Inventory_ID, а не все строки, соответствующие критериям.

+0

Последняя последняя цифра повторяет – Paparazzi

ответ

0

Это ваш запрос, отформатированный и упрощен с помощью таблицы псевдонимов:

SELECT MIN(l.Log_StartDate) As MaintDate, m.Manufacturer_Name, 
     i.Inventory_Model, i.Inventory_SerialNr, l.Event_ID, l.Inventory_ID 
FROM Maintenance_Log l INNER JOIN 
    GL_Inventory i 
    ON l.Inventory_ID = i.Inventory_ID INNER JOIN 
    Manufacturer m 
    ON i.Manufacturer_ID = m.Manufacturer_ID) 
WHERE l.Owner_ID = @OwnerID AND l.Log_CompletedDate Is Null 
GROUP BY l.Log_StartDate, m.Manufacturer_Name, i.Inventory_Model, 
     i.Inventory_SerialNr, l.Event_ID, l.Inventory_ID ; 

Во-первых, я отмечаю, что Log_StartDate одновременно в GROUP BY и аргумент MIN(). Итак, мне интересно, если это будет исправить вашу проблему:

SELECT MIN(l.Log_StartDate) As MaintDate, m.Manufacturer_Name, 
     i.Inventory_Model, i.Inventory_SerialNr, l.Event_ID, l.Inventory_ID 
FROM Maintenance_Log l INNER JOIN 
    GL_Inventory i 
    ON l.Inventory_ID = i.Inventory_ID INNER JOIN 
    Manufacturer m 
    ON i.Manufacturer_ID = m.Manufacturer_ID) 
WHERE l.Owner_ID = @OwnerID AND l.Log_CompletedDate Is Null 
GROUP BY m.Manufacturer_Name, i.Inventory_Model, 
     i.Inventory_SerialNr, l.Event_ID, l.Inventory_ID ; 

Если вы все еще хотите одну строку для наибольшего inventory_id, то вы можете использовать оконные функции:

WITH t as (
     SELECT MIN(l.Log_StartDate) As MaintDate, m.Manufacturer_Name, 
      i.Inventory_Model, i.Inventory_SerialNr, l.Event_ID, l.Inventory_ID , 
      ROW_NUMBER() OVER (PARTITION BY m.Manufacturer_Name, i.Inventory_Model, i.Inventory_SerialNr, l.Event_ID 
           ORDER BY l.Inventory_ID -- Do you want this ASC or DESC ? 
           ) as seqnum 
     FROM Maintenance_Log l INNER JOIN 
      GL_Inventory i 
      ON l.Inventory_ID = i.Inventory_ID INNER JOIN 
      Manufacturer m 
      ON i.Manufacturer_ID = m.Manufacturer_ID) 
     WHERE l.Owner_ID = @OwnerID AND l.Log_CompletedDate Is Null 
     GROUP BY m.Manufacturer_Name, i.Inventory_Model, 
       i.Inventory_SerialNr, l.Event_ID, l.Inventory_ID 
    ) 
SELECT t.* 
FROM t 
WHERE seqnum = 1; 
+0

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

0
WITH X AS (
SELECT ML.Log_StartDate As MaintDate 
    , M.M_Name 
    , I.Inventory_Model 
    , I.Inventory_SerialNr 
    , ML.Event_ID 
    , ML.Inventory_ID 
    , ROW_NUMBER() OVER (PARTITION BY ML.Inventory_ID 
            ORDER BY ML.Log_StartDate DESC)rn 
FROM Maintenance_Log ML 
INNER JOIN GL_Inventory I ON ML.Inventory_ID = I.Inventory_ID 
INNER JOIN Manufacturer M ON I.M_ID = M.M_ID 
WHERE ML.Owner_ID = @OwnerID 
    AND ML.Log_CompletedDate Is Null 
) 
SELECT MaintDate 
     ,M_Name 
     ,Inventory_Model 
     ,Inventory_SerialNr 
     ,Event_ID 
     ,Inventory_ID 
FROM X 
WHERE RN = 1 
+0

Спасибо М.Али, с некоторыми изменениями это работает отлично. Я действительно оценил помощь. Просто чтобы вы знали, что я сменил ORDER BY на ML.Log_Start ASC, чтобы получить самое раннее сверху и пришлось изменить «INNER JOIN Manufacturer M ON I.M_ID = M.M_ID» на «INNER JOIN Manufacturer M ON I. Manufacturer_ID = M.Manufacturer_ID ". Как только я это сделал, он работает так, как я хотел. Спасибо. – ArtHandy

0

Как правило, в этой ситуации (нужен первый результат из подзапроса для каждой соединяемой строки), CROSS APPLY - это то, что вы хотите.

Принимая во внимание, что INNER JOIN (выберите верхнюю часть 1 ...) будет использовать ту же самую «верхнюю 1» строку для каждой соединяемой строки, CROSS APPLY (select top 1 ...) будет оценивать выражение для каждой соединяемой строки.

Если вам нужно, чтобы он вел себя как LEFT OUTER JOIN (не фильтруя строки без результата в выражении), вместо этого используйте OUTER APPLY.

0

Запрос сделал то, о чем вы просили, из-за уникальности каждой строки.

На основании данных, которые вы опубликовали (с предположением, что первая дата будет иметь наименьшее значение Maintenance_Log.Event_ID), нижеприведенный запрос может быть решением.

SELECT MIN(Maintenance_Log.Log_StartDate) As MaintDate 
    , Manufacturer.Manufacturer_Name 
    , GL_Inventory.Inventory_Model 
    , GL_Inventory.Inventory_SerialNr 
    , MIN(Maintenance_Log.Event_ID) 
    , Maintenance_Log.Inventory_ID 
FROM Maintenance_Log 
INNER JOIN GL_Inventory ON Maintenance_Log.Inventory_ID = GL_Inventory.Inventory_ID 
INNER JOIN Manufacturer ON GL_Inventory.Manufacturer_ID = Manufacturer.Manufacturer_ID 
WHERE Maintenance_Log.Owner_ID = @OwnerID 
    AND Maintenance_Log.Log_CompletedDate Is Null 
GROUP BY Maintenance_Log.Inventory_ID 
     , Maintenance_Log.Log_StartDate 
     , Manufacturer.Manufacturer_Name 
     , GL_Inventory.Inventory_Model 
     , GL_Inventory.Inventory_SerialNr 
     --, Maintenance_Log.Event_ID