सेल्फ ज्वाइन का विकल्प


10

मैंने यहां एक प्रश्न पूछा है: /programming/43807566/how-to-divide-two-values-from-the-same-column-but-at-different-row

मानों को एक ही तालिका से, एक ही स्तंभ पर लेकिन अलग-अलग पंक्तियों में विभाजित करने के बारे में। अब मेरे पास समस्या है जहां मेरे पास अधिक संख्या और भाजक हैं (विभिन्न के साथ uns)। अभी भी self joinपोस्टग्रेज के साथ इस समस्या को हल करने का एक अच्छा तरीका है या बेहतर समाधान हैं?

उदाहरण:

| postcode | value | uns |
|----------|-------|-----|
|       AA |    40 |  53 |
|       BB |    20 |  53 |
|       AA |    10 |  54 |
|       AA |    20 |  55 |
|       AA |    10 |  56 |
|       AA |    30 |  57 |
|       AA |    50 |  58 |
|       BB |    10 |  54 |
|       BB |    10 |  55 |
|       BB |    70 |  56 |
|       BB |    80 |  57 |
|       BB |    10 |  58 |

परिणाम होना चाहिए:

| postcode | formula    |
|----------|------------|
|       AA | 18.888...  |
|       BB | 14.375     |

जहाँ मान को पिनकोड द्वारा वर्गीकृत किया जाता है और सूत्र है (बिना मान वाला):

(V53 * V56 + V54 * V57 + V55 * V58) / (V56 + V57 + V58)

शून्य से अंतिम विभाजन से बचने के लिए ध्यान देना। फॉर्मूला और भी जटिल हो सकता है लेकिन यह एक अच्छा उदाहरण है।


क्या आपकी मेज पर कोई फ़ील्ड है जो ध्वज संख्याएँ और भाजक हैं?
मैकनेट्स

नहीं, भाजक मान 56, 57, 58 के साथ मूल्यों का योग है।
यादृच्छिक करें

सबसे अच्छा समाधान की तरह लगता है कि डेटा को पिवट करना होगा ताकि unsकॉलम नाम बन जाएं - वहां से, जो भी सूत्र मानों का उपयोग करता है वह व्यावहारिक होना चाहिए। क्या फॉर्मूला हार्ड-कोडेड होगा, या डायनामिक रूप से किसी तरह प्राप्त होगा?
RDFozz

कुछ सूत्र हैं (~ 30) जो बहुत सारी सारणियाँ बनाने में लगेंगे
रैंडमाइज़ करें

जवाबों:


3

यह अपने मूल में एक धुरी / क्रॉसस्टैब समस्या है, जैसे माइकल पहले से ही सटीक रूप से निदान करता है।

यदि आप tablefuncPostgres में मॉड्यूल से परिचित नहीं हैं , तो यहां बुनियादी निर्देश पढ़ें:

क्वेरी सरल और बहुत तेज़ हो जाती है (यहां प्रस्तुत अन्य समाधानों की तुलना में तेज़):

SELECT (v53 * v56 + v54 * v57 + v55 * v58) / NULLIF(v56 + v57 + v58, 0)
FROM   crosstab(
   'SELECT postcode, uns, value FROM tbl ORDER BY 1'
 , 'SELECT generate_series(53,58)'
   ) AS ct (postcode text
          , v53 numeric, v54 numeric, v55 numeric
          , v56 numeric, v57 numeric, v58 numeric);

NULLIF शून्य से विभाजन को रोकने के लिए।

यहाँ dbfiddle


6

आप सभी अनिश्चित / मान जोड़े को JSON ऑब्जेक्ट में एकत्रित कर सकते हैं, फिर उपयोग करें कि नाम से UNS मानों तक पहुँचने के लिए। इसके लिए कुछ कास्टिंग की आवश्यकता होती है क्योंकि मान केवल JSON ऑब्जेक्ट से पाठ के रूप में निकाले जा सकते हैं, लेकिन सूत्र आपके विवरण के समान ही दिखता है:

