Asisten Basis Data GreenPig

  1. Entri
  2. Koneksi perpustakaan
  3. Kelas mana
  4. Bergabunglah dengan kelas
  5. Kueri kelas

╔═══╗╔═══╗╔═══╗╔═══╗╔╗─╔╗────╔═══╗╔══╗╔═══╗ β•‘β•”β•β•β•β•‘β•”β•β•—β•‘β•‘β•”β•β•β•β•‘β•”β•β•β•β•‘β•šβ•β•β•‘β”€β”€β”€β”€β•‘β•”β•β•—β•‘β•šβ•—β•”β•β•‘β•”β•β•β• β•‘β•‘β•”β•β•—β•‘β•šβ•β•β•‘β•‘β•šβ•β•β•—β•‘β•šβ•β•β•—β•‘β•”β•—β”€β•‘β”€β”€β”€β”€β•‘β•šβ•β•β•‘β”€β•‘β•‘β”€β•‘β•‘β•”β•β•— β•‘β•‘β•šβ•—β•‘β•‘β•”β•—β•”β•β•‘β•”β•β•β•β•‘β•”β•β•β•β•‘β•‘β•šβ•—β•‘β”€β”€β”€β”€β•‘β•”β•β•β•β”€β•‘β•‘β”€β•‘β•‘β•šβ•—β•‘ β•‘β•šβ•β•β•‘β•‘β•‘β•‘β•‘β”€β•‘β•šβ•β•β•—β•‘β•šβ•β•β•—β•‘β•‘β”€β•‘β•‘β”€β”€β”€β”€β•‘β•‘β”€β”€β”€β•”β•β•šβ•—β•‘β•šβ•β•β•‘ β•šβ•β•β•β•β•šβ•β•šβ•β”€β•šβ•β•β•β•β•šβ•β•β•β•β•šβ•β”€β•šβ•β”€β”€β”€β”€β•šβ•β”€β”€β”€β•šβ•β•β•β•šβ•β•β•β• 5HHHG HH HHHHHHH 9HHHA HHHHHHHH5 HHHHHHHHHHHHHHHHHH 9HHHHH5 5HHHHHHHHHHHHHHHHHHHHHHHHHHH HHHHHHHHHHHHHHHHHHHHHHHHHHHH ;HHHHHHHHHHHHHHHHHHHHHHHHHHA H2 HHHHHHHHHHHHHHHHHHHHHH HHHHHHHHHHHHHHHHHHHHHHH9 HHHHHHHHHHHHHHHHHHHHHHH AHHHHHHHHHHHHHHHHHHHHHH HHHHHHHHHHHHHHHHHHHHH9 iHS HHHHHHHHHHHHHHHHHHHHHHhh HHHHHHHHHHHHHHHHHH AA HHHHHHHHHHHHHH3 &H Hi HS Hr & H& H& Hi 

Entri


Saya ingin memberi tahu Anda tentang pengembangan perpustakaan kecil saya di php. Tugas apa yang dia selesaikan? Mengapa saya memutuskan untuk menulisnya dan mengapa itu bisa bermanfaat bagi Anda? Nah coba jawab pertanyaan-pertanyaan ini.


GreenPig (selanjutnya disebut GP ) adalah asisten basis data kecil yang dapat melengkapi fungsionalitas kerangka kerja php yang Anda gunakan.


Seperti halnya alat GP , itu diasah untuk tugas-tugas tertentu. Ini akan berguna bagi Anda jika Anda lebih suka menulis kueri basis data dalam sql murni dan tidak menggunakan catatan aktif dan teknologi serupa lainnya. Sebagai contoh, kami memiliki basis data Oracle di tempat kerja dan seringkali kueri menempati beberapa layar dengan puluhan gabungan, fungsi plsql, gabungan semua, dll. Masih digunakan. dll, jadi tidak ada yang tersisa untuk dilakukan selain menulis kueri dalam sql murni.


Tetapi dengan pendekatan ini, muncul pertanyaan: bagaimana cara menghasilkan di mana bagian dari permintaan sql ketika pengguna mencari informasi? Pertama-tama, GP ditujukan untuk kompilasi yang nyaman melalui php di mana ada permintaan kompleksitas.


