Как указать два выражения в списке выбора, когда подзапрос не введен с EXISTS
У меня есть запрос, который использует подзапрос, и у меня возникла проблема с возвращением ожидаемых результатов. Я получаю сообщение об ошибке: "В списке выбора можно указать только одно выражение, если подзапрос не введен в EXISTS". Как я могу переписать это, чтобы работать?
SELECT
a.Part,
b.Location,
b.LeadTime
FROM
dbo.Parts a
LEFT OUTER JOIN dbo.Vendor b ON b.Part = a.Part
WHERE
b.Location IN ('A','B','C')
AND
Date IN (SELECT Location, MAX(Date) FROM dbo.Vendor GROUP BY Location)
GROUP BY
a.Part,
b.Location,
b.LeadTime
ORDER BY
a.Part
3 ответа
Я думаю, что-то вроде этого может быть то, что вы ищете. Вы не сказали, какая версия SQL Server- это работает в SQL 2005 и выше:
SELECT
p.Part,
p.Location, -- from *p*, otherwise if no match we'll get a NULL
v.LeadTime
FROM
dbo.Parts p
OUTER APPLY (
SELECT TOP (1) * -- * here is okay because we specify columns outside
FROM dbo.Vendor v
WHERE p.Location = v.Location -- the correlation part
ORDER BY v.Date DESC
) v
WHERE
p.Location IN ('A','B','C')
ORDER BY
p.Part
;
Теперь ваш запрос можно исправить как есть, добавив часть "корреляция", чтобы изменить ваш запрос на correlated subquery
как показано в ответе Кори (вы также удалите GROUP BY
пункт). Однако этот метод все еще требует дополнительного и ненужного объединения, что снижает производительность, плюс он может извлекать только один столбец за раз. Этот метод позволяет вам извлечь все столбцы из другой таблицы и не имеет дополнительного объединения.
Примечание: это логически дает те же результаты, что и ответ Ламака, однако я предпочитаю его по нескольким причинам:
- Когда есть индекс на столбцах корреляции (
Location
здесь) это может быть удовлетворено поисками, ноRow_Number
Решение должно сканировать (я считаю). - Я предпочитаю, чтобы это выражало намерение запроса более прямо и кратко. в
Row_Number
метод, нужно выйти во внешнее состояние, чтобы увидеть, что мы только хватаемrn = 1
значения, затем вернитесь в CTE, чтобы увидеть, что это такое. - С помощью
CROSS APPLY
или жеOUTER APPLY
все остальные таблицы, не участвующие в выборе "одна внутренняя строка на внешнюю строку", находятся вне того места, где (для меня) они принадлежат. Мы не скупимся на проблемы вместе. С помощьюRow_Number
чувствует себя немного как бросатьDISTINCT
на запрос, чтобы исправить дублирование, а не заниматься основной проблемой. Я думаю, что это в основном та же проблема, что и предыдущий пункт, сформулированный по-другому. - В тот момент, когда у вас есть ДВЕ таблицы, из которых вы хотите извлечь самое последнее значение,
Row_Number()
раствор взрывается полностью. С этим синтаксисом вы просто легко добавляете другойAPPLY
пункт, и это совершенно ясно, что вы делаете. Есть способ использоватьRow_Number
для сценария с несколькими таблицами, перемещая другие таблицы за пределы, но я все еще не предпочитаю этот синтаксис. - Использование этого синтаксиса позволяет выполнять дополнительные объединения в зависимости от того, существует выбранная строка или нет (в случае, если соответствующая строка не была найдена). в
Row_Number
решение, вы можете только разумно сделать этоNOT NULL
проверка во внешнем запросе - так что вы вынуждены разделить запрос на несколько отдельных частей (вы не хотите присоединяться к значениям, которые вы отбрасываете!).
PS Я настоятельно рекомендую вам использовать псевдонимы, которые указывают на таблицу, которую они представляют. Пожалуйста, не используйте a
а также b
, я использовал p
за Parts
а также v
за Vendor
- это поможет вам и другим быстрее разобраться в запросе.
Если я вас правильно понял, вы хотите строки с максимальной датой для местоположений A, B и C. Теперь, предполагая SQL Server 2005+, вы можете сделать это:
;WITH CTE AS
(
SELECT
a.Part,
b.Location,
b.LeadTime,
RN = ROW_NUMBER() OVER(PARTITION BY a.Part ORDER BY [Date] DESC)
FROM
dbo.Parts a
LEFT OUTER JOIN dbo.Vendor b ON b.Part = a.Part
WHERE
b.Location IN ('A','B','C')
)
SELECT Part,
Location,
LeadTime
FROM CTE
WHERE RN = 1
ORDER BY Part
В вашем подзапросе вы должны соотнести местоположение и деталь с внешним запросом. Пример:
Date = (SELECT MAX(Date)
FROM dbo.Vender v
WHERE v.Location = b.Location
AND v.Part = b.Part
)
Так что это вернет одну дату для каждого места и части