Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 12

Thema: In Function where-Bedingung mit möglichen Nullwerten formulieren

  1. #1
    BlubberWolf ist offline Neuer Benutzer
    Registriert seit
    20.04.2009
    Beiträge
    27

    Standard In Function where-Bedingung mit möglichen Nullwerten formulieren

    Hi Forum,

    ich möchte in einer Tabelle mehrfach vorkommende Zeilen mit Hilfe einer Function zählen. Die Function bekommt Werte für die where-Bedingung übergeben.

    Code:
    create table t_x (
      id serial,
      a  integer,
      b  integer
    );
    
    insert into t_x (a,b) values (null,1), (null,1), (null,1), (2,2), (2,2), (2,1);
    
    create or replace function find_multiples_of(x_row t_x)
    returns integer as $$
    DECLARE
        rc integer;
    BEGIN
        select count(id) into rc from t_x
        where
            case when x_row.a is null then
                a is null
            else
                a = x_row.a
            end
        and 
            case when x_row.b is null then
                b is null
            else
                b = x_row.b
            end
        ;
        
        return rc;
    END;
    $$ language plpgsql;
    
    
    select find_multiples_of((null,null,1)::t_x);
    select find_multiples_of((null,2,2)::t_x);
    Das funktioniert soweit. Das case zu schreiben wird länglich bei vielen Spalten. Geht's irgendwie kürzer ?

  2. #2
    akretschmer ist gerade online Super-Moderator
    Registriert seit
    29.10.2006
    Ort
    Nähe Dresden
    Beiträge
    5.337

    Standard

    Zitat Zitat von BlubberWolf Beitrag anzeigen
    Hi Forum,

    ich möchte in einer Tabelle mehrfach vorkommende Zeilen mit Hilfe einer Function zählen. Die Function bekommt Werte für die where-Bedingung übergeben.
    Bin mir nicht ganz sicher, Dich richtig zu verstehen, aber ich versuchs mal:

    Code:
    test=*# select * from t_x;
     id | a | b
    ----+---+---
      1 |   | 1
      2 |   | 1
      3 |   | 1
      4 | 2 | 2
      5 | 2 | 2
      6 | 2 | 1
    (6 rows)
    
    test=*# select count(1) from t_x where a=b and a is not null;
     count
    -------
         2
    (1 row)
    Andreas
    --
    ads Das hatte dir akretschmer gestern schon gesagt und siehe da sobald du das machst, funktioniert es ;-)
    https://www.xing.com/profile/Andreas_Kretschmer7

  3. #3
    akretschmer ist gerade online Super-Moderator
    Registriert seit
    29.10.2006
    Ort
    Nähe Dresden
    Beiträge
    5.337

    Standard

    Zitat Zitat von akretschmer Beitrag anzeigen
    Bin mir nicht ganz sicher, Dich richtig zu verstehen, aber ich versuchs mal:
    Okay, jetzt weiß ich erst mal, was du willst, sorry.
    --
    ads Das hatte dir akretschmer gestern schon gesagt und siehe da sobald du das machst, funktioniert es ;-)
    https://www.xing.com/profile/Andreas_Kretschmer7

  4. #4
    BlubberWolf ist offline Neuer Benutzer
    Registriert seit
    20.04.2009
    Beiträge
    27

    Standard

    Es geht im Prinzip um meine Schreibfaulheit :-).

    Ich befürchte, dass ich um die Case Anweisungen nicht rummkomme.

  5. #5
    akretschmer ist gerade online Super-Moderator
    Registriert seit
    29.10.2006
    Ort
    Nähe Dresden
    Beiträge
    5.337

    Standard

    Zitat Zitat von akretschmer Beitrag anzeigen
    Okay, jetzt weiß ich erst mal, was du willst, sorry.
    Das Problem sind ja die Vergleiche mit NULL.

    Frage: ist -1 (zum Beispiel) ein praktisch vorkommender Wert? Falls nein, reduziert sich Dein Problem auf folgendes:

    Code:
    test=*# select * from t_x where (coalesce(a,-1),coalesce(b,-1)) = (-1,1);
     id | a | b
    ----+---+---
      1 |   | 1
      2 |   | 1
      3 |   | 1
    (3 rows)
    
    test=*# select * from t_x where (coalesce(a,-1),coalesce(b,-1)) = (2,2);
     id | a | b
    ----+---+---
      4 | 2 | 2
      5 | 2 | 2
    (2 rows)
    Das zählen hab ich mal weggelassen, um zu sehen, was passiert. Anstatt gegen NULL zu prüfen setzt Du -1 ein, zum auslesen der Spalten nutzt Du coalesce(), um NULL in -1 zu wandeln.


    Die Treffer zu zählen ist dann trivial ...


    Andreas
    --
    ads Das hatte dir akretschmer gestern schon gesagt und siehe da sobald du das machst, funktioniert es ;-)
    https://www.xing.com/profile/Andreas_Kretschmer7

  6. #6
    BlubberWolf ist offline Neuer Benutzer
    Registriert seit
    20.04.2009
    Beiträge
    27

    Standard

    Ja, das Problem sind die eventuell auftretenden Null-Werte. (sorry, sollte vielleicht besser posten).

    Das zwingt einen in der where-Bedingung Null-Werte abzufangen, weil der Vergleich dann nicht mit '=' sondern mit 'is null' formuliert werden muss.

    Ich such' tatsächlich eine allgemeine (kurze) Lösung. coalesce() hilft dann leider nicht (alle Werte zulässig).


    Edit: Typo
    Geändert von BlubberWolf (13.11.2009 um 15:33 Uhr)

  7. #7
    akretschmer ist gerade online Super-Moderator
    Registriert seit
    29.10.2006
    Ort
    Nähe Dresden
    Beiträge
    5.337

    Standard

    Zitat Zitat von BlubberWolf Beitrag anzeigen
    Ja, das Problem sind die eventuell auftretenden Null-Werte. (sorry, sollte vielleicht besser posten).

    Das zwingt einen in der where-Bedingung Null-Werte abzufangen, weil der Vergleich dann nicht mit '=' sondern mit 'is null' formuliert werden muss.

    Ich such' tatsächlich eine allgemeine (kurze) Lösung. coalesce() hilft dann leider nicht (alle Werte zulässig).


    Edit: Typo
    Okay:

    Code:
    test=*# select * from t_x where (coalesce(a::text,'NULL'),coalesce(b::text,'NULL')) = (2::text,2::text);
     id | a | b
    ----+---+---
      4 | 2 | 2
      5 | 2 | 2
    (2 Zeilen)
    
    Zeit: 0,507 ms
    test=*# select * from t_x where (coalesce(a::text,'NULL'),coalesce(b::text,'NULL')) = ('NULL',1::text);
     id | a | b
    ----+---+---
      1 |   | 1
      2 |   | 1
      3 |   | 1
    (3 Zeilen)
    .oO( PostgreSQL ist, wenn es dennoch geht )

    Andreas
    --
    ads Das hatte dir akretschmer gestern schon gesagt und siehe da sobald du das machst, funktioniert es ;-)
    https://www.xing.com/profile/Andreas_Kretschmer7

  8. #8
    BlubberWolf ist offline Neuer Benutzer
    Registriert seit
    20.04.2009
    Beiträge
    27

    Standard

    Schlimm, schlimm, schlimm :-)

    Nicht nur, dass es funktioniert. Hab's in eine Function gepackt

    Code:
    create or replace function cfind_multiples_of(x_row t_x)
    returns integer as $$
    DECLARE
        rc integer;
    BEGIN
        select count(id) into rc from t_x
        where
            (coalesce(a::text,'NULL'),coalesce(b::text,'NULL')) =  (coalesce(x_row.a::text,'NULL'),coalesce(x_row.b::text,'NULL'))
        ;
        
        return rc;
    END;
    $$ language plpgsql;
    und mit timing on mal geschaut, wie die Performance so ist.
    Der erste Eindruck ist : es ist nicht langsamer, eher leicht schneller als die Case-Anweisung. Schlimm, schlimm, schlimm.
    Kostet Case so viel ?

    Ich vergleich's noch mal genauer.

    Irgendwann gibt's irgendwo irgendeine Anzahl Bier !

  9. #9
    akretschmer ist gerade online Super-Moderator
    Registriert seit
    29.10.2006
    Ort
    Nähe Dresden
    Beiträge
    5.337

    Standard

    Zitat Zitat von BlubberWolf Beitrag anzeigen
    und mit timing on mal geschaut, wie die Performance so ist.
    Der erste Eindruck ist : es ist nicht langsamer, eher leicht schneller als die Case-Anweisung. Schlimm, schlimm, schlimm.
    Kostet Case so viel ?

    Ich vergleich's noch mal genauer.

    Irgendwann gibt's irgendwo irgendeine Anzahl Bier !
    Ja, CASE kostet schon etwas.

    Btw.: auch ich war heute überrascht.

    Man stelle sich mehrere Tabellen vor, z.B. person, email, adresse. Zu jeder Person können N adressen und email existieren. Das abzubilden also auch noch Tabellen person_adresse und person_email. Um nun da eine Person mit N email und M adressen zu speichern, brauche ich etliche Inserts. Bisher. Falls der Patch von Marko es schafft, wird das in 8.5 mit einem einzelnen Insert funktionieren. Der Performance-Gewinn ist immens, Details dazu demnächst irgendwo. Ich war einfach von David's und Marko's Vortrag in Paris animiert, das mal zu testen.

    Andreas
    --
    ads Das hatte dir akretschmer gestern schon gesagt und siehe da sobald du das machst, funktioniert es ;-)
    https://www.xing.com/profile/Andreas_Kretschmer7

  10. #10
    BlubberWolf ist offline Neuer Benutzer
    Registriert seit
    20.04.2009
    Beiträge
    27

    Standard

    Zitat Zitat von akretschmer Beitrag anzeigen
    Ja, CASE kostet schon etwas.

    Btw.: auch ich war heute überrascht.

    Man stelle sich mehrere Tabellen vor, z.B. person, email, adresse. Zu jeder Person können N adressen und email existieren. Das abzubilden also auch noch Tabellen person_adresse und person_email. Um nun da eine Person mit N email und M adressen zu speichern, brauche ich etliche Inserts. Bisher. Falls der Patch von Marko es schafft, wird das in 8.5 mit einem einzelnen Insert funktionieren. Der Performance-Gewinn ist immens, Details dazu demnächst irgendwo. Ich war einfach von David's und Marko's Vortrag in Paris animiert, das mal zu testen.

    Andreas
    Meinst du den Vortrag über Writable CTEs ?
    Hoffentlich nicht, sonst muss ich mich da mal reinarbeiten ;-).

    Das,was du mit Person/Adresse/Email ansprichst, dafür Tabellen peson_adressen, person_email zu benutzen, weigern wir uns zu machen. Das ist Design-mässig Blödsinn. Wir versuchen's über Updatable-Views zu lösen. Und wenn wir dabei auf die Nase fallen, haben wir wenigstens was gelernt :-).

Seite 1 von 2 12 LetzteLetzte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

Links: Tobias Bauer - IT- und Funkdienstleistungen   -   Bilderrahmen-kaufen.de - Der Onlineshop für Bilderrahmen & Fotorahmen   -   Funkforum