PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Bagaimana cara mengembalikan hasil SELECT di dalam suatu fungsi di PostgreSQL?

Gunakan RETURN QUERY :

CREATE OR REPLACE FUNCTION word_frequency(_max_tokens int)
  RETURNS TABLE (txt   text   -- also visible as OUT parameter inside function
               , cnt   bigint
               , ratio bigint)
  LANGUAGE plpgsql AS
$func$
BEGIN
   RETURN QUERY
   SELECT t.txt
        , count(*) AS cnt                 -- column alias only visible inside
        , (count(*) * 100) / _max_tokens  -- I added brackets
   FROM  (
      SELECT t.txt
      FROM   token t
      WHERE  t.chartype = 'ALPHABETIC'
      LIMIT  _max_tokens
      ) t
   GROUP  BY t.txt
   ORDER  BY cnt DESC;                    -- potential ambiguity 
END
$func$;

Telepon:

SELECT * FROM word_frequency(123);

Mendefinisikan tipe pengembalian secara eksplisit adalah banyak lebih praktis daripada mengembalikan record umum . Dengan cara ini Anda tidak perlu memberikan daftar definisi kolom dengan setiap panggilan fungsi. RETURNS TABLE adalah salah satu cara untuk melakukannya. Ada yang lain. Tipe data OUT parameter harus sama persis dengan apa yang dikembalikan oleh kueri.

Pilih nama untuk OUT parameter dengan hati-hati. Mereka terlihat di tubuh fungsi hampir di mana saja. Kolom kualifikasi tabel dengan nama yang sama untuk menghindari konflik atau hasil yang tidak diharapkan. Saya melakukannya untuk semua kolom dalam contoh saya.

Namun perhatikan potensi konflik penamaan antara OUT parameter cnt dan alias kolom dengan nama yang sama. Dalam kasus khusus ini (RETURN QUERY SELECT ... ) Postgres menggunakan alias kolom di atas OUT parameter dengan cara apa pun. Ini bisa menjadi ambigu dalam konteks lain, meskipun. Ada berbagai cara untuk menghindari kebingungan:

  1. Gunakan posisi ordinal item dalam daftar SELECT:ORDER BY 2 DESC . Contoh:
    • Pilih baris pertama di setiap grup GROUP BY?
  2. Ulangi ekspresi ORDER BY count(*) .
  3. (Tidak berlaku di sini.) Setel parameter konfigurasi plpgsql.variable_conflict atau gunakan perintah khusus #variable_conflict error | use_variable | use_column dalam fungsi. Lihat:
    • Konflik penamaan antara parameter fungsi dan hasil JOIN dengan klausa USING

Jangan gunakan "teks" atau "hitung" sebagai nama kolom. Keduanya legal untuk digunakan di Postgres, tetapi "hitungan" adalah kata khusus dalam SQL standar dan nama fungsi dasar dan "teks" adalah tipe data dasar. Dapat menyebabkan kesalahan yang membingungkan. Saya menggunakan txt dan cnt dalam contoh saya, Anda mungkin menginginkan nama yang lebih eksplisit.

Menambahkan ; . yang hilang dan memperbaiki kesalahan sintaks di header. (_max_tokens int) , bukan (int maxTokens) - ketik setelah nama .

Saat bekerja dengan pembagian bilangan bulat, lebih baik untuk mengalikan terlebih dahulu dan membagi kemudian, untuk meminimalkan kesalahan pembulatan. Atau bekerja dengan numeric atau tipe floating point. Lihat di bawah.

Alternatif

Ini yang pikirkan kueri Anda seharusnya terlihat seperti (menghitung pembagian relatif per token ):

CREATE OR REPLACE FUNCTION word_frequency(_max_tokens int)
  RETURNS TABLE (txt            text
               , abs_cnt        bigint
               , relative_share numeric)
  LANGUAGE plpgsql AS
$func$
BEGIN
   RETURN QUERY
   SELECT t.txt, t.cnt
        , round((t.cnt * 100) / (sum(t.cnt) OVER ()), 2)  -- AS relative_share
   FROM  (
      SELECT t.txt, count(*) AS cnt
      FROM   token t
      WHERE  t.chartype = 'ALPHABETIC'
      GROUP  BY t.txt
      ORDER  BY cnt DESC
      LIMIT  _max_tokens
      ) t
   ORDER  BY t.cnt DESC;
END
$func$;

Ekspresi sum(t.cnt) OVER () adalah fungsi jendela. Anda bisa gunakan CTE alih-alih subquery. Bagus, tapi subquery biasanya lebih murah dalam kasus sederhana seperti ini (kebanyakan sebelum Postgres 12).

RETURN terakhir eksplisit pernyataan tidak diperlukan (tetapi diizinkan) saat bekerja dengan OUT parameter atau RETURNS TABLE (yang secara implisit menggunakan OUT parameter).

round() dengan dua parameter hanya berfungsi untuk numeric jenis. count() di subquery menghasilkan bigint hasil dan sum() di atas bigint ini menghasilkan numeric hasilnya, jadi kita berurusan dengan numeric nomor secara otomatis dan semuanya masuk ke tempatnya.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Kesalahan NodeJS Postgres getaddrinfo ENOTFOUND

  2. Fungsi PostgreSQL mengembalikan beberapa set hasil

  3. Lembar Cheat Konfigurasi PostgreSQL

  4. Rails:Tidak ada kumpulan koneksi untuk ActiveRecord::Base

  5. Menggunakan regex di WHERE di Postgres