Tetapi apa yang mendorong saya untuk menulis perpustakaan ini (kecuali, tentu saja, untuk mendapatkan pengalaman yang menarik)? Ini adalah tiga hal:


Pertama, kebutuhan untuk mendapatkan bukan jawaban flat standar dari database, tetapi array, seperti pohon bersarang.


Berikut adalah contoh sampel basis data standar:
 [ [0] => [ ['id'] => 1 ['type'] => 'car' ['val_id'] => 1 ['name'] => ' ()' ['value'] => 790 ], [1] => [ ['id'] => 1 ['type'] => 'car' ['val_id'] => 2 ['name'] => '   ' ['value'] => 24 ], [2] => [ ['id'] => 1 ['type'] => 'car' ['val_id'] => 3 ['name'] => ' ' ['value'] => 75 ], [3] => [ ['id'] => 4 ['type'] => 'phone' ['val_id'] => 10 ['name'] => ' ' ['value'] => 5 ], [4] => [ ['id'] => 4 ['type'] => 'phone' ['val_id'] => 8 ['name'] => ' ()' ['value'] => 0.12 ], [5] => [ ['id'] => 4 ['type'] => 'phone' ['val_id'] => 9 ['name'] => '   ' ['value'] => 1 ], [6] => [ ['id'] => 4 ['type'] => 'phone' ['val_id'] => 10 ['name'] => ' ' ['value'] => 5 ], [7] => [ ['id'] => 4 ['type'] => 'phone' ['val_id'] => 8 ['name'] => ' ()' ['value'] => 0.12 ], [8] => [ ['id'] => 4 ['type'] => 'phone' ['val_id'] => 9 ['name'] => '   ' ['value'] => 1 ], [9] => [ ['id'] => 4 ['type'] => 'phone' ['val_id'] => 10 ['name'] => ' ' ['value'] => 5 ], [10] => [ ['id'] => 4 ['type'] => 'phone' ['val_id'] => 8 ['name'] => ' ()' ['value'] => 0.12 ], [11] => [ ['id'] => 4 ['type'] => 'phone' ['val_id'] => 9 ['name'] => '   ' ['value'] => 1 ], [12] => [ ['id'] => 1 ['type'] => 'car' ['val_id'] => 1 ['name'] => ' ()' ['value'] => 790 ], [13] => [ ['id'] => 1 ['type'] => 'car' ['val_id'] => 2 ['name'] => '   ' ['value'] => 24 ], [14] => [ ['id'] => 1 ['type'] => 'car' ['val_id'] => 3 ['name'] => ' ' ['value'] => 75 ], [15] => [ ['id'] => 1 ['type'] => 'car' ['val_id'] => 1 ['name'] => ' ()' ['value'] => 790 ], [16] => [ ['id'] => 1 ['type'] => 'car' ['val_id'] => 2 ['name'] => '   ' ['value'] => 24 ], [17] => [ ['id'] => 1 ['type'] => 'car' ['val_id'] => 3 ['name'] => ' ' ['value'] => 75 ] ] 

Untuk mendapatkan susunan mirip pohon, kita perlu membawa hasilnya sendiri ke formulir yang diinginkan, atau membuat N basis data permintaan untuk setiap produk. Dan jika kita perlu pagination, dan bahkan dengan menyortir? GP mampu menyelesaikan masalah ini. Berikut adalah contoh sampel dengan GP :


 [ [1] => [ ['prod_type'] => 'car' ['properties'] => [ [1] => [ ['name'] => ' ()' ['value'] => 790 ] [2] => [ ['name'] => '   ' ['value'] => 24 ] [3] => [ ['name'] => ' ' ['value'] => 75 ] ] ] [4] => [ ['prod_type'] => 'phone' ['properties'] => [ [10] => [ ['name'] => ' ' ['value'] => 5 ] [8] => [ ['name'] => ' ()' ['value'] => 0.12 ] [9] => [ ['name'] => '   ' ['value'] => 1 ] ] ] ] 

