एक ही समय में दो घटना तालिकाओं को मिलाएं


12

दो टेबल दिए:

CREATE TABLE foo (ts timestamp, foo text);
CREATE TABLE bar (ts timestamp, bar text);

मैं एक प्रश्न है कि के लिए रिटर्न मान लिखना चाहते हैं ts, fooऔर barहै कि हाल ही में मूल्यों का एक एकीकृत दृश्य प्रतिनिधित्व करता है। दूसरे शब्दों में, यदि fooनिहित:

ts | foo
--------
1  | A
7  | B

और barनिहित:

ts | bar
--------
3  | C
5  | D
9  | E

मुझे एक क्वेरी चाहिए जो वापस आए:

ts | foo | bar
--------------
1  | A   | null
3  | A   | C
5  | A   | D
7  | B   | D
9  | B   | E

यदि दोनों तालिकाओं में एक ही समय में एक घटना होती है, तो आदेश कोई फर्क नहीं पड़ता।

मैं संघ सभी और डमी मूल्यों का उपयोग करके आवश्यक संरचना बनाने में सक्षम रहा हूं:

SELECT ts, foo, null as bar FROM foo
UNION ALL SELECT ts, null as foo, bar FROM bar

जो मुझे नए मूल्यों की एक रेखीय समयरेखा देगा, लेकिन मैं पिछली पंक्तियों के आधार पर शून्य मानों को कैसे पॉप्युलेट करता हूं, यह जानने में सक्षम नहीं हूं। मैंने lagविंडो फ़ंक्शन की कोशिश की है, लेकिन AFAICT यह केवल पिछली पंक्ति को देखेगा, न कि पीछे की ओर। मैंने पुनरावर्ती CTEs को देखा है, लेकिन मुझे यकीन नहीं है कि प्रारंभ और समाप्ति की स्थिति कैसे सेट करें।


क्या मान fooऔर barसमय के साथ सख्ती से बढ़ रहे हैं या इस मामले में परीक्षण मामला भ्रामक है?
इरविन ब्रान्डस्टेट्टर

2
किसी और को परेशानी से बचाने के लिए, sqlfiddle.com/# -15/511414
क्रेग रिंगर

1
एक उत्तर दिए जाने के बाद प्रश्न की प्रकृति को बदलने के बजाय, कृपया एक नया प्रश्न पूछें । आप संदर्भ के लिए इसे हमेशा लिंक कर सकते हैं। (यदि आपके पास एक है तो आप अपना जवाब भी दे सकते हैं।) मूल संस्करण आम जनता के लिए दिलचस्प होना चाहिए। आइए एक ही प्रश्न में ज्यादा पैक न करें।
इरविन ब्रान्डस्टेट्टर

ओवरलोड के लिए क्षमा करें। मैंने अनुवर्ती को हटा दिया है और इसे एक नए प्रश्न के रूप में जोड़ा है ।
क्रिस्टोफर करी

जवाबों:


7

विंडो फ़ंक्शंस केFULL [OUTER] JOIN दो राउंड के साथ संयुक्त a का उपयोग करें :

SELECT ts
     , min(foo) OVER (PARTITION BY foo_grp) AS foo
     , min(bar) OVER (PARTITION BY bar_grp) AS bar
FROM (
   SELECT ts, f.foo, b.bar
        , count(f.foo) OVER (ORDER BY ts) AS foo_grp
        , count(b.bar) OVER (ORDER BY ts) AS bar_grp
   FROM   foo f
   FULL   JOIN bar b USING (ts)
   ) sub;

चूंकि count()NULL मूल्यों की गणना नहीं की जाती है, इसलिए यह आसानी से हर गैर-शून्य मान के साथ बढ़ता है, जिससे ऐसे समूह बनते हैं जो समान मूल्य साझा करेंगे। बाहरी रूप में SELECT, min()(या max()) NULL मानों को अनदेखा करता है, जिससे प्रति समूह एक गैर-शून्य मान प्राप्त होता है। देखा।

संबंधित FULL JOINमामला:

यह उन मामलों में से एक है जहां एक प्रक्रियात्मक समाधान सिर्फ तेज हो सकता है, क्योंकि यह एक ही स्कैन में काम कर सकता है। इस plpgsql फ़ंक्शन की तरह :

CREATE OR REPLACE FUNCTION f_merge_foobar()
  RETURNS TABLE(ts int, foo text, bar text) AS
$func$
#variable_conflict use_column
DECLARE
   last_foo text;
   last_bar text;
BEGIN
   FOR ts, foo, bar IN
      SELECT ts, f.foo, b.bar
      FROM   foo f
      FULL   JOIN bar b USING (ts)
      ORDER  BY 1
   LOOP
      IF foo IS NULL THEN foo := last_foo;
      ELSE                last_foo := foo;
      END IF;

      IF bar IS NULL THEN bar := last_bar;
      ELSE                last_bar := bar;
      END IF;

      RETURN NEXT;
   END LOOP;
END
$func$ LANGUAGE plpgsql;

कॉल करें:

SELECT * FROM f_merge_foobar();

db <> फिडेल यहां , दोनों को प्रदर्शित करते हुए।

संबंधित जवाब #variable_conflict use_column:


दिलचस्प समस्या यह नहीं है। मुझे लगता है कि एक कुशल समाधान के लिए संभवतः एक समान coalesceविंडो फ़ंक्शन के निर्माण की आवश्यकता होती है ।
क्रेग रिंगर

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

@ क्रिस्टोफर: मुझे आपके सेटअप में प्रत्येक संस्करण के प्रदर्शन में दिलचस्पी होगी। EXPLAIN ANALYZE, 5 सर्वश्रेष्ठ ...?
इरविन ब्रान्डस्टेट्टर

2
दया जो Postgres ने अभी तक लागू नहीं की है IGNORE NULLS(जैसा कि Oracle में है: sqlfiddle.com/# -4 / fab35/1 )।
ypercube y

1
@ypercube: हाँ, ओरेकल सरल NULL मूल्यों को बिल्कुल भी संग्रहीत नहीं करता है और परिणामस्वरूप ''NULL और NULL के बीच का अंतर नहीं बता सकता है।
इरविन ब्रान्डस्टेट्टर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.