Выберите топ 1 для каждой группы - PullRequest
1 голос
/ 21 июля 2010

У меня есть база данных Access, которая содержит таблицу с информацией о деталях, которые мы сортируем.В этой таблице есть поле идентификатора автономного номера и 110ID, который связан с другой таблицей с информацией о детали.Он также содержит sortDate, sortShift, отсортированный, удаленный и восстановленный.Мне нужно выяснить, сколько деталей было отсортировано с момента обнаружения последнего дефекта (ни одного бракованного или отремонтированного) для каждого 110ID.

Проблема в том, что я не могу гарантировать, что информация будет внесена в базу данных в хронологическомпорядок.Поэтому мне нужно суммировать поле «sorted» для любых записей, у которых «sortDate» больше, чем последний дефект, или «sortDate» такой же, как последний дефект, но больше «sortShift», или использовать идентификатор автонумера в качестве последнего средстваесли 'sortDate' и 'sortShift' совпадают.

Это запрос, который я сейчас использую:

SELECT SortInfo.[110ID], Sum(SortInfo.Sorted) AS SumOfSorted
FROM SortInfo
WHERE (
    ((SortInfo.sortdate)>(select top 1 dupe.sortdate from sortinfo as dupe where     (((dupe.[110id])=(sortinfo.[110id])) and (((dupe.repaired)<>0) or ((dupe.scrapped)<>0))) order by dupe.sortdate desc, dupe.sortshift desc, dupe.id desc)))
    OR (((SortInfo.sortdate)=(select top 1 dupe.sortdate from sortinfo as dupe where (((dupe.[110id])=(sortinfo.[110id])) and (((dupe.repaired)<>0) or ((dupe.scrapped)<>0))) order by dupe.sortdate desc, dupe.sortshift desc, dupe.id desc)) 
        AND ((SortInfo.sortshift)>(select top 1 dupe.sortshift from sortinfo as dupe where (((dupe.[110id])=(sortinfo.[110id])) and (((dupe.repaired)<>0) or ((dupe.scrapped)<>0))) order by dupe.sortdate desc, dupe.sortshift desc, dupe.id desc))) 
    OR (((SortInfo.sortdate)=(select top 1 dupe.sortdate from sortinfo as dupe where (((dupe.[110id])=(sortinfo.[110id])) and (((dupe.repaired)<>0) or ((dupe.scrapped)<>0))) order by dupe.sortdate desc, dupe.sortshift desc, dupe.id desc)) 
        AND ((SortInfo.sortshift)=(select top 1 dupe.sortshift from sortinfo as dupe where (((dupe.[110id])=(sortinfo.[110id])) and (((dupe.repaired)<>0) or ((dupe.scrapped)<>0))) order by dupe.sortdate desc, dupe.sortshift desc, dupe.id desc)) 
        AND ((SortInfo.ID)>(select top 1 dupe.id from sortinfo as dupe where (((dupe.[110id])=(sortinfo.[110id])) and (((dupe.repaired)<>0) or ((dupe.scrapped)<>0))) order by dupe.sortdate desc, dupe.sortshift desc, dupe.id desc))
)
GROUP BY SortInfo.[110ID];

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

1 Ответ

0 голосов
/ 21 июля 2010

Вместо использования всех этих подзапросов вы можете сделать это либо с помощью ЛЕВОГО ВНЕШНЕГО СОЕДИНЕНИЯ, либо подзапроса NOT EXISTS.Я не очень часто пользуюсь Access, поэтому вам может понадобиться настроить их, если это одна из тех областей, где Access не соответствует стандарту ANSI.

SELECT
    SI.[110ID],
    SUM(SI.Sorted) AS SumOfSorted
FROM
    SortInfo SI
LEFT OUTER JOIN SortInfo SI2 ON
    SI2.Repaired <> 0 AND
    SI2.Scrapped <> 0 AND
    (
        SI2.SortDate > SI.SortDate OR
        (SI2.SortDate = SI.SortDate AND SI2.SortShift > SI.SortShift) OR
        (SI2.SortDate = SI.SortDate AND SI2.SortShift = SI.SortShift AND SI2.ID > SI.ID)
    )
WHERE
    SI2.ID IS NULL
GROUP BY
    SI.[110ID]

SELECT
    SI.[110ID],
    SUM(SI.Sorted) AS SumOfSorted
FROM
    SortInfo SI
WHERE
    NOT EXISTS
    (
        SELECT *
        FROM
            SortInfo SI2
        WHERE
            SI2.Repaired <> 0 AND
            SI2.Scrapped <> 0 AND
            (
                SI2.SortDate > SI.SortDate OR
                (SI2.SortDate = SI.SortDate AND SI2.SortShift > SI.SortShift) OR
                (SI2.SortDate = SI.SortDate AND SI2.SortShift = SI.SortShift AND SI2.ID > SI.ID)
            )    
    GROUP BY
        SI.[110ID]
    )
...