Menggunakan DISTINCT dalam fungsi pencarian CakePHP

Saya sedang menulis aplikasi CakePHP 1.2. Saya memiliki daftar orang-orang yang saya ingin pengguna dapat memfilternya di berbagai bidang. Untuk setiap bidang yang dapat difilter, saya memiliki daftar drop-down. Pilih kombinasi filter, klik filter, dan halaman hanya menampilkan rekaman yang cocok.

Di people_controller, saya punya sedikit kode ini:

$first_names = $this->Person->find('list', array(
    'fields'=>'first_name',
    'order'=>'Person.first_name ASC',
    'conditions'=> array('Person.status'=>'1')
));
$this->set('first_names', $first_names);

(Status = 1 karena saya menggunakan soft delete.)

Itu menciptakan daftar semua nama_depan. Tapi duplikatnya ada di sana.

Menggali di Buku Masak, saya menemukan contoh menggunakan kata kunci DISTINCT dan memodifikasi kode saya untuk menggunakannya.

$first_names = $this->Person->find('list', array(
    'fields'=>'DISTINCT first_name',
    'order'=>'Person.first_name ASC',
    'conditions'=> array('Person.status'=>'1')
));

Ini memberi saya kesalahan SQL seperti ini:

Query: SELECT `Person`.`id`, DISTINCT `Person`.` first_name` FROM `people` AS `Person`   WHERE `Person`.`status` = 1   ORDER BY `Person`.`first_name` ASC

Masalahnya jelas. Kerangka kerja ini menambahkan Person.id ke kueri. Saya menduga ini berasal dari penggunaan 'daftar'.

Saya akan menggunakan filter yang dipilih untuk membuat pernyataan SQL ketika tombol filter diklik. Saya tidak memerlukan bidang is, tetapi tidak dapat menghilangkannya.

Terima kasih, Frank Luke


person Frank Luke    schedule 11.11.2009    source sumber


Jawaban (12)


Anda benar, sepertinya Anda tidak dapat menggunakan DISTINCT dengan list. Karena Anda tidak memerlukan id tetapi hanya namanya, Anda dapat menggunakan find all seperti di atas lalu $first_names = Set::extract($first_names, '/Person/first_name');. Itu akan memberi Anda sebuah array dengan nama depan yang berbeda.

person Marko    schedule 11.11.2009
comment
Ini tidak hanya berfungsi dengan sempurna untuk daftar tetapi saya juga telah menggunakan perintah set di tempat lain. Terima kasih telah berbagi tentang perpustakaan hebat ini! - person Frank Luke; 20.11.2009
comment
Saya mencoba ini, tapi saya masih menemukan duplikat dalam daftar yang dihasilkan. - person paullb; 28.06.2012
comment
@paullb Anda dapat menghapus duplikat dari array yang diekstraksi dengan array_unique. Dan selagi Anda melakukannya, lihatlah Hash class (sejak CakePHP 2.2) yang pada akhirnya akan menggantikan Set. - person Jari Keinänen; 03.07.2012
comment
@koiyu Itu benar tetapi jawaban yang diberikan tidak menghapus duplikat seperti yang disebutkan dalam pertanyaan. (Fungsi DISTINCT) - person paullb; 05.07.2012
comment
@Pyrite sepertinya belum dihapus book.cakephp. org/3.0/en/core-libraries/hash.html - person DIDoS; 31.10.2015
comment
@ele Saya yakin saya pasti bingung; kelas Set telah dihapus di 3.0 (yang merupakan pendahulu kelas Hash). - person Pyrite; 10.11.2015

Coba gunakan 'kelompokkan berdasarkan', ini berfungsi dengan sempurna:

$first_names = $this->Person->find('list', array(
  'fields'=>'first_name',
   'order'=>'Person.first_name ASC',
   'conditions'=> array('Person.status'=>'1'),
   'group' => 'first_name'));
person Kielanas    schedule 20.11.2009
comment
Ini berfungsi tetapi memiliki konsekuensi yang tidak diinginkan yaitu mengurutkan daftar berdasarkan nama_depan yang mungkin tidak diinginkan. - person paullb; 28.06.2012
comment
@paullb Saya juga punya masalah ini. Apakah ada solusi untuk masalah pesanan? - person trante; 28.08.2012

Anda dapat mencoba ini. Di sini ini membutuhkan ID Orang sebagai kunci, jadi tidak ada kemungkinan entri duplikat.

    $first_names = $this->Person->find('list', array(
    'fields' => array('id','first_name'),
    'conditions' => array('Person.status' => '1'),
   ));
    $this->set('first_names', $first_names);
person shravan uchil    schedule 23.01.2014

Inilah cara saya melakukannya di CakePHP 3.x:

     $query = $this->MyTables->find('all');
     $result = $query->distinct()->toArray();
person Dawoodjee    schedule 27.08.2015

Menggunakan pengelompokan SQL juga akan menghasilkan daftar yang berbeda. Tidak yakin dengan konsekuensi negatifnya, jika ada, tetapi tampaknya ini berhasil bagi saya.

