Saya punya tabel,, persons
yang berisi dua kolom, kolom berbasis id
dan JSONB data
(tabel ini baru saja dibuat untuk tujuan demonstrasi untuk bermain-main dengan dukungan JSON PostgreSQL).
Sekarang, seharusnya berisi dua catatan:
1, { name: 'John', age: 30 }
2, { name: 'Jane', age: 20 }
Sekarang, seharusnya saya ingin mendapatkan nama setiap orang yang lebih tua dari 25. Apa yang saya coba adalah:
select data->'name' as name from persons where data->'age' > 25
Sayangnya, ini menghasilkan kesalahan. Saya bisa menyelesaikannya dengan menggunakan ->>
alih-alih ->
, tetapi kemudian perbandingan tidak berfungsi seperti yang diharapkan lagi, karena bukan angka yang dibandingkan, tetapi representasi mereka sebagai string:
select data->'name' as name from persons where data->>'age' > '25'
Saya kemudian menemukan bahwa saya benar-benar dapat memecahkan masalah dengan menggunakan ->
dan pemeran untuk int
:
select data->'name' as name from persons where cast(data->'age' as int) > 25
Ini berfungsi, tetapi tidak menyenangkan karena saya harus tahu tipe yang sebenarnya (tipe age
dalam dokumen JSON adalah number
, jadi mengapa PostgreSQL tidak bisa mengetahuinya dengan sendirinya?).
Saya kemudian menemukan bahwa jika saya mengkonversi secara manual untuk text
menggunakan ::
sintaks, semuanya berfungsi seperti yang diharapkan juga - meskipun kita sekarang membandingkan string lagi.
select data->'name' as name from persons where data->'age'::text > '25'
Jika saya kemudian mencoba ini dengan nama bukan umur, itu tidak berhasil:
select data->'name' as name from persons where data->'name'::text > 'Jenny'
Ini menghasilkan kesalahan:
sintaks input tidak valid untuk tipe json
Jelas sekali, saya tidak mendapatkan sesuatu di sini. Sayangnya, cukup sulit untuk menemukan contoh nyata menggunakan JSON dengan PostgreSQL.
Ada petunjuk?
sumber
data->'name'::text
, Anda melemparkan'name'
string ke teks, bukan hasilnya. Anda tidak mendapatkan kesalahan ketika membandingkan'25'
karena25
JSON literal yang valid; tetapiJenny
tidak (meskipun"Jenny"
akan).'Jenny'
dengan'"Jenny"'
.Jawaban:
Ini tidak berfungsi karena mencoba memberikan
jsonb
nilaiinteger
.Ini sebenarnya akan berfungsi:
Atau lebih pendek:
Dan ini:
Sepertinya kebingungan dengan dua operator
->
dan->>
dan prioritas operator . Para pemain::
mengikat lebih kuat dari operator json (b).Mencari tahu tipe secara dinamis
Ini adalah bagian yang lebih menarik dari pertanyaan Anda:
SQL adalah bahasa yang diketik dengan ketat, tidak mengizinkan ekspresi yang sama untuk dievaluasi
integer
dalam satu baris dantext
di berikutnya. Tetapi karena Anda hanya tertarik padaboolean
hasil tes, Anda dapat mengatasi pembatasan ini denganCASE
ekspresi yang bercabang tergantung pada hasil darijsonb_typeof()
:Sebuah string literal yang tidak diketik di sebelah kanan
>
operator dipaksa untuk masing-masing jenis nilai di sebelah kiri secara otomatis. Jika Anda memasukkan nilai yang diketik di sana, jenisnya harus cocok atau Anda harus melemparkannya secara eksplisit - kecuali ada pemeran implisit yang memadai terdaftar dalam sistem.Jika Anda tahu bahwa semua nilai numerik sebenarnya
integer
, Anda juga dapat:sumber