Dan tentu saja pada saat yang sama nyaman pagination dan sortasi: ->pagination(1, 10)->sort('id') .


Alasan kedua tidak begitu sering, tetapi tetap saja terjadi (dan dalam kasus saya ini adalah alasan utama). Jika beberapa entitas disimpan dalam database, dan properti entitas ini dinamis dan ditetapkan oleh pengguna, maka ketika Anda perlu mencari entitas dengan properti mereka, Anda harus menambahkan (bergabung) tabel yang sama dengan nilai properti (sebanyak yang digunakan properti saat mencari). Jadi, GP akan membantu Anda menghubungkan semua tabel dan menghasilkan kueri tempat dengan hampir satu fungsi. Menjelang akhir artikel saya akan menganalisis kasus ini secara rinci.


Dan akhirnya, semua ini harus bekerja untuk database Oracle dan untuk mySql. Ada juga sejumlah fitur yang dijelaskan dalam dokumentasi.


Mungkin saja saya menemukan sepeda lain, tetapi saya dengan cermat mencari dan tidak menemukan solusi yang cocok untuk saya. Jika Anda tahu perpustakaan yang memecahkan masalah ini - silakan tulis di komentar.


Sebelum melanjutkan langsung ke pemeriksaan perpustakaan itu sendiri dan ke contoh, saya akan mengatakan bahwa hanya akan ada esensi, tanpa penjelasan rinci. Jika Anda tertarik pada cara kerja GP , Anda dapat melihat dokumentasi , di dalamnya saya mencoba menjelaskan semuanya secara rinci.


Koneksi perpustakaan


Perpustakaan dapat diinstal melalui komposer: composer require falbin/green-pig-dao


Maka Anda perlu menulis pabrik tempat Anda akan menggunakan perpustakaan ini.


Kelas mana


Menggunakan kelas ini, Anda dapat menyusun bagian mana dari kueri sql dari segala kompleksitas.


Bagian atom dari permintaan


Pertimbangkan bagian atom terkecil dari kueri. Dijelaskan oleh sebuah array: [, , ]
Contoh: ['name', 'like', '%%']


  • Elemen pertama array hanyalah string, dimasukkan ke dalam kueri sql tanpa perubahan, dan, oleh karena itu, Anda dapat menulis fungsi sql di dalamnya. Contoh: ['LOWER(name)', 'like', '%%']
  • Elemen kedua juga merupakan string yang dimasukkan ke dalam sql tanpa perubahan antara dua operan. Itu dapat mengambil nilai-nilai berikut: =,>, <,> =, <=, <>, seperti, tidak suka, antara, bukan antara, di, bukan di .
  • Elemen ketiga dari array dapat berupa tipe numerik atau string. Di mana kelas akan secara otomatis mengganti alias yang dihasilkan ke dalam kueri sql.
  • Elemen array dengan kunci sql. Terkadang perlu bahwa nilai dimasukkan ke dalam kode sql tanpa perubahan. Misalnya, untuk menerapkan fungsi. Ini dapat dicapai dengan menetapkan 'sql' sebagai kunci (untuk elemen ke-3). Contoh: ['LOWER(name)', 'like', 'sql' => "LOWER('$name')"]
  • Elemen array dengan kunci bind adalah array untuk menyimpan binding. Contoh di atas salah dari sudut pandang keamanan. Anda tidak dapat memasukkan variabel ke dalam sql - terlalu banyak injeksi. Karenanya, dalam hal ini, Anda perlu menentukan alias sendiri, misalnya seperti ini: ['LOWER(name)', 'like', 'sql' => "LOWER(:name)", 'bind'=> ['name' => $name] ]
  • Operator dalam dapat ditulis seperti ini: ['curse', 'not in', [1, 3, 5]] . Kelas Where mengonversi entri seperti itu ke kode sql berikut: curse not in (:al_where_jCgWfr95kh, :al_where_mCqefr95kh, :al_where_jCfgfr9Gkh)
  • Pernyataan antar dapat ditulis seperti ini: ['curse', ' between', 1, 5] . Kelas Where mengonversi entri seperti itu ke dalam kode sql berikut: curse between :al_where_Pi4CRr4xNn and :al_where_WiPPS4NKiG
    Tapi hati-hati, jika elemen ketiga dan keempat dari array adalah string, maka logika khusus diterapkan. Dalam hal ini, diyakini bahwa pemilihan berasal dari rentang tanggal dan, oleh karena itu, fungsi sql dari casting string ke tanggal digunakan. Fungsi mengkonversi ke tanggal (mySql dan Oracle memiliki yang berbeda) dan parameternya diambil dari berbagai pengaturan (lebih banyak dalam dokumentasi). Array ['build_date', 'between', '01.01.2016', '01.01.2019'] akan dikonversi ke sql: build_date between TO_DATE(:al_where_fkD7nZg5lU, 'dd.mm.yyyy hh24:mi::ss') and TO_DATE(:al_where_LdyVRznPF8, 'dd.mm.yyyy hh24:mi::ss')

