sql >> Databáze >  >> RDS >> PostgreSQL

ORDER BY ... POUŽITÍ klauzule v PostgreSQL

Velmi jednoduchý příklad by byl:

> SELECT * FROM tab ORDER BY col USING <

Ale to je nuda, protože to není nic, co byste nemohli získat tradičním ORDER BY col ASC .

Také standardní katalog nezmiňuje nic vzrušujícího o podivných srovnávacích funkcích/operátorech. Jejich seznam můžete získat:

    > SELECT amoplefttype::regtype, amoprighttype::regtype, amopopr::regoper 
      FROM pg_am JOIN pg_amop ON pg_am.oid = pg_amop.amopmethod 
      WHERE amname = 'btree' AND amopstrategy IN (1,5);

Všimnete si, že většinou existují < a > funkce pro primitivní typy jako integer , date atd a některé další pro pole a vektory a tak dále. Žádný z těchto operátorů vám nepomůže získat vlastní objednávku.

Ve většině v případech, kdy je vyžadováno vlastní řazení, můžete se dostat pryč pomocí něčeho jako ... ORDER BY somefunc(tablecolumn) ... kde somefunc vhodně mapuje hodnoty. Protože to funguje s každou databází, je to také nejběžnější způsob. Pro jednoduché věci můžete dokonce napsat výraz místo vlastní funkce.

Přepnutí převodů nahoru

ORDER BY ... USING dává smysl v několika případech:

  • Řazení je tak neobvyklé, že somefunc trik nefunguje.
  • Pracujete s neprimitivním typem (jako point , circle nebo imaginární čísla) a nechcete se ve svých dotazech opakovat s podivnými výpočty.
  • Soubor dat, který chcete seřadit, je tak velký, že je žádoucí nebo dokonce vyžadována podpora pomocí indexu.

Zaměřím se na komplexní datové typy:často existuje více než jeden způsob, jak je rozumným způsobem třídit. Dobrým příkladem je point :Můžete je „uspořádat“ podle vzdálenosti do (0,0) nebo podle x nejprve a poté y nebo jen y nebo cokoliv jiného chcete.

PostgreSQL samozřejmě předdefinované operátory pro point :

    > CREATE TABLE p ( p point );
    > SELECT p <-> point(0,0) FROM p;

Ale žádné z nich je prohlášeno za použitelné pro ORDER BY ve výchozím nastavení (viz výše):

    > SELECT * FROM p ORDER BY p;
    ERROR:  could not identify an ordering operator for type point
    TIP:  Use an explicit ordering operator or modify the query.

Jednoduché operátory pro point jsou operátory „dole“ a „nad“ <^ a >^ . Porovnávají jednoduše y část bodu. Ale:

    >  SELECT * FROM p ORDER BY p USING >^;
    ERROR: operator > is not a valid ordering operator
    TIP: Ordering operators must be "<" or ">" members of __btree__ operator families.

ORDER BY USING vyžaduje operátor s definovanou sémantikou:Samozřejmě to musí být binární operátor, musí akceptovat stejný typ jako argumenty a musí vracet boolean. Myslím, že musí být také tranzitivní (pokud a btree - indexové řazení. To vysvětluje podivné chybové zprávy obsahující odkaz na btree .

ORDER BY USING také vyžaduje nejen jednoho operátora být definován, ale třída operátorů a rodina operátorů . Zatímco jeden mohl implementovat třídění pouze s jedním operátorem, PostgreSQL se snaží třídit efektivně a minimalizovat porovnávání. Proto se používá několik operátorů, i když zadáte pouze jeden - ostatní musí dodržovat určitá matematická omezení - tranzitivitu jsem již zmínil, ale je jich více.

Přepnutí převodového stupně nahoru

Definujme něco vhodného:Operátor pro body, který porovnává pouze y část.

Prvním krokem je vytvoření vlastní rodiny operátorů, kterou může bstrom používat metoda přístupu k indexu. viz

    > CREATE OPERATOR FAMILY xyzfam USING btree;   -- superuser access required!
    CREATE OPERATOR FAMILY

Dále musíme poskytnout funkci komparátoru, která vrátí -1, 0, +1 při porovnávání dvou bodů. Tato funkce BUDE být volán interně!

    > CREATE FUNCTION xyz_v_cmp(p1 point, p2 point) RETURNS int 
      AS $$BEGIN RETURN btfloat8cmp(p1[1],p2[1]); END $$ LANGUAGE plpgsql;
    CREATE FUNCTION

Dále definujeme třídu operátorů pro rodinu. Vysvětlení čísel naleznete v příručce.

    > CREATE OPERATOR CLASS xyz_ops FOR TYPE point USING btree FAMILY xyzfam AS 
        OPERATOR 1 <^ ,
        OPERATOR 3 ?- ,
        OPERATOR 5 >^ ,
        FUNCTION 1 xyz_v_cmp(point, point) ;
    CREATE OPERATOR CLASS

Tento krok kombinuje několik operátorů a funkcí a také definuje jejich vztah a význam. Například OPERATOR 1 znamená:Toto je operátor pro less-than testy.

Nyní operátory <^ a >^ lze použít v ORDER BY USING :

> INSERT INTO p SELECT point(floor(random()*100), floor(random()*100)) FROM generate_series(1, 5);
INSERT 0 5
> SELECT * FROM p ORDER BY p USING >^;
    p    
---------
 (17,8)
 (74,57)
 (59,65)
 (0,87)
 (58,91)

Voila – seřazeno podle y .

Abych to shrnul: ORDER BY ... USING je zajímavý pohled pod pokličku PostgreSQL. Ale nic, co byste v dohledné době potřebovali, pokud nebudete pracovat velmi specifické oblasti databázové technologie.

Další příklad lze nalézt v dokumentu Postgres. se zdrojovým kódem pro příklad zde a zde. Tento příklad také ukazuje, jak vytvořit operátory.



  1. Java - datum uložené jako předchozí den

  2. Přejmenování uživatelem definovaného datového typu v SQL Server (T-SQL)

  3. Optimalizujte skupinový maximální dotaz

  4. Vyhoďte chybu bránící aktualizaci tabulky ve spouštěči MySQL