Quassnoi показывает, как сделать SUMPRODUCT, и с помощью ИНЕК позволит ограничить поле Date ...
SELECT
SUM([tbl].data * [tbl].weight)/SUM([tbl].weight)
FROM
[tbl]
WHERE
[tbl].date >= '2009 Jan 01'
AND [tbl].date < '2010 Jan 01'
Более сложная часть - это то, где вы хотите «динамически указать», какое поле [данные] и какое поле [вес]. Короткий ответ заключается в том, что вам реально придется использовать Dynamic SQL. Что-то вдоль линий:
- Создать строку шаблона
- Заменить все экземпляры [TBL] .data с полем соответствующие данные
- Заменить все экземпляры [TBL] .Weight с соответствующим полем веса
- Выполнить строку
Динамический SQL, однако, несет в себе собственные накладные расходы. Являются ли запросы относительно нечастыми, или время выполнения самого запроса относительно велико, это может быть неважно. Однако, если они являются общими и короткими, вы можете заметить, что использование динамического sql вводит заметные служебные данные. (Не говоря уже быть осторожным атак SQL-инъекции и т.д.)
EDIT:
В вашем примере вы Lastest выделить три поля:
Когда [KPI] является «Весом» Y ", затем [Фактический] Используемый весовой коэффициент.
Когда [KPI] является «Tons Milled», тогда [Actual] - данные, которые вы хотите скопировать.
Некоторые вопросы у меня есть следующие:
- Есть ли какие-либо другие поля?
- Есть ли когда-либо ТОЛЬКО один раз в день за KPI?
Причина, по которой я хочу сказать, что вы хотите, чтобы JOIN вы делали, это только 1: 1.(Вы не хотите 5 Actuals присоединения с 5 Массы, давая 25 resultsing записей)
Несмотря на это, небольшое упрощение вашего запроса, конечно, возможно ...
SELECT
SUM([baseSeries].Actual * [weightSeries].Actual)/SUM([weightSeries].Actual)
FROM
CalcProductionRecords AS [baseSeries]
INNER JOIN
CalcProductionRecords AS [weightSeries]
ON [weightSeries].RecordDate = [baseSeries].RecordDate
-- AND [weightSeries].someOtherID = [baseSeries].someOtherID
WHERE
[baseSeries].KPI = 'Tons Milled'
AND [weightSeries].KPI = 'Weighty'
Закомментированный из линии только необходимы, если вам нужны дополнительные предикаты, чтобы обеспечить соотношение 1: 1 между вашими данными и весами.
Если вы не можете guarnatee только одно значение даты, и не имеют каких-либо других областях, чтобы присоединиться, вы можете изменить ваш sub_query на основе версии немного ...
SELECT
SUM([baseSeries].Actual * [weightSeries].Actual)/SUM([weightSeries].Actual)
FROM
(
SELECT
RecordDate,
SUM(Actual)
FROM
CalcProductionRecords
WHERE
KPI = 'Tons Milled'
GROUP BY
RecordDate
)
AS [baseSeries]
INNER JOIN
(
SELECT
RecordDate,
AVG(Actual)
FROM
CalcProductionRecords
WHERE
KPI = 'Weighty'
GROUP BY
RecordDate
)
AS [weightSeries]
ON [weightSeries].RecordDate = [baseSeries].RecordDate
Это предполагает, что AVG веса действителен, если в тот же день имеется несколько весов.
EDIT: Кто-то голосовал за это, так я думал, что улучшить окончательный ответ :)
SELECT
SUM(Actual * Weight)/SUM(Weight)
FROM
(
SELECT
RecordDate,
SUM(CASE WHEN KPI = 'Tons Milled' THEN Actual ELSE NULL END) AS Actual,
AVG(CASE WHEN KPI = 'Weighty' THEN Actual ELSE NULL END) AS Weight
FROM
CalcProductionRecords
WHERE
KPI IN ('Tons Milled', 'Weighty')
GROUP BY
RecordDate
)
AS pivotAggregate
Это позволяет избежать JOIN, а также только сканирует таблицу один раз.
Он полагается на то, что значения NULL
игнорируются при расчете AVG()
.
Как диапазон дат войти в него? Сколько столбцов - несколько или много? Исправлено ли количество столбцов? –
@martin, только один столбец. Раньше он был одним на KPI, но это было не весело. Диапазон дат за отчетный период. – ProfK
Является ли вышеприведенное заявление рассмотренным CTE? Если не так, как вы можете превратить это в CTE? Кто угодно? – PositiveGuy