Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Pilih Semua Acara dengan Acara->Jadwal->Tanggal antara tanggal mulai dan berakhir di CakePHP

Dalam situasi seperti ini, saya cenderung tidak menggunakan asosiasi Cake, atau Containable, dan membuat gabungan sendiri:

$events = $this->Event->find('all', array(
    'joins'=>array(
        array(
            'table' => $this->Schedule->table, 
            'alias' => 'Schedule', 
            'type' => 'INNER', 
            'foreignKey' => false,
            'conditions'=> array(
                'Schedule.event_id = Event.id',
            ),
        ),
        array(
            'table' => $this->Date->table, 
            'alias' => 'Date', 
            'type' => 'INNER', 
            'foreignKey' => false,
            'conditions'=> array(
                'Date.schedule_id = Schedule.id',
            ),
        ),
    ),
    'conditions'=>array(
        'Date.start >=' => $start_date,
        'Date.start <=' => $end_date,
    ),
    'order'=>'Event.created DESC',
    'limit'=>5
));

Agak tebal, tetapi menghasilkan kueri persis seperti yang saya inginkan.

PERBARUI

Mari pecahkan kode Anda menjadi beberapa bagian dan lihat di mana kami dapat memperbaikinya. Bagian pertama adalah persiapan untuk find . Saya telah menulis ulang kode Anda untuk membuatnya lebih pendek, dan inilah yang saya dapatkan:

// Default options go here
$defaultOpts = array(
    'start' => date('Y-m-d') . ' 00:00:00',
    'end' => date('Y-m-d') . ' 23:59:59',
    'limit' => 10
)

// Use default options if nothing is passed, otherwise merge passed options with defaults
$opts = is_array($opts) ? array_merge($defaultOpts, $opts) : $defaultOpts;

// Initialize array to hold query conditions
$conditions = array();

//date conditions
$conditions[] = array(
    "Date.start >=" => $qOpts['start'],
    "Date.start <=" => $qOpts['end'],
));

//cities conditions
if(isset($opts['cities']) && is_array($opts['cities'])) {
    $conditions['OR'] = array();
    $conditions['OR'][] = array('Venue.city_id'=>$opts['cities']);
    $conditions['OR'][] = array('Restaurant.city_id'=>$opts['cities']);
}

//event types conditions
//$opts['event_types'] = array('1');
if(isset($opts['event_types']) && is_array($opts['event_types'])) {
    $conditions[] = 'EventTypesEvents.event_type_id' => $opts['event_types']
}

//event sub types conditions
if(isset($opts['event_sub_types']) && is_array($opts['event_sub_types'])) {
    $conditions[] = 'EventSubTypesEvents.event_sub_type_id' => $opts['event_sub_types']
}

//event sub sub types conditions
if(isset($opts['event_sub_types']) && is_array($opts['event_sub_sub_types'])) {
    $conditions[] = 'EventSubSubTypesEvents.event_sub_sub_type_id' => $opts['event_sub_sub_types']
}

Perhatikan bahwa saya menghilangkan sebagian besar OR. Itu karena Anda dapat melewatkan array sebagai nilai dalam conditions , dan Cake akan membuatnya menjadi IN(...) pernyataan dalam SQL Query. Misalnya:'Model.field' => array(1,2,3) menghasilkan 'Model.field IN (1,2,3)' . Ini berfungsi seperti OR, tetapi membutuhkan lebih sedikit kode. Jadi blok kode di atas melakukan hal yang sama persis seperti yang dilakukan kode Anda, tetapi lebih pendek.

Sekarang sampai pada bagian yang kompleks, find sendiri.

Biasanya saya akan merekomendasikan penggabungan paksa saja, tanpa Containable, dan dengan 'recursive'=>false . Saya percaya ini biasanya adalah cara terbaik untuk menangani temuan kompleks. Dengan Associations dan Containable, Cake menjalankan beberapa query SQL terhadap database (satu query per Model/tabel), yang cenderung tidak efisien. Juga, Containable tidak selalu mengembalikan hasil yang diharapkan (seperti yang Anda perhatikan saat mencobanya).

Tapi karena dalam kasus Anda ada empat asosiasi kompleks yang terlibat, mungkin pendekatan campuran akan menjadi solusi ideal - jika tidak, akan terlalu rumit untuk membersihkan data duplikat. (4 asosiasi kompleks adalah:Acara memiliki Banyak Tanggal [melalui Acara memiliki Banyak Jadwal, Jadwal memiliki Banyak Tanggal], Jenis Peristiwa HABTM Peristiwa, SubJenis Peristiwa HABTM Peristiwa, SubSubJenis Peristiwa HABTM Peristiwa). Jadi, kita bisa membiarkan Cake menangani pengambilan data EventType, EventSubType, dan EventSubSubType, menghindari terlalu banyak duplikat.

