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