Pertanyaan yang rumit


Mari kita membuat instance kelas melalui pabrik: $wh = GP::where();


Untuk menunjukkan koneksi logis antara "bagian atom" dari permintaan, Anda harus menggunakan fungsi linkAnd() atau linkOr() . Contoh:


 // sql: (old > 18 and old < 50) $wh->linkAnd([ ['old', '<', 18], ['old', '>', 50] ]); // sql: (old < 18 or old > 50) $wh->linkOr([ ['old', '<', 18], ['old', '>', 50] ]); 

Saat menggunakan fungsi linkAnd / linkOr, semua data disimpan di dalam instance kelas Where - $ wh. Juga, semua "bagian atom" yang ditunjukkan dalam fungsi diberi tanda kurung .


Sql dari kompleksitas apa pun dapat dijelaskan oleh tiga fungsi: linkAnd(), linkOr(), getRaw() . Pertimbangkan sebuah contoh:


 // sql: curse = 1 and (old < 18 or old > 50) $wh->linkAnd([ ['curse', '=', 1], $wh->linkOr([ ['old', '<', 18], ['old', '>', 50] ])->getRaw() ]); 

Kelas Where memiliki variabel pribadi yang menyimpan ekspresi mentah. Metode linkAnd() dan linkOr() menimpa variabel ini, oleh karena itu, ketika membangun ekspresi logis, metode bersarang bersama-sama dan variabel dengan ekspresi mentah berisi data yang diperoleh dari metode yang terakhir dieksekusi.


GABUNG GABUNG


Gabung adalah kelas yang menghasilkan fragmen kode sql bergabung. Mari kita membuat instance kelas melalui pabrik: $jn = GP::leftJoin('coursework', 'student_id', 's.id') , di mana:


  • kursus adalah tabel yang akan kita ikuti.
  • student_id - kolom dengan kunci asing dari tabel kursus .
  • s.id - kolom tabel yang digunakan untuk bergabung harus ditulis bersama dengan alias tabel (dalam hal ini, alias tabel adalah s).

Dihasilkan sql: left JOIN coursework coursework_joM9YuTTfW ON coursework_joM9YuTTfW.student_id = s.id


Saat membuat turunan kelas, kami sudah menggambarkan kondisi untuk bergabung dengan tabel, tetapi mungkin perlu untuk memperjelas dan memperluas kondisi. Fungsi linkAnd / linkOr akan membantu Anda melakukan ini: $jn->linkAnd(['semester_number', '>', 2])


Sql yang dihasilkan: inner JOIN coursework coursework_Nd1n5T7c0r ON coursework_Nd1n5T7c0r.student_id = s.id and (semester_number > :al_where_M1kEcHzZyy)


Jika ada beberapa tabel untuk bergabung, Anda bisa menggabungkannya di kelas: CollectionJoin .


Kueri kelas


Ini adalah kelas utama untuk bekerja dengan database, melaluinya ada seleksi, perekaman, pembaruan dan penghapusan data. Anda juga dapat melakukan pemrosesan data tertentu yang diperoleh dari database.