with vals(postcode, v) as (
  select postcode, json_object_agg(uns, value)
  from x
  group by postcode
), factors (postcode, denominator, divisor) as (
  select postcode, 
         (v->>'53')::decimal * (v->>'56')::decimal + (v->>'54')::decimal * (v->>'57')::decimal + (v->>'55')::decimal * (v->>'58')::decimal,
         (v->>'56')::decimal + (v->>'57')::decimal + (v->>'58')::decimal
  from vals
)
select postcode, 
       denominator / nullif(divisor, 0)
from factors;

मैंने एकत्रीकरण, भाजक और भाजक के मूल्यांकन और अंतिम विभाजन को तीन चरणों में विभाजित किया है ताकि इसे और अधिक पठनीय बनाया जा सके।

ऑनलाइन उदाहरण: http://rextester.com/IZYT54566


आप फ़ंक्शन बनाकर सूत्र को सरल बना सकते हैं:

create function val(p_vals json, p_uns text)
  returns decimal
as $$
  select (p_vals ->> p_uns)::decimal;
$$
language sql;

with vals (postcode, v) as (
  select postcode, json_object_agg(uns, value)
  from x
  group by postcode
), factors (postcode, denominator, divisor) as (
  select postcode, 
         val(v, '53') * val(v, '56') + val(v, '54') * val(v, '57') + val(v, '55') * val(v, '58'),
         val(v, '56') + val(v, '57') + val(v, '58')
  from vals
)
select postcode, 
       denominator / nullif(divisor, 0)
from factors;

4

PIVOT पैटर्न इसके लिए काम करेगा। यह पंक्तियों के मूल्यों को उनकी सामान्य कुंजी के अनुसार एकल पंक्ति में स्तंभों में परिवर्तित करता है। वहाँ एक हैं कुछ तरीके इस लागू करने के लिए। कुछ को केवल एक टेबल स्कैन की आवश्यकता होती है।

PIVOT के बाद आपके पास एक पंक्ति प्रति पिनकोड और एक स्तंभ प्रति मान होगा। क्वेरी के शेष भाग के रूप में लिखा जाएगा, हालांकि यह एक एकल तालिका संदर्भित करता है।


3

यह मानते हुए कि (postcode, uns)कर रहे हैं UNIQUE(शायद, एक पी), धुरी पैटर्न, के रूप में पहले से ही @ माइकल हरे रंग से टिप्पणी की, लागू किया जा सकता portably निम्न क्वेरी का उपयोग कर:

SELECT
     postcode, 
     CAST(V53 * V56 + V54 * V57 + V55 * V58 AS numeric) 
         / nullif(V56 + V57 + V58, 0) AS formula
FROM
    (SELECT
         postcode,
         sum(case when uns=53 then value end) AS v53,     
         sum(case when uns=54 then value end) AS v54,     
         sum(case when uns=55 then value end) AS v55,     
         sum(case when uns=56 then value end) AS v56,
         sum(case when uns=57 then value end) AS v57,
         sum(case when uns=58 then value end) AS v58
    FROM
         t
    GROUP BY
         postcode
    ) AS s
ORDER BY
    postcode ;

SQLFiddle पर इसे जांचें


3

यह मानते हुए कि (postcode, uns)कर रहे हैं UNIQUE(शायद, एक पी), शायद सबसे सरल : जिस तरह से, शायद सबसे पोर्टेबल एक है, हालांकि शायद इष्टतम नहीं आवश्यकतानुसार कई subselects के रूप में उपयोग :

SELECT
    postcode,
    ((SELECT value FROM t WHERE t.uns = 53 AND t.postcode = p.postcode) *
     (SELECT value FROM t WHERE t.uns = 56 AND t.postcode = p.postcode) +
     (SELECT value FROM t WHERE t.uns = 54 AND t.postcode = p.postcode) *
     (SELECT value FROM t WHERE t.uns = 57 AND t.postcode = p.postcode) +
     (SELECT value FROM t WHERE t.uns = 55 AND t.postcode = p.postcode) *
     (SELECT value FROM t WHERE t.uns = 58 AND t.postcode = p.postcode)
    )::double precision / 
     nullif( (SELECT sum(value) FROM t 
              WHERE t.uns IN (56, 57, 58) AND t.postcode = p.postcode), 0)
    AS formula
FROM
    (SELECT DISTINCT postcode FROM t) AS p
ORDER BY
    postcode ;

SQLFiddle पर जाँच करें ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.