T SQL - красноречивая замена коррелированного подзапроса - PullRequest
6 голосов
/ 10 ноября 2008

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

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

    
ItemId    ItemVersionId    Year    Value
===========================================
1         1                01      0.1
1         1                02      0.1
1         1                03      0.2
1         1                04      0.2
1         1                05      0.2
1         1                06      0.3
1         1                07      0.3
1         1                08      0.4
1         2                04      0.3
1         2                05      0.3
1         2                06      0.3
1         2                07      0.4
1         2                08      0.5
1         3                07      0.6
1         3                08      0.7
2         1                01      0.1
2         1                01      0.1
2         1                01      0.2
etc

Я хочу вернуть полный профиль для элемента, используя самую последнюю версию, где это применимо. Для приведенного выше примера для элемента 1:

ItemId    ItemVersionId    Year    Value
===========================================
1         1                01      0.1
1         1                02      0.1
1         1                03      0.2
1         2                04      0.3
1         2                05      0.3
1         2                06      0.3
1         3                07      0.6
1         3                08      0.7

Я сейчас использую

SELECT ItemId, ItemVersionId, Year, Value
FROM table t
WHERE
    ItemId = 1
    AND ItemVersionId = (SELECT MAX(ItemVersionId) FROM table WHERE ItemId = t.ItemId AND Year = t.Year)   

Хотя это возвращает правильное значение, я подозреваю, что есть более эффективный способ сделать это, особенно когда таблица становится большой.

Я использую SQL Server 2005.

Заранее спасибо

Ответы [ 3 ]

5 голосов
/ 10 ноября 2008

Я бы сделал это с CTE:

WITH Result AS
(
  SELECT Row_Number() OVER (PARTITION BY ItemId, Year
ORDER BY ItemversionId DESC) AS RowNumber
      ,ItemId
      ,ItemversionId
      ,Year
      ,Value
  FROM table
)
SELECT ItemId
  ,ItemversionId
  ,Year
  ,Value
FROM Result
WHERE RowNumber = 1
ORDER BY ItemId, Year
0 голосов
/ 10 ноября 2008

Это должно работать, хотя вам придется тестировать производительность с вашими собственными данными:

SELECT
    T1.ItemID,
    T1.ItemVersionID,
    T1.Year,
    T1.Value
FROM
    MyTable T1
INNER JOIN (SELECT Year, MAX(ItemVersionID) AS MaxItemVersionID FROM MyTable T2 WHERE T2.ItemID = 1 GROUP BY Year) SQ ON
    SQ.Year = T1.Year AND
    SQ.MaxItemVersionID = T1.ItemVersionID
WHERE
    T1.ItemID = 1

Кроме того, вы можете изменить подзапрос так, чтобы он также группировался и возвращал ItemID, чтобы вы могли возвращать данные для более чем одного элемента за раз, если вам нужно для какой-то другой части вашего приложения. Обязательно добавьте ItemID к критериям объединения.

0 голосов
/ 10 ноября 2008

Я думаю, это нормально, как ты это делаешь. Вы можете проверить, существует ли составной индекс для ItemId и Year .

Вы можете проверить план запроса, чтобы увидеть влияние этого запроса.

Если в вашей базе данных есть таблица «Item», вы можете попробовать другой подход. Вставьте столбец ItemVersionId в эту таблицу и убедитесь, что вы обновляете это значение при сохранении новых версий. Затем в вашем запросе объедините таблицу Item, используя ItemId и ItemVersionId вместо использования этого подзапроса.

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