di Quassnoi mostra come fare la SUMPRODUCT, e utilizzando una clausola WHERE permetterebbe di limitare da un campo Data ...
SELECT
SUM([tbl].data * [tbl].weight)/SUM([tbl].weight)
FROM
[tbl]
WHERE
[tbl].date >= '2009 Jan 01'
AND [tbl].date < '2010 Jan 01'
La parte più complessa è dove si desidera "specificare dinamicamente" il campo che è [dati] e quale campo è [peso]. La risposta breve è che realisticamente dovresti usare Dynamic SQL. Qualcosa sulla falsariga di:
- Creare una stringa di modello
- Sostituire tutte le istanze di [TBL] .data con il campo i dati appropriati
- Sostituire tutte le istanze di [TBL] .weight con il campo di peso appropriato
- Esegui la stringa
SQL dinamico, tuttavia, svolge il proprio overhead. Le query sono relativamente poco frequenti o il tempo di esecuzione della query è relativamente lungo, ciò potrebbe non avere importanza. Se sono comuni e brevi, tuttavia, si può notare che l'utilizzo di SQL dinamico introduce un notevole overhead. (Per non parlare facendo attenzione degli attacchi di SQL injection, ecc)
EDIT:
Nel tuo esempio lastest di evidenziare tre campi:
Quando il [KPI] è "Peso Y ", quindi [Attuale] il fattore di ponderazione da utilizzare.
Quando [KPI] è "Tonnellate", quindi [Effettivo] è i dati che si desidera aggregare.
Alcune domande che ho sono:
- Esistono altri campi?
- C'è solo UNO effettivo per data per KPI?
La ragione per cui chiedo di voler garantire che il JOIN che fai sia sempre 1: 1.(Se non si desidera 5 effettivi unirsi con 5 pesi, dando record 25 resultsing)
Indipendentemente da ciò, un leggero semplificazione delle query è certamente possibile ...
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'
La linea commentata necessari solo se hai bisogno di predicati aggiuntivi per assicurare una relazione 1: 1 tra i tuoi dati e i pesi.
Se non è possibile guarnatee un solo valore per la data, e non hanno tutti gli altri campi di aderire, è possibile modificare la versione basata sub_query leggermente ...
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
Ciò presuppone che AVG del peso sia valido se sono presenti più pesi per lo stesso giorno.
EDIT: Qualcuno ha appena votato per questo quindi ho pensato di migliorare la risposta finale :)
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
questo modo si evita il join e anche analizza solo la tabella una volta.
Si basa sul fatto che i valori NULL
vengono ignorati durante il calcolo dello AVG()
.
modo l'intervallo di date c'entra? Quante colonne: poche o molte? Il numero di colonne è fisso? –
@martin, solo una colonna. Era uno per KPI, ma non era divertente. L'intervallo di date è per un periodo di riferimento. – ProfK
L'istruzione sopra è considerata un CTE? Se no, come potresti trasformarlo in un CTE? Chiunque? – PositiveGuy