Pertimbangkan contoh khas.


Mari kita membuat instance kelas melalui pabrik: $qr = GP::query();


Sekarang kita akan mengatur template sql, menggantikan nilai-nilai yang diperlukan untuk skenario yang diberikan ke dalam template sql dan mengatakan bahwa kita ingin mendapatkan satu record, dan khususnya data dari kolom average_mark .


 $rez = $qr->sql("select /*select*/ from student s inner join mark m on s.id = m.student_id inner join lesson l on l.id = m.lesson_id /*where*/ /*group*/") ->sqlPart('/*select*/', 's.name, avg(m.mark) average_mark', []) ->whereAnd('/*where*/', ['s.id', '=', 1]) ->sqlPart('/*group*/', 'group by s.name', []) ->one('average_mark'); 

Hasil: 3,16666666666666666666666666666666666667


Seleksi dari database dengan parameter bersarang


Yang paling penting, saya tidak memiliki kesempatan untuk mendapatkan pilihan dari database dalam tampilan pohon, dengan properti terlampir. Oleh karena itu, perpustakaan GP memiliki kesempatan seperti itu, dan kedalaman sarang tidak terbatas.


Cara termudah untuk mempertimbangkan prinsip operasi didasarkan pada contoh. Untuk dipertimbangkan, kami mengambil skema basis data berikut :



Isi Tabel:



Seringkali, saat menanyakan database, Anda ingin mendapatkan jawaban seperti pohon, bukan jawaban datar. Misalnya, dengan menjalankan kueri ini:


 SELECT s.id, s.name, c.id title_id, c.title FROM student s INNER JOIN coursework c ON c. student_id = s.id WHERE s.id = 3 

Kami mendapatkan hasil yang datar:


 [ 0 => [ 'id' => 3, 'name' => '', 'title_id' => 6, 'title' => '«»    ', ], 1=> [ 'id' => 3, 'name' => '', 'title_id' => 7, 'title' => '  ' ] ] 

Dengan menggunakan GP, ​​Anda bisa mendapatkan hasil ini:


 [ 3 => [ 'name' => '', 'courseworks' => [ 6 => ['title' => '«»    '], 7 => ['title' => '  '] ] ] ] 

Untuk mencapai hasil ini, Anda harus meneruskan array dengan opsi ke all fungsi (fungsi mengembalikan semua baris permintaan):


 all([ 'id'=> 'pk', 'name' => 'name', 'courseworks' => [ 'title_id' => 'pk', 'title' => 'title' ] ]) 

Array $option dalam agregator fungsi ( $option , $ rawData) dan semua ( $options ) dibuat sesuai dengan aturan berikut:


  • Kunci array - nama kolom. Elemen array - nama baru untuk kolom, Anda dapat memasukkan nama lama.
  • Ada satu kata khusus untuk nilai array - pk . Dikatakan bahwa data akan dikelompokkan berdasarkan kolom ini (kunci array adalah nama kolom).
  • Di setiap level seharusnya hanya ada satu pk .
  • Dalam array teragregasi (menghasilkan), nilai-nilai dari kolom yang dinyatakan oleh pk akan digunakan sebagai kunci.
  • Jika perlu untuk menempatkan bagian kolom tingkat yang lebih rendah, maka nama baru yang diciptakan digunakan sebagai kunci array, dan array yang dibangun sesuai dengan aturan yang dijelaskan di atas akan digunakan sebagai nilai.

Pertimbangkan contoh yang lebih kompleks. Misalkan kita perlu mendapatkan semua siswa dengan nama kursus mereka dan dengan semua nilai di semua mata pelajaran. Kami ingin menerimanya bukan dalam bentuk datar, tetapi dalam bentuk seperti pohon, tanpa duplikat. Di bawah ini adalah permintaan yang diinginkan ke database dan hasilnya.


 SELECT s.id student_id, s.name student_name, s.semester_number, c.id coursework_id, c.semester_number coursework_semester, c.title coursework_title, l.id lesson_id, l.name lesson, m.id mark_id, m.mark FROM student s LEFT JOIN coursework c ON c.student_id = s.id LEFT JOIN mark m ON m.student_id = s.id LEFT JOIN lesson l ON l.id = m.lesson_id ORDER BY s.id, c.id, l.id, m.id 

