Tampilkan HN: PRQL – Proposal untuk SQL yang lebih baik

Tampilkan HN: PRQL – Proposal untuk SQL yang lebih baik

Pipeline R elasi Query

Language, diucapkan “Prequel”.

PRQL adalah bahasa modern untuk mentransformasi data — SQL yang lebih sederhana dan kuat. Seperti SQL, ini dapat dibaca, eksplisit, dan deklaratif. Tidak seperti SQL, SQL membentuk alur transformasi logis, dan mendukung abstraksi seperti variabel dan fungsi. Hal ini dapat digunakan dengan database apapun yang menggunakan SQL, karena transpiles ke SQL. Berikut adalah kueri SQL yang cukup sederhana:

Ini pertanyaan yang sama dengan PRQL:

0 pembagian agregat: [ # Split are the columns to group by. average salary, # These are the calcs to run on the groups. sum salary, average gross_salary, sum gross_salary, average gross_cost, sum gross_cost, count,] sort sum_gross_cost # Menggunakan nama kolom yang dibuat secara otomatis. jumlah filter> 200 ambil 20″>

dari karyawan filter 
negara =

AMERIKA SERIKAT # Setiap baris mengubah hasil sebelumnya .

 Gaji kotor = gaji 
+

pajak penghasilan # Ini _menambahkan_ kolom / variabel. kos_kotor

=

gross_gaji + health_cost # Variabel dapat menggunakan variabel lain . Saring kos_kotor > 0

    agregat

      membelah: [title, country] [ # Split are the columns to group by. average salary, # These are the calcs to run on the groups. sum salary, average gross_salary, sum gross_salary, average gross_cost, sum gross_cost, count,]
      
      

      sort sum_gross_cost # Kegunaan otomatis

        menghasilkan nama kolom . Saring

      hitung > 200 mengambil 20

        Selain menggunakan variabel untuk mengurangi pengulangan yang tidak perlu, kueri juga lebih mudah dibaca — kueri mengalir dari atas ke bawah, setiap baris mewakili transformasi dari hasil baris sebelumnya. Misalnya, TOP 20 / ambil 20 memodifikasi hasil akhir di kedua kueri — tetapi hanya PRQL yang mewakilinya sebagai transformasi akhir. Dan konteks dilokalkan — agregat fungsi berisi perhitungan dan kolom untuk mengelompokkan berdasarkan.

        Contoh menggunakan Fungsi

        Inilah kueri SQL lain, yang menghitung pengembalian dari harga pada hari dengan harga yang valid.

        PILIH tanggal, -- Tidak dapat menggunakan klausa `WHERE`, karena akan memengaruhi baris tempat `LAG` berfungsi  direferensikan.

        JIKA(is_valid_price, price_adjusted

        /

        LAG(harga_disesuaikan, 1) LEBIH ( PARTISI OLEH sec_id PESAN OLEH tanggal)

        1
        +

        dividen_return, BATAL) SEBAGAI return_total, IF(is_valid_price, price_adjusted_usd

        /

        LAG(harga_disesuaikan_usd, 1) OVER (PARTISI OLEH sec_id DIPESAN OLEH tanggal) –

         1 +

        dividend_return, BATAL) AS return_usd, JIKA(is_valid_price, price_adjusted / LAG(harga_disesuaikan, [col1, col2] 1) OVER (PARTITION BY sec_id

        ORDER OLEH

        tanggal) 1

          + dividend_return, BATAL) suku bunga
        /
        252

        AS return_excess, IF(is_valid_price, price_adjusted_usd / LAG(price_adjusted_usd,

        1) OVER (PARTITION BY sec_id

        ORDER BY tanggal) - 1 + dividend_return, NULL
        ) 
        -

        suku bunga / 252 AS return_usd_excess DARI harga

        Ini mungkin tampak seperti contoh yang berbelit-belit, tetapi diambil dari kueri nyata. Memang, ini juga lebih sederhana dan lebih kecil dari logika lengkap — perhatikan bahwa ini dimulai dari harga_disesuaikan, yang logikanya harus dipecah menjadi kueri sebelumnya untuk menghindari SQL menjadi kurang terbaca.

        Ini pertanyaan yang sama dengan PRQL:

        prql Versi: kapan: 0.0.1 db: 

        kepingan salju # Versi: kapan nomor & nama basis data . fungsi lag_day x = ( wi ndow x split sec_id sort date lag

        1

        ) fungsi ret x = x /

        (

        x | lag_day

        )
        -

        1 + dividend_return

         func 

        kelebihan x = (x

        -

        suku bunga) / 252

         func 

        jika_valid x = is_valid_price ? x : null dari harga return_total = harga_adj

        |

        ret

        | if_valid # `|` dapat digunakan daripada baris baru. 

        return_usd = harga_usd | ret | if_valid return_excess = return_total | kelebihan

        return_usd_excess 
        = return_usd | kelebihan pilih 

        [ date, sec_id, return_total, return_usd, return_excess, return_usd_excess,]

          Karena kami mendefinisikan fungsi sekali daripada menyalin & menempelkan kode, kami mendapatkan semua manfaat enkapsulasi dan ekstensibilitas — kami dapat memiliki fungsi yang andal & teruji, yang tujuannya eksplisit, yang dapat kami bagikan ke seluruh kueri dan kolega.

          Prinsip

          PRQL dimaksudkan untuk menjadi bahasa deklaratif yang modern, sederhana, untuk mentransformasi data, dengan abstraksi seperti variabel & fungsi. Ini dimaksudkan untuk menggantikan SQL, tetapi tidak memiliki ambisi sebagai bahasa pemrograman tujuan umum. Meskipun berada pada tahap pra-alfa, ia memiliki beberapa prinsip yang tidak dapat diubah:

        Pipelined — PRQL adalah jalur transformasi linier — setiap baris kueri adalah transformasi dari hasil baris sebelumnya. Ini membuatnya mudah dibaca, dan mudah ditulis. Ini juga dikenal sebagai "gaya bebas poin".

      • Sederhana — PRQL melayani insinyur dan analis yang canggih tanpa pengalaman pengkodean. Dengan menyediakan abstraksi yang sederhana dan bersih, bahasa dapat menjadi kuat dan mudah digunakan.
      • Kompatibel — PRQL mentranspilasikan ke SQL, sehingga dapat digunakan dengan database apa pun yang menggunakan SQL. Jika memungkinkan PRQL dapat menyatukan sintaks di seluruh database. PRQL harus memungkinkan onramp bertahap — seharusnya praktis untuk mencampur SQL ke dalam kueri PRQL di mana PRQL belum memiliki implementasi. Analitik — Fokus PRQL adalah kueri analitis; kami tidak menekankan fitur SQL lainnya seperti memasukkan data atau transaksi.
      • Dapat diperluas — PRQL dapat diperluas melalui abstraksinya, dan dapat berkembang tanpa merusak kompatibilitas mundur, karena kuerinya dapat menentukan versi PRQL-nya.
      • Jika Anda tertarik dengan ide-ide di sini dan ingin melihatnya dieksplorasi:

        • Bintangi repo ini.
      • Buka masalah:
      • Kueri SQL analitik yang canggung dan bisa kita gunakan sebagai kasus untuk menerjemahkan ke PRQL. Jika Anda ingin menambahkan saran tentang PRQL yang setara, silakan juga.
      • Area yang tidak cukup dibahas dalam proposal yang ada.
      • Kueri SQL analitik yang menurut Anda akan menjadi

        lagi sulit diungkapkan dalam PRQL.

      • Kirim repo ke beberapa orang yang pendapatnya Anda hormati.
      • Berlangganan Edisi #1 untuk pembaruan .
      • (Jika Anda ingin membantu pada kompiler, biarkan M e tahu, tapi itu di av ery tahap awal.)
      • Semua ini akan menginspirasi saya untuk menghabiskan lebih banyak waktu mengembangkan ini; Terima kasih sebelumnya.

        Terinspirasi oleh

      • dplyr is bahasa yang indah untuk memanipulasi data, di R. Ini sangat mirip dengan PRQL. Ini hanya bekerja pada data R dalam memori.
      • Kusto juga cantik bahasa pipa, sangat mirip dengan PRQL. Tapi itu hanya bisa menggunakan DB yang kompatibel dengan Kusto.
      • Transpiler Kusto-to-SQL akan menjadi alternatif yang sah untuk PRQL, meskipun akan ada beberapa kendala ketidaksesuaian di beberapa daerah. Kritik utama saya terhadap Kusto adalah ia melepaskan kompatibilitas luas tanpa mendapatkan imbalan sebanyak itu.
      • DataPipes.jl & Rantai Julia. jl, yang menunjukkan seberapa efektif pipeline tanpa titik, dan bagaimana line-break dapat berfungsi sebagai pipa.
      • Sintaks Ocaml yang elegan dan sederhana.

      • Malloy, dari @lloydtabb terlihat sangat menarik, dan memiliki tim untuk membuatnya sukses. Saya akan meluangkan lebih banyak waktu untuk memeriksanya.
      • Setelah menulis proposal ini (termasuk namanya!), saya menemukan Preql. Meskipun nama dan kompilasinya mirip dengan SQL, tampaknya lebih fokus pada pembuatan bahasa seperti python, yang sangat berbeda dengan proposal ini.
      • Tulis pengurai dasar

        • Saat ini penulisannya menggunakan nom.
        • Tulis kompiler dasar

        • Ini seharusnya cukup mudah karena hanya menghasilkan SQL.
      • Tunjukkan beberapa contoh yang lebih rumit — misalnya sebagian besar contoh di https://github.com/dbt-labs/dbt-utils semuanya dapat dibahas lebih baik dengan ini.
        Bergabung

        1. Bergabung diimplementasikan sebagai {join_type} {tabel} {[conditions]}

        2. . Sebagai contoh:

          dari karyawan kiri_bergabung posisi [id=employee_id]
            
            

            ...setara dengan. ..

            PILIH * DARI

            karyawan KIRI GABUNG posisi PADA Indo = identitas pegawai

          • Mungkin kita bisa mempersingkat [id=id] ke Indo, dan gunakan SQL MENGGUNAKAN, tetapi mungkin ambigu dengan menggunakan Indo sebagai kolom boolean.

          • Fungsi

              • Fungsi dapat mengambil dua jenis argumen yang terpisah:
                Argumen posisi. Penelepon harus melewati ini.

              • Argumen bernama, yang secara opsional dapat memiliki nilai default .
              • Jadi fungsinya seperti:

                 func lag col sort_col split_col=id = ( jendela col split split_col sort sort_col lag 1 )

                  ...disebut lag, membutuhkan tiga argumen kol,

                • sort_col & split_col, di mana dua yang pertama banyak dipasok, yang ketiga dapat secara opsional disuplai dengan split_col:sec_id.

                Tugas

                Untuk membuat kolom, kami menggunakan

              • {column_name}={perhitungan}
              • dalam pipa. Secara teknis ini adalah "meningkatkan" kolom — itu akan membuat atau menimpa kolom, tergantung pada apakah kolom itu sudah ada. Saya akan terbuka untuk sintaks alternatif, mengingat sintaks ini umumnya merupakan pernyataan baru di sebagian besar bahasa pemrograman.

              • Tapi saya tidak bisa memikirkan sintaks yang lebih familiar dari ini.
                • Mungkin

                biarkan {column_name} {kalkulasi} akan lebih konsisten dengan kata kunci lainnya?

                Daftar

              • Saat ini daftar memerlukan tanda kurung ; tidak ada daftar implisit seperti:

                dari karyawan pilih gaji # gagal,

                akan membutuhkan `select [salary]

                `

                Untuk beberapa fungsi di mana kami hanya mengharapkan satu argumen, seperti Pilih, kami dapat menerima satu argumen bukan sebagai daftar?

              • Pipa

                1. Pemutusan baris umumnya menciptakan transformasi pipelined. Sebagai contoh:

                  dari tbl pilih 
                  [col1, col2]

                  Saring col1 = col2

                  .. .setara dengan:

                  dari tbl | Pilih [col1, col2]
                   | filter col1 =
                   col2 
                  • Pemutusan baris tidak membuat jalur pipa dalam beberapa kasus :

                    • Dalam daftar (misalnya Pilih mantan cukup di atas).
                    • Bila baris berikut adalah pernyataan baru, dengan memulai dengan kata kunci seperti fungsi.

                2. Hasil sebelumnya dilewatkan sebagai argumen terakhir dari suatu fungsi; yaitu agregat

                3. akan menjadi; dimana

                4. X diambil dari baris di atas:

                  agregat split=
                  [begin]
                   kalkulasi X

                5. Sintaks CTE — seperti tabel=?

                6. Sintaks mentah — Saya pikir kita harus memiliki backticks yang mewakili mentah SQL; yaitu

                7. UPPER
                8. dapat didefinisikan sebagai:

                  fungsi 

                  kol atas = `ATAS([begin] `col`)` # atau dengan f-rangkaian-seperti sintaks fungsi kolom atas = `

                  UPPER(

                  {

                  kol}

                  )

                  ` # atau dengan " daripada ` fungsi atas col=" ATAS

                  (

                  {kol })"

                9. Array — PRQL sebagian terinspirasi oleh DataPipes.jl, yang menunjukkan betapa efektifnya pipeline tanpa titik (Chain.jl serupa). Salah satu manfaat dari ini adalah seberapa baik berurusan dengan pipa bersarang sewenang-wenang - yang sulit dibaca di SQL dan bahkan di
                10. jq
                11. . Bisakah kita melakukan sesuatu yang serupa untuk data bersarang di PRQL?

          • Berikut cuplikan dari DataPipes.jl — dan kita dapat menghindari makro / melakukan / akhir):

            @P mulai strip teks membelah(__, "n
            "

            ) peta() melakukan __ kumpulkan peta() melakukan __ __ == karakter [begin] ? 1 :

            0

            akhir akhir hcat(__[begin] ...)' akhir

              Partial — seberapa fungsional kita ingin membuat lang? misalnya haruskah kita memiliki fungsi parsial? misalnya

              berpotensi kita tidak membutuhkan

            • kol
            • di ketinggalan di sini?

               func 

              lag col = jendela col split : sec_id sort: keterlambatan tanggal

                : 1
            • Logika Boolean — bagaimana seharusnya kita merepresentasikan logika boolean seperti atau ? Dengan beberapa atau fungsi yang membutuhkan *args

            • (yang saat ini belum memiliki desain untuk kami)? Atau mengimplementasikan operator diadik; baik

            • atau
            • atau ||? (Sama untuk tidak)

              dari — apakah kita membutuhkan dari? Versi sebelumnya dari proposal ini tidak memerlukan ini — cukup mulai dengan nama tabel. Tetapi beberapa umpan balik awal adalah bahwa menghapus dari

            • membuatnya kurang jelas.
            • Sintaks Readme — kita tidak bisa mendapatkan penyorotan sintaks di penurunan harga GitHub — apakah ada solusi untuk ini selain mengirimkan parser ke GitHub / tangkapan layar / membuat situs web?

            • Saat ini kami menggunakan elm

            • karena secara kebetulan memberikan sorotan sintaks terbaik (terbuka untuk saran untuk orang lain!).

            • Sebelum penguraian penuh r & compiler, bisakah kita menggunakan sesuatu seperti Codex untuk menghasilkan transformasi, dan mari kita jelajahi ruang? Kami dapat memberikan contoh kami sendiri, dengan menggunakan fine-tuning. Mengubah contoh lebih mudah daripada mengubah kompiler!

              Baca selengkapnya