Jadi inilah yang saya sarankan:gunakan gabungan untuk semua pemfilteran yang diperlukan, tetapi jangan sertakan Tanggal dan [Sub[Sub]]Jenis di bidang. Karena asosiasi model yang Anda miliki, Cake akan secara otomatis menjalankan kueri tambahan terhadap DB untuk mengambil bit data tersebut. Tidak perlu Containable.

Kode:

// We already fetch the data from these 2 models through
// joins + fields, so we can unbind them for the next find,
// avoiding extra unnecessary queries. 
$this->unbindModel(array('belongsTo'=>array('Restaurant', 'Venue'));

$data = $this->find('all', array(
    // The other fields required will be added by Cake later
    'fields' => "
        Event.*, 
        Restaurant.id, Restaurant.name, Restaurant.slug, Restaurant.address, Restaurant.GPS_Lon, Restaurant.GPS_Lat, Restaurant.city_id,
        Venue.id, Venue.name, Venue.slug, Venue.address, Venue.GPS_Lon, Venue.GPS_Lat, Venue.city_id,
        City.id, City.name, City.url_name
    ",  
    'joins' => array(
        array(
            'table' => $this->Schedule->table,
            'alias' => 'Schedule',
            'type' => 'INNER',
            'foreignKey' => false,
            'conditions' => 'Schedule.event_id = Event.id',
        ),
        array(
            'table' => $this->Schedule->Date->table,
            'alias' => 'Date',
            'type' => 'INNER',
            'foreignKey' => false,
            'conditions' => 'Date.schedule_id = Schedule.id',
        ),
        array(
            'table' => $this->EventTypesEvent->table,
            'alias' => 'EventTypesEvents',
            'type' => 'INNER',
            'foreignKey' => false,
            'conditions' => 'EventTypesEvents.event_id = Event.id',
        ),
        array(
            'table' => $this->EventSubSubTypesEvent->table,
            'alias' => 'EventSubSubTypesEvents',
            'type' => 'INNER',
            'foreignKey' => false,
            'conditions' => 'EventSubSubTypesEvents.event_id = Event.id',
        ),
        array(
            'table' => $this->Restaurant->table,
            'alias' => 'Restaurant',
            'type' => 'LEFT',
            'foreignKey' => false,
            'conditions' => 'Event.restaurant_id = Restaurant.id',
        ),
        array(
            'table' => $this->City->table,
            'alias' => 'RestaurantCity',
            'type' => 'LEFT',
            'foreignKey' => false,
            'conditions' => 'Restaurant.city_id = city.id',
        ),
        array(
            'table' => $this->Venue->table,
            'alias' => 'Venue',
            'type' => 'LEFT',
            'foreignKey' => false,
            'conditions' => 'Event.venue_id = Venue.id',
        ),
        array(
            'table' => $this->City->table,
            'alias' => 'VenueCity',
            'type' => 'LEFT',
            'foreignKey' => false,
            'conditions' => 'Venue.city_id = city.id',
        ),
    ),
    'conditions' => $conditions,
    'limit' => $opts['limit'],
    'recursive' => 2
));

Kami menghilangkan contains , dan beberapa kueri tambahan yang dijalankan Cake karenanya. Sebagian besar gabungan bertipe INNER . Ini berarti bahwa setidaknya satu catatan harus ada di kedua tabel yang terlibat dalam gabungan, atau Anda akan mendapatkan hasil yang lebih sedikit dari yang Anda harapkan. Saya berasumsi setiap Acara berlangsung di Restoran ATAU sebuah Tempat, tetapi tidak keduanya, itu sebabnya saya menggunakan LEFT untuk tabel tersebut (dan kota). Jika beberapa bidang yang digunakan dalam gabungan bersifat opsional, Anda harus menggunakan LEFT bukannya INNER pada gabungan terkait.

Jika kita menggunakan 'recursive'=>false di sini, kami masih mendapatkan peristiwa yang tepat, dan tidak ada pengulangan data, tetapi tanggal dan [Sub[Sub]]Jenis akan hilang. Dengan 2 tingkat rekursi, Cake akan secara otomatis mengulang peristiwa yang dikembalikan, dan untuk setiap peristiwa akan menjalankan kueri yang diperlukan untuk mengambil data model terkait.

Ini hampir seperti yang Anda lakukan, tetapi tanpa Containable, dan dengan beberapa penyesuaian tambahan. Saya tahu ini masih merupakan bagian kode yang panjang, jelek dan membosankan, tapi bagaimanapun juga ada 13 tabel database yang terlibat...

Ini semua adalah kode yang belum diuji, tetapi saya yakin ini akan berhasil.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Menggunakan variabel dalam klausa LIMIT di MySQL

  2. Tip Singkat MySQL:Menggunakan Perintah DROP USER

  3. Bagaimana menuliskan ke database banyak penulis dalam tabel buku sederhana?

  4. SQLException Aneh:Kolom tidak ditemukan

  5. apa gunanya opsi kumpulan di database.yml?