Hasilnya tidak sesuai dengan kita:



Untuk mencapai tugas, Anda perlu menulis array $option berikut:


 $option = [ 'student_id' => 'pk', 'student_name' => 'name', 'courseworks' => [ 'coursework_semester' => 'pk', 'coursework_title' => 'title' ], 'lessons' => [ 'lesson_id' => 'pk', 'lesson' => 'lesson', 'marks' => [ 'mark_id' => 'pk', 'mark' => 'mark' ] ] ]; 

Permintaan basis data:


 //    Query   .       // (    yii2) $qr = Yii::$app->gp->query( "SELECT s.id student_id, s.name student_name, s.semester_number, c.id coursework_id, c.semester_number coursework_semester, c.title coursework_title, l.id lesson_id, l.name lesson, m.id mark_id, m.mark FROM student s LEFT JOIN coursework c ON c.student_id = s.id LEFT JOIN mark m ON m.student_id = s.id LEFT JOIN lesson l ON l.id = m.lesson_id ORDER BY s.id, c.id, l.id, m.id"); //   1,  2   3  //  1 $result = $qr->all($option); //  2 $result = $qr->aggregator($option, $qr->all()); //  3 $qr->all(); $result = $qr->aggregator($option, $qr->rawData()); 

Fungsi aggregator dapat memproses array apa pun dengan struktur yang mirip dengan hasil query database, sesuai dengan aturan yang dijelaskan dalam $option .


Variabel $result berisi data berikut:


 [ 1 => [ 'name' => '', 'courseworks' => [ 1 => ['title' => '    '], ], 'lessons' => [ 1 => [ 'lesson' => '', 'marks' => [ 1 => ['mark' => 3], 2 => ['mark' => 4] ] ], 2 => [ 'lesson' => '', 'marks' => [ 3 => ['mark' => 2], 4 => ['mark' => 2], 5 => ['mark' => 3] ] ], 4 => [ 'lesson' => '', 'marks' => [ 6 => ['mark' => 5] ] ] ] ], 3 => [ 'name' => '', 'courseworks' => [ 1 => ['title' => '«»    '], 2 => ['title' => '  '] ], 'lessons' => [ 1 => [ 'lesson' => '', 'marks' => [ 17 => ['mark' => 5] ] ], 2 => [ 'lesson' => '', 'marks' => [ 18 => ['mark' => 2] ] ], 3 => [ 'lesson' => '-', 'marks' => [ 20 => ['mark' => 4] ] ], 4 => [ 'lesson' => '', 'marks' => [ 16 => ['mark' => 2], 19 => ['mark' => 3] ] ], ] ] ] 

Ngomong-ngomong, dengan pagination dengan kueri teragregasi, hanya data teratas dan paling dasar yang dipertimbangkan. Pada contoh di atas, hanya akan ada 2 baris untuk pagination.


Penggabungan ganda dengan diri Anda atas nama pencarian


Seperti yang saya tulis sebelumnya, tugas utama perpustakaan saya adalah menyederhanakan pembuatan bagian-bagian di mana untuk kueri pemilihan. Jadi dalam hal ini kita mungkin perlu berulang kali bergabung dengan 'nite tabel yang sama untuk query di mana? Salah satu opsi adalah ketika kita memiliki produk tertentu yang propertinya tidak diketahui sebelumnya dan mereka akan ditambahkan oleh pengguna, dan kita perlu diberi kesempatan untuk mencari produk dengan properti dinamis ini. Cara termudah untuk menjelaskan dengan contoh sederhana.


