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

PostgreSQL:ERROR:42601:daftar definisi kolom diperlukan untuk fungsi yang mengembalikan catatan

Kembalikan kolom yang dipilih

CREATE OR REPLACE FUNCTION get_user_by_username(_username text
                                              , _online bool DEFAULT false)
  RETURNS TABLE (
    user_id int
  , user_name varchar
  , last_activity timestamptz
  )
  LANGUAGE plpgsql AS
$func$
BEGIN
   IF _online THEN
      RETURN QUERY
      UPDATE users u 
      SET    last_activity = current_timestamp  -- ts with time zone
      WHERE  u.user_name = _username
      RETURNING u.user_id
              , u.user_name
              , u.last_activity;
   ELSE
      RETURN QUERY
      SELECT u.user_id
           , u.user_name
           , u.last_activity
      FROM   users u
      WHERE  u.user_name = _username;
   END IF;
END
$func$;

Telepon:

SELECT * FROM get_user_by_username('myuser', true);

Anda memiliki DECLARE result record; tetapi tidak menggunakan variabel. Saya menghapus cruftnya.

Anda dapat mengembalikan catatan langsung dari UPDATE , yang jauh lebih cepat daripada memanggil SELECT additional tambahan penyataan. Gunakan RETURN QUERY dan UPDATE dengan RETURNING klausa.

Jika pengguna tidak _online , default ke SELECT plain biasa . Ini juga merupakan default (aman) jika parameter kedua dihilangkan - yang hanya mungkin setelah memberikan default tersebut dengan DEFAULT false dalam definisi fungsi.

Jika Anda tidak memenuhi syarat tabel nama kolom (tablename.columnname ) dalam kueri di dalam fungsi, waspadalah terhadap konflik penamaan antara nama kolom dan parameter bernama, yang terlihat (sebagian besar) di mana saja di dalam suatu fungsi.
Anda juga dapat menghindari konflik seperti itu dengan menggunakan referensi posisi ($n ) untuk parameter. Atau gunakan awalan yang tidak pernah gunakan untuk nama kolom:seperti garis bawah (_username ).

Jika users.username didefinisikan unik di tabel Anda, lalu LIMIT 1 dalam permintaan kedua hanya cruft. Jika tidak , lalu UPDATE dapat memperbarui beberapa baris, yang kemungkinan besar salah . Saya menganggap username yang unik dan kurangi kebisingannya.

Tentukan jenis kembalian fungsi (seperti yang ditunjukkan @ertx) atau Anda harus memberikan daftar definisi kolom dengan setiap panggilan fungsi, yang aneh.

Membuat tipe untuk tujuan itu (seperti yang diusulkan @ertx) adalah pendekatan yang valid, tetapi mungkin berlebihan untuk satu fungsi. Itulah cara untuk menggunakan Postgres versi lama sebelum kami memiliki RETURNS TABLE untuk tujuan itu - seperti yang ditunjukkan di atas.

Anda tidak membutuhkan pengulangan untuk fungsi sederhana ini.

Setiap fungsi membutuhkan deklarasi bahasa. LANGUAGE plpgsql dalam hal ini.

Saya menggunakan timestamptz (timestamp with time zone ) bukannya timestamp (timestamp without time zone ), yang merupakan default yang waras. Lihat:

  • Mengabaikan zona waktu sama sekali di Rails dan PostgreSQL

Kembalikan (kumpulan) seluruh baris

Untuk mengembalikan semua kolom dari tabel yang ada users , ada cara yang lebih sederhana. Postgres secara otomatis mendefinisikan jenis komposit dengan nama yang sama untuk setiap tabel . Cukup gunakan RETURNS SETOF users untuk menyederhanakan kueri:

CREATE OR REPLACE FUNCTION get_user_by_username(_username text
                                              , _online bool DEFAULT false)
  RETURNS SETOF users
  LANGUAGE plpgsql AS
$func$
BEGIN
   IF _online THEN
      RETURN QUERY
      UPDATE users u 
      SET    last_activity = current_timestamp
      WHERE  u.user_name = _username
      RETURNING u.*;
   ELSE
      RETURN QUERY
      SELECT *
      FROM   users u
      WHERE  u.user_name = _username;
   END IF;
END
$func$;

Kembalikan seluruh baris ditambah tambahan khusus

Untuk menjawab pertanyaan yang ditambahkan oleh TheRealChx101 dalam komentar di bawah:

Bagaimana jika Anda juga memiliki nilai yang dihitung selain seluruh tabel?

Tidak sesederhana itu, tapi bisa dilakukan. Kami dapat mengirim seluruh jenis baris sebagai satu bidang, dan tambahkan lainnya:

CREATE OR REPLACE FUNCTION get_user_by_username3(_username text
                                               , _online bool DEFAULT false)
  RETURNS TABLE (
    users_row users
  , custom_addition text
  )
  LANGUAGE plpgsql AS
$func$
BEGIN
   IF _online THEN
      RETURN QUERY
      UPDATE users u 
      SET    last_activity = current_timestamp  -- ts with time zone
      WHERE  u.user_name = _username
      RETURNING u  -- whole row
              , u.user_name || u.user_id;
   ELSE
      RETURN QUERY
      SELECT u, u.user_name || u.user_id
      FROM   users u
      WHERE  u.user_name = _username;
   END IF;
END
$func$;

"Sihir" ada dalam pemanggilan fungsi, tempat kami (secara opsional) menguraikan jenis baris:

SELECT (users_row).*, custom_addition FROM get_user_by_username('foo', true);

db<>main biola di sini (menampilkan semua)

Jika Anda membutuhkan sesuatu yang lebih "dinamis", pertimbangkan:

  • Memfaktorkan ulang fungsi PL/pgSQL untuk mengembalikan output dari berbagai kueri SELECT


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Mengapa sebaiknya menyimpan nomor telepon sebagai string vs. integer?

  2. Skema Django dan postgresql

  3. Cara Menghindari Penguncian Vendor Cloud PostgreSQL

  4. Perbedaan antara bahasa sql dan bahasa plpgsql dalam fungsi PostgreSQL

  5. Array elemen PostgreSQL yang masing-masing merupakan kunci asing