$first_names = $this->Person->find('list', array(
    'fields' => 'first_name',
    'order' => 'first_name',
    'group' => 'first_name',
    'conditions' => array('Person.status' => '1'),
));
$this->set('first_names', $first_names);
person Synexis    schedule 19.06.2013

Saya tahu ini pertanyaan untuk CakePHP 1.2, tapi saya juga mencarinya dengan CakePHP versi 3. Dan di versi ini ada metode untuk membentuk Query menjadi berbeda:

$first_names = $this->Persons->find(
    'list',
    [
        'fields'=> ['name']
    ]
)
  ->distinct();
;

Ini akan menghasilkan query sql seperti ini:

SELECT DISTINCT Persons.name AS `Persons__name` FROM persons Persons

Namun metode distinct sedikit lebih kuat daripada hanya memasukkan DISTINCT ke dalam kueri.

Jika Anda hanya ingin membedakan hasil pada satu bidang, sehingga hanya membuang baris dengan nama duplikat, Anda juga dapat menggunakan metode berbeda dengan array bidang sebagai parameter:

$first_names = $this->Persons->find(
    'list',
    [
        'fields'=> ['id', 'name'] //it also works if the field isn't in the selection
    ]
)
  ->distinct(['name']); //when you use more tables in the query, use: 'Persons.name'
;

Ini akan menghasilkan kueri sql umum seperti ini (pastinya ini adalah kueri grup):

SELECT DISTINCT
    Persons.id AS `Persons__id`, Persons.name AS `Persons__name`
FROM persons Persons
GROUP BY name #respectively Persons.name

Semoga saya bisa membantu beberapa untuk CakePHP 3. :)

person TheFRedFox    schedule 04.06.2015

Ya, masalahnya adalah Anda menggunakan daftar yang dirancang untuk keluaran id/nilai. Anda mungkin harus melakukan find('all') dan kemudian membuat daftarnya sendiri.

person PetersenDidIt    schedule 11.11.2009

Ya, saya juga mencoba mengambil hasil unik dengan 'daftar' tetapi tidak berhasil. Lalu saya memperbaiki masalahnya dengan menggunakan 'semua'.

person Muthukumaran    schedule 12.11.2009

Dalam contoh sekarang di buku untuk versi 2 itu menyatakan hal berikut:

public function some_function() {
    // ...
    $justusernames = $this->Article->User->find('list', array(
        'fields' => array('User.username')
    ));
    $usernameMap = $this->Article->User->find('list', array(
        'fields' => array('User.username', 'User.first_name')
    ));
    $usernameGroups = $this->Article->User->find('list', array(
        'fields' => array('User.username', 'User.first_name', 'User.group')
    ));
    // ...
}

Dengan contoh kode di atas, vars yang dihasilkan akan terlihat seperti ini:

$justusernames = Array
(
    //[id] => 'username',
    [213] => 'AD7six',
    [25] => '_psychic_',
    [1] => 'PHPNut',
    [2] => 'gwoo',
    [400] => 'jperras',
)

$usernameMap = Array
(
    //[username] => 'firstname',
    ['AD7six'] => 'Andy',
    ['_psychic_'] => 'John',
    ['PHPNut'] => 'Larry',
    ['gwoo'] => 'Gwoo',
    ['jperras'] => 'Joël',
)

$usernameGroups = Array
(
    ['User'] => Array
    (
        ['PHPNut'] => 'Larry',
        ['gwoo'] => 'Gwoo',
    )

    ['Admin'] => Array
    (
        ['_psychic_'] => 'John',
        ['AD7six'] => 'Andy',
        ['jperras'] => 'Joël',
    )

)

Anda harus merencanakan kueri Anda dengan cara yang sedikit berbeda dan merencanakan database Anda untuk mengakomodasi pencarian daftar.

person Andrew Myers    schedule 12.04.2013

Dalam beberapa kasus, Anda ingin mengelompokkan dengan menggunakan beberapa kunci, tetapi Anda menginginkan elemen unik dalam hasilnya. Misalnya, Anda memiliki aplikasi kalender dengan dua jenis acara. Satu peristiwa pada hari pertama dan yang lainnya pada hari kedua bulan 1. Dan Anda ingin menampilkan atau menghitung semua peristiwa, dikelompokkan berdasarkan hari dan jenis. Jika hanya menggunakan DISTINCT saja, cukup sulit. Solusi paling sederhana adalah mengelompokkan dua kali:

$this->Events->virtualFields['count'] = 'COUNT(*)';                   
$acts  = $this->Activity->find('all',array(                   
             'group' => array('DAY(Event.start)','EventType.id'),
               ));
person gdm    schedule 03.04.2014

Cukup kelompokkan berdasarkan bidang yang ingin Anda bedakan.. atau gunakan Set::extract() lalu array_unique()

person Eric Wong    schedule 03.12.2013

Dalam versi 2.7-RC, ini berfungsi

$this->Model1->find('list', array(
      'fields' => array('Model1.field1', Model1.field1')
));
person Joshua H    schedule 04.07.2015