2009-11-08 11 views
11

मैं आंकड़ों की दो पंक्तियों से भारित औसत प्राप्त करने का एक तरीका ढूंढ रहा हूं, जहां औसत औसत है (एक्सेल नोटेशन उधार लेना):टी-एसक्यूएल (एक्सेल के SUMPRODUCT की तरह) में भारित औसत

(A1*B1)+(A2*B2)+...+(An*Bn)/SUM(A1:An) 

पहला भाग एक्सेल के SUMPRODUCT() फ़ंक्शन के समान कार्यक्षमता को दर्शाता है।

मेरी पकड़ यह है कि मुझे गतिशील रूप से निर्दिष्ट करने की आवश्यकता है कि कौन सी पंक्ति वजन के साथ औसत हो जाती है, और वजन किस पंक्ति से आता है, और एक तिथि सीमा होती है।

संपादित करें: यह मेरे विचार से आसान है, क्योंकि एक्सेल मुझे सोच रहा था कि मुझे किसी प्रकार का पिवट चाहिए। मेरे समाधान अब तक इस प्रकार है:

select sum(baseSeries.Actual * weightSeries.Actual)/sum(weightSeries.Actual) 
from (
    select RecordDate , Actual 
    from CalcProductionRecords 
    where KPI = 'Weighty' 
) baseSeries inner join (  
    select RecordDate , Actual 
    from CalcProductionRecords 
    where KPI = 'Tons Milled' 
) weightSeries on baseSeries.RecordDate = weightSeries.RecordDate 
+0

कैसे तिथि सीमा में आता है की कोशिश? कितने कॉलम - कुछ या बहुत सारे? कॉलम की संख्या तय है? –

+0

@ मार्टिन, सिर्फ एक कॉलम। यह प्रति केपीआई प्रति एक था, लेकिन यह मजेदार नहीं था। दिनांक सीमा एक रिपोर्टिंग अवधि के लिए है। – ProfK

+0

क्या उपरोक्त कथन एक सीटीई माना जाता है? यदि नहीं, तो आप इसे सीटीई में कैसे बदल सकते हैं? किसी को? – PositiveGuy

उत्तर

13

Quassnoi के जवाब से पता चलता SUMPRODUCT कैसे करना है, और कहां खंड आप एक दिनांक फ़ील्ड से प्रतिबंधित करने की अनुमति होगी एक का उपयोग कर ...

SELECT 
    SUM([tbl].data * [tbl].weight)/SUM([tbl].weight) 
FROM 
    [tbl] 
WHERE 
    [tbl].date >= '2009 Jan 01' 
    AND [tbl].date < '2010 Jan 01' 

अधिक जटिल हिस्सा वह जगह है जहां आप "गतिशील रूप से निर्दिष्ट" करना चाहते हैं कि कौन सा क्षेत्र [डेटा] है और [फ़ील्ड] क्या फ़ील्ड है। संक्षिप्त जवाब यह है कि वास्तव में आपको गतिशील एसक्यूएल का उपयोग करना होगा। की तर्ज पर कुछ:
- बनाएँ एक स्ट्रिंग टेम्पलेट
- उपयुक्त डेटा क्षेत्र
साथ .data की [tbl] सब बदल दें - [tbl] उचित वजन क्षेत्र
साथ .weight के सभी उदाहरणों बदलें - स्ट्रिंग

डायनामिक एसक्यूएल निष्पादित करें, हालांकि, इसका अपना ओवरहेड होता है। क्या प्रश्न अपेक्षाकृत कम हैं, या क्वेरी का निष्पादन समय अपेक्षाकृत लंबा है, इससे कोई फर्क नहीं पड़ता। यदि वे आम और छोटे हैं, हालांकि, आप देख सकते हैं कि गतिशील एसक्यूएल का उपयोग करके एक उल्लेखनीय ओवरहेड पेश किया जाता है। (नहीं एसक्यूएल इंजेक्शन हमलों से सावधान किया जा रहा है उल्लेख करने के लिए, आदि)

संपादित करें:

अपने नवीनतम उदाहरण में आप तीन क्षेत्रों पर प्रकाश डाला:

  • RecordDate
  • KPI
  • वास्तविक

जब [केपीआई] "वजन वाई ", फिर [वास्तविक] उपयोग करने के लिए वज़न फैक्टर।
जब [केपीआई] "टोंस मिल्ड" होता है, तो [वास्तविक] वह डेटा होता है जिसे आप एकत्र करना चाहते हैं।


कुछ सवाल मेरे पास है कर रहे हैं:

  • वहाँ किसी भी अन्य क्षेत्रों रहे हैं?
  • क्या प्रति केपीआई प्रति दिन केवल एक वास्तविक वास्तविक है?

कारण मैं पूछता हूं कि आप यह सुनिश्चित करना चाहते हैं कि आप जो जॉइन करते हैं वह केवल 1: 1 है।(आप नहीं है 5 वास्तविक 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 

यह मानता है कि वज़न के एवीजी वैध हैं यदि उसी दिन कई वजन होते हैं।


संपादित करें: के लिए इस इसलिए मैंने सोचा कि मैं अंतिम जवाब :)

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 

इस से बचा जाता है में शामिल हों और यह भी केवल तालिका एक बार स्कैन करता है में सुधार चाहते हैं किसी ने मतदान किया।

यह इस तथ्य पर निर्भर करता है किकी गणना करते समय NULL मानों को अनदेखा किया जाता है।

+0

@ डेम्स, ऐसा लगता है कि मैं चीजों को बहुत जटिल के रूप में देख रहा था, क्योंकि गतिशील रूप से आपूर्ति किए गए मान फील्ड मान हैं, नाम नहीं, जैसा कि मैंने ऊपर संशोधन किया है। – ProfK

10
SELECT SUM(A * B)/SUM(A) 
FROM mytable 
+0

आप मानते हैं कि मूल्य दो अलग-अलग स्तंभों से आते हैं। वे वास्तव में रिकॉर्ड के विभिन्न सेटों में एक ही कॉलम से आते हैं। – ProfK

+0

क्या आप कृपया कुछ नमूना डेटा पोस्ट कर सकते हैं? – Quassnoi

1

मैं समस्या को समझने है तो इस

SET DATEFORMAT dmy 
    declare @tbl table(A int, B int,recorddate datetime,KPI varchar(50)) 
    insert into @tbl 
     select 1,10 ,'21/01/2009', 'Weighty'union all 
     select 2,20,'10/01/2009', 'Tons Milled' union all 
     select 3,30 ,'03/02/2009', 'xyz'union all 
     select 4,40 ,'10/01/2009', 'Weighty'union all 
     select 5,50 ,'05/01/2009', 'Tons Milled'union all 
     select 6,60,'04/01/2009', 'abc' union all 
     select 7,70 ,'05/01/2009', 'Weighty'union all 
     select 8,80,'09/01/2009', 'xyz' union all 
     select 9,90 ,'05/01/2009', 'kws' union all 
     select 10,100,'05/01/2009', 'Tons Milled' 

    select SUM(t1.A*t2.A)/SUM(t2.A)Result from 
        (select RecordDate,A,B,KPI from @tbl)t1 
     inner join(select RecordDate,A,B,KPI from @tbl t)t2 
     on t1.RecordDate = t2.RecordDate 
     and t1.KPI = t2.KPI 
संबंधित मुद्दे