#sql #ms-access-2013
#sql #ms-access-2013
Вопрос:
У меня есть три таблицы, которые необходимо объединить, чтобы получить взамен ежемесячные данные инвентаризации.
Таблица 1: TargetInventory
Таблица 2: targetValue
Таблица 3: TargetWeight
[TargetInventory] не изменяется после добавления в первый раз.
[targetValue] — это всего лишь небольшая таблица, которая включает цены на различные виды металла.
[TargetWeight] обновляется ежемесячно в рамках нашего процесса инвентаризации. Мы ВСТАВЛЯЕМ новые данные, мы никогда не ОБНОВЛЯЕМ старые данные.
Ниже приведена взаимосвязь между этими таблицами. (Извините, у меня нет очков репутации для публикации изображения. Здесь совершенно новый, так что, надеюсь, это имеет смысл.)
(* = UniqueKey)
--TargetValue-- --TargetInventory-- --TargetWeight--
*MaterialID <===| *TargetID <=====| *ID
Material |===> MaterialID |===> TargetID
PricePerOunce Length RecordDate
Density Width Weight
Thickness
DateInInventory
Таблица TargetWeight содержит несколько записей для TargetID (поскольку новая добавляется каждый месяц при инвентаризации). Это хорошо для меня, чтобы отслеживать историческое использование, но для текущей стоимости запасов мне нужен только самый последний целевой вес.Возвращаемый вес.
Я не знаю, как выполнить ПЕРЕКРЕСТНОЕ ПРИМЕНЕНИЕ из другого ВНУТРЕННЕГО СОЕДИНЕНИЯ, поэтому я в недоумении, как это сделать (не переключаясь на MySQL и просто выполняя ОГРАНИЧЕНИЕ 1 …)
Я думаю, что это должно выглядеть примерно так, как показано ниже, но я не уверен, как завершить запрос.
SELECT
TargetInventory.TargetID AS TargetInventory_TargetID,
TargetInventory.MaterialID AS TargetInventory_MaterialID,
TargetInventory.Length,
TargetInventory.Width,
TargetInventory.Thickness,
TargetValue.MaterialID AS TargetValue_MaterialID,
TargetValue.PricePerOunce,
TargetValue.Density,
TargetWeight.ID,
TargetWeight.TargetID AS TargetWeight_TargetID,
TargetWeight.RecordDate,
TargetWeight.Weight
FROM
(TargetValue
INNER JOIN TargetInventory
ON TargetValue.[MaterialID] = TargetInventory.[MaterialID]
)
CROSS APPLY (
SELECT TOP 1 *
FROM .....
)
Ответ №1:
Следующий запрос работает для меня в Access 2010. Он использует ВНУТРЕННЕЕ СОЕДИНЕНИЕ в подзапросе, чтобы заменить ПЕРЕКРЕСТНОЕ ПРИМЕНЕНИЕ (которое Access SQL не поддерживает). Предполагается, что для данного (TargetID, recordDate) будет не более одной записи [TargetWeight]:
SELECT
TargetInventory.TargetID AS TargetInventory_TargetID,
TargetInventory.MaterialID AS TargetInventory_MaterialID,
TargetInventory.Length,
TargetInventory.Width,
TargetInventory.Thickness,
TargetValue.MaterialID AS TargetValue_MaterialID,
TargetValue.PricePerOunce,
TargetValue.Density,
LatestWeight.ID,
LatestWeight.TargetID AS TargetWeight_TargetID,
LatestWeight.RecordDate,
LatestWeight.Weight
FROM
(
TargetValue
INNER JOIN
TargetInventory
ON TargetValue.[MaterialID] = TargetInventory.[MaterialID]
)
INNER JOIN
(
SELECT tw.*
FROM
TargetWeight AS tw
INNER JOIN
(
SELECT TargetID, MAX(RecordDate) AS LatestDate
FROM TargetWeight
GROUP BY TargetID
) AS latest
ON latest.TargetID=tw.TargetID
AND latest.LatestDate=tw.RecordDate
) AS LatestWeight
ON LatestWeight.TargetID = TargetInventory.TargetID
Альтернативный подход специально для Access 2010 или более поздней версии
Если приведенный выше запрос зависает с большим количеством строк в [TargetWeight], то другим возможным решением для Access 2010 было бы добавить Yes/No
поле с именем [Current] в таблицу [TargetWeight] и использовать следующий после вставки данных макрос, чтобы гарантировать, что только последняя запись для каждого [TargetID]помечается как [Текущий]:
Как только это будет сделано, запрос будет просто
SELECT
TargetInventory.TargetID AS TargetInventory_TargetID,
TargetInventory.MaterialID AS TargetInventory_MaterialID,
TargetInventory.Length,
TargetInventory.Width,
TargetInventory.Thickness,
TargetValue.MaterialID AS TargetValue_MaterialID,
TargetValue.PricePerOunce,
TargetValue.Density,
TargetWeight.ID,
TargetWeight.TargetID AS TargetWeight_TargetID,
TargetWeight.RecordDate,
TargetWeight.Weight
FROM
(
TargetValue
INNER JOIN
TargetInventory
ON TargetValue.[MaterialID] = TargetInventory.[MaterialID]
)
INNER JOIN
TargetWeight
ON TargetInventory.TargetID = TargetWeight.TargetID
WHERE TargetWeight.Current = True;
Чтобы максимизировать производительность, [TargetWeight] .[TargetID] и [TargetWeight] .[Текущие] поля должны быть проиндексированы.
Ответ №2:
SELECT TargetInventory.TargetID AS TargetInventory_TargetID,
TargetInventory.MaterialID AS TargetInventory_MaterialID,
TargetInventory.Length,
TargetInventory.Width,
TargetInventory.Thickness,
TargetValue.MaterialID AS TargetValue_MaterialID,
TargetValue.PricePerOunce,
TargetValue.Density, Weight.ID,
Weight.TargetID AS TargetWeight_TargetID,
Weight.RecordDate,
Weight.Weight
FROM TargetInventory
INNER JOIN TargetValue ON TargetValue.[MaterialID] = TargetInventory.[MaterialID]
CROSS APPLY (
SELECT TOP 1 *
FROM TargetWeight
WHERE TargetID = TargetInventory.TargetID
ORDER BY RecordDate DESC
) AS Weight
Комментарии:
1. Этот запрос T-SQL работает в SQL Server, но не в Access.
2. Работает до тех пор, пока не БУДЕТ НАНЕСЕН КРЕСТ. Я могу удалить аргумент ПЕРЕКРЕСТНОГО ПРИМЕНЕНИЯ, и форма работает нормально. Но вместе с этим я получаю «Синтаксическую ошибку (пропущенная операция) в выражении запроса»targetValue. [MaterialID] = TargetInventory . [MaterialID] …..’ и продолжается до конца запроса. Как ни странно, ошибка исключает последний символ и заменяет его одинарной кавычкой. Не уверен, что это нормально.
3. @GordThompson Можете ли вы порекомендовать другое решение, которое будет работать с Access? Я также могу просто запустить два разных запроса и объединить их в отчете. Может быть лучшим вариантом.
4. О, я понимаю, я не знал об этом ограничении доступа. Другое решение, которое, я полагаю, сработало бы, — поместить часть «веса» на уровень выбора запроса. Однако @GordThompson дал лучшее решение. Спасибо.