İki olay tablosunu tek bir zaman çizelgesinde birleştirin


12

Verilen iki tablo:

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

Ben döner değerler bir sorgu yazmak isteyen ts, foove baro en son değerlerin birleştirilmiş bir görünümünü temsil etmektedir. Diğer bir deyişle, fooiçerdiği takdirde :

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

ve bariçerdiği:

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

Geri dönen bir sorgu istiyorum:

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

Her iki tablonun da aynı anda bir etkinliği varsa, siparişin önemi yoktur.

Birlik all ve kukla değerleri kullanarak gerekli yapıyı oluşturabildim:

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

Bu bana yeni değerlerin doğrusal bir zaman çizelgesini verecektir, ancak önceki satırlara dayalı boş değerleri nasıl dolduracağımı tam olarak anlayamıyorum. lagPencere işlevini denedim , ancak AFAICT sadece bir önceki satıra bakacak, özyinelemeli olarak geriye değil. Özyinelemeli CTE'lere baktım, ancak başlangıç ​​ve sonlandırma koşullarının nasıl ayarlanacağından emin değilim.


Zaman içindeki değerler foove barkesinlikle yükseliyor mu yoksa test durumu bu açıdan yanıltıcı mı?
Erwin Brandstetter

2
Başkalarını güçlükten
Craig Ringer

1
Bir cevap verildikten sonra sorunun niteliğini değiştirmek yerine, lütfen yeni bir soru sorun . Referans olması için her zaman buna bağlayabilirsiniz. (Varsa kendi cevabınızı bile verebilirsiniz.) Orijinal versiyon herkes için ilginç olmalıdır. Tek bir soruda çok fazla şey toplamayalım.
Erwin Brandstetter

Aşırı yük için özür dilerim. İzlemeyi kaldırdım ve yeni bir soru olarak ekledim .
Christopher Currie

Yanıtlar:


7

FULL [OUTER] JOINİki tur pencere işlevi ile birlikte a kullanın :

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;

Yana count()NULL değerleri sayılmaz uygun sadece bu suretle aynı değeri paylaşacak grupları oluşturarak, her boş olmayan değeri ile artar. Dışta SELECT, min()(veya max()) benzer şekilde NULL değerleri yok sayar, böylece grup başına null olmayan bir değer seçilir. Voila.

İlgili FULL JOINdurum:

Prosedürel bir çözümün daha hızlı olabileceği durumlardan biridir, çünkü işi tek bir taramada yapabilir. Bu plpgsql işlevi gibi :

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;

Telefon etmek:

SELECT * FROM f_merge_foobar();

db <> her ikisini de gösteren burada keman .

İlgili cevap #variable_conflict use_column:


İlginç bir sorun değil mi? Etkili bir çözüm muhtemelen benzer bir coalescepencere işlevi oluşturulması gerektirir .
Craig Ringer

@CraigRinger: Gerçekten. Kendimi isteyerek, merak ederek, düşünerek buluyorum ... bunun alt sorgu olmadan bir şekilde mümkün olması gerektiğini, ancak bir yol bulamadım. Her tabloyu bir kez tarayabildiği için plpgsql işlevinin daha hızlı olacağı durumlardan biridir.
Erwin Brandstetter

@Christopher: Kurulumunuzdaki her bir varyantın performansı ile ilgilenirim. EXPLAIN ANALYZE, en iyisi 5 ...?
Erwin Brandstetter

2
Yazık ki Postgres henüz uygulanmadı IGNORE NULLS(Oracle'ın yaptığı gibi: sqlfiddle.com/#!4/fab35/1 ).
ypercubeᵀᴹ

1
@ypercube: Evet, Oracle simple NULL değerlerini hiç saklamaz ve sonuç olarak ''ve NULL arasındaki farkı söyleyemez .
Erwin Brandstetter
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.