Misalkan kita memiliki toko online yang menjual komponen komputer, dan kita tidak memiliki bermacam-macam ketat, dan kita akan secara berkala membeli satu komponen atau lainnya. Tetapi kami ingin menggambarkan semua produk kami sebagai satu kesatuan dan untuk mencari semua produk. Jadi, entitas apa yang dapat dibedakan dari sudut pandang logika bisnis:


  1. Produk. Entitas yang paling penting di mana semuanya dibangun.
  2. Jenis produk. Ini dapat direpresentasikan sebagai properti root untuk semua properti produk lainnya. Misalnya, di toko kecil kami hanya: RAM, SSD, dan HDD.
  3. Properti produk. Dalam implementasi kami, properti apa pun dapat diterapkan ke semua jenis produk, pilihan tetap ada di hati nurani manajer. Di toko kami, manajer hanya membuat 3 properti: ukuran memori, faktor bentuk, dan DDR.
  4. Nilai barang. Nilai yang akan dikendarai pembeli dalam pencarian.

Semua logika bisnis yang dijelaskan di atas tercermin secara rinci dalam gambar di bawah ini.



Misalnya, kami memiliki produk: 16 GB DDR 3 RAM . Dalam diagram, ini dapat ditampilkan sebagai berikut:



Struktur dan data dari database terlihat jelas pada gambar berikut:



Seperti yang kita lihat dari diagram, semua nilai semua properti disimpan dalam satu tabel val (omong-omong, dalam versi sederhana kami, semua properti memiliki nilai numerik). Karenanya, jika kami ingin mencari secara bersamaan beberapa properti dengan sekelompok AND, kami mendapatkan pilihan kosong.


Misalnya, pembeli mencari produk yang cocok untuk permintaan seperti itu: jumlah memori harus lebih dari 10 GB dan faktor bentuk harus 2,5 inci . Jika kami menulis sql seperti yang ditunjukkan di bawah ini, kami mendapatkan pilihan kosong:


 select * from product p inner join val v on v.product_id = p.id where (v.property_id = 1 and v.value > 10) AND (v.property_id = 3 and v.value = 2.5) 

Karena nilai semua properti disimpan dalam satu tabel, untuk mencari beberapa properti, Anda harus bergabung dengan tabel val untuk setiap properti yang akan dicari. Tetapi ada nuansa, gabung bergabung dengan tabel "horizontal" (untuk kata union semua bergabung "vertikal"), berikut ini adalah contoh:



Hasil ini tidak sesuai dengan kami, kami ingin melihat semua nilai dalam satu kolom. Untuk melakukan ini, Anda harus bergabung dengan tabel tabel 1 kali lebih banyak daripada properti di mana pencarian dilakukan.



Kami hampir secara otomatis menghasilkan kueri sql. Mari kita lihat fungsinya
whereWithJoin ($aliasJoin, $options, $aliasWhere, $where) , yang akan melakukan semua pekerjaan:


  • $ aliasJoin - alias di templat dasar, bukannya menggantikan bagian sql dengan joins.
  • $ options - array dengan deskripsi aturan untuk membuat bagian gabung.
  • $ aliasWhere - alias di templat dasar, yang menggantikan bagian mana sql sebagai gantinya.
  • $ where adalah instance dari kelas Where.

Mari kita lihat sebuah contoh: whereWithJoin('/*join*/', $options, '/*where*/', $wh) .


Pertama, buat variabel $ options : $options = ['v' => ['val', 'product_id', 'p.id']];


v adalah alias dari tabel. Jika alias yang diberikan ditemukan dalam $ wh , maka tabel val baru akan terhubung dengan bergabung (di mana product_id adalah kunci asing dari tabel val , dan p.id adalah kunci utama untuk tabel dengan alias p ), alias baru dan alias ini dihasilkan untuk itu akan mengganti v di mana.


$ wh adalah turunan dari kelas Where. Kami membentuk permintaan yang sama: memori harus lebih dari 10 GB dan faktor bentuk harus 2,5 inci.


 $wh->linkAnd([ $wh->linkAnd([ ['v.property_id', '=', 1], ['v.value', '>', 10] ])->getRaw(), //    $wh->linkAnd([ ['v.property_id', '=', 3], ['v.value', '=', 2.5] ])->getRaw(),//    ]); 

Saat membuat permintaan di mana, perlu untuk membungkus bagian dengan properti id dan nilainya dalam tanda kurung, ini memberitahu fungsi whereWithJoin() yang alias tabel akan sama di bagian ini.


 $qr->sql("select p.id, t.name type_name, pr.id prop_id, pr.name prop_name, v.id val_id, v.value from product p inner join type t on t.id = p.type_id inner join val v on v.product_id = p.id inner join properties pr on pr.id = v.property_id /*join*/ /*where*/") ->whereWithJoin('/*join*/', $options, '/*where*/', $wh) //     . ->all([ 'id' => 'pk', 'type_name' => 'type', 'properties' => [ 'prop_id' => 'pk', 'prop_name' => 'name', 'values' => [ 'val_id' => 'pk', 'value' => 'val' ] ] ]); 

Kami melihat melalui sql, $qr->debugInfo() , dan waktu eksekusi query yang dihasilkan: $qr->debugInfo() :


 [ [ 'type' => 'info', 'sql' => 'select p.id, t.name type_name, pr.id prop_id, pr.name prop_name, v.id val_id, v.value from product p inner join type t on t.id = p.type_id inner join val v on v.product_id = p.id inner join properties pr on pr.id = v.property_id inner JOIN val val_mIQWpnHhdQ ON val_mIQWpnHhdQ.product_id = p.id inner JOIN val val_J0uveMpwEM ON val_J0uveMpwEM.product_id = p.id WHERE ( val_mIQWpnHhdQ.property_id = :al_where_leV5QlmOZN and val_mIQWpnHhdQ.value > :al_where_ycleYAswIw ) and ( val_J0uveMpwEM.property_id = :al_where_dinxDraTOE and val_J0uveMpwEM.value = :al_where_wZJhUqs74i )', 'binds' => [ 'al_where_leV5QlmOZN' => 1, 'al_where_ycleYAswIw' => 10, 'al_where_dinxDraTOE' => 3, 'al_where_wZJhUqs74i' => 2.5 ], 'timeQuery' => 0.0384588241577 ] ] 

$qr->rawData() :


 [ [ 'id' => 3, 'type_name' => 'SSD', 'prop_id' => 1, 'prop_name' => ' ', 'val_id' => 5, 'value' => 512 ], [ 'id' => 3, 'type_name' => 'SSD', 'prop_id' => 3, 'prop_name' => '-', 'val_id' => 6, 'value' => 2.5 ], [ 'id' => 4, 'type_name' => 'SSD', 'prop_id' => 1, 'prop_name' => ' ', 'val_id' => 7, 'value' => 256 ], [ 'id' => 4, 'type_name' => 'SSD', 'prop_id' => 3, 'prop_name' => '-', 'val_id' => 8, 'value' => 2.5 ], [ 'id' => 6, 'type_name' => 'HDD', 'prop_id' => 1, 'prop_name' => ' ', 'val_id' => 11, 'value' => 1024 ], [ 'id' => 6, 'type_name' => 'HDD', 'prop_id' => 3, 'prop_name' => '-', 'val_id' => 12, 'value' => 2.5 ] ] 

$qr->aggregateData() :


 [ 3 => [ 'type' => 'SSD', 'properties' => [ 1 => [ 'name' => ' ', 'values' => [ 5 => ['val' => 512] ] ], 3 => [ 'name' => '-', 'values' => [ 6 => ['val' => 2.5] ] ] ] ], 4 => [ 'type' => 'SSD', 'properties' => [ 1 => [ 'name' => ' ', 'values' => [ 7 => ['val' => 256] ] ], 3 => [ 'name' => '-', 'values' => [ 8 => ['val' => 2.5] ] ] ] ], 6 => [ 'type' => 'HDD', 'properties' => [ 1 => [ 'name' => ' ', 'values' => [ 11 => ['val' => 1024] ] ], 3 => [ 'name' => '-', 'values' => [ 12 => ['val' => 2.5] ] ] ] ] ] 

, , whereWithJoin() , .


whereWithJoin() , , n , m . n m 1 id . , AND .




GitHub .

Source: https://habr.com/ru/post/id483458/


All Articles