web-dev-qa-db-ja.com

CakePHPの検索機能でDISTINCTを使用する

私はCakePHP1.2アプリを書いています。ユーザーがさまざまなフィールドでフィルタリングできるようにしたいユーザーのリストがあります。フィルタ可能なフィールドごとに、ドロップダウンリストがあります。フィルタの組み合わせを選択し、[フィルタ]をクリックすると、一致するレコードのみがページに表示されます。

People_controllerには、次のコードがあります。

$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);

(ソフト削除を使用しているため、ステータス= 1です。)

これにより、すべてのfirst_namesの順序付きリストが作成されます。しかし、重複はそこにあります。

クックブックを掘り下げて、DISTINCTキーワードを使用した例を見つけ、それを使用するようにコードを変更しました。

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

これにより、次のようなSQLエラーが発生します。

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

問題は明らかです。フレームワークはPerson.idをクエリに追加しています。これは「リスト」の使用によるものと思われます。

フィルタボタンがクリックされたときに、選択したフィルタを使用してSQLステートメントを作成します。 isフィールドは必要ありませんが、削除することはできません。

ありがとう、フランク・ルーク

13
Frank Luke

そうです、DISTINCTlistと一緒に使用することはできないようです。 idは必要なく、名前だけが必要なので、上記のように_find all_を使用してから、$first_names = Set::extract($first_names, '/Person/first_name');を使用できます。これにより、個別の名を持つ配列が得られます。

19
Marko

'group by'を使用してみてください、それは完璧に機能します:

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

あなたはこれを試すことができます。ここでは、個人IDをキーとして使用するため、エントリが重複する可能性はありません。

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

これが私がCakePHP3.xでそれをした方法です:

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

SQLグループ化を使用すると、個別のリストも生成されます。マイナスの結果があるかどうかはわかりませんが、私にとってはうまくいくようです。

$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);
3
Synexis

CakePHP 1.2の質問であることは知っていますが、CakePHPバージョン3でもそれを探していました。このバージョンには、クエリを個別のクエリに形成する方法があります。

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

これにより、次のようなSQLクエリが生成されます。

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

ただし、distinctメソッドは、クエリにDISTINCTを挿入するよりも少し強力です。

1つのフィールドの結果を区別したいだけで、名前が重複している行を破棄する場合は、フィールドの配列をパラメーターとして使用して、distinctメソッドを使用することもできます。

$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'
;

これは一般的に次のようなSQLクエリになります(確かにそれはグループクエリです):

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

CakePHP3のお手伝いをさせていただきます。:)

3
TheFRedFox

現在の例では バージョン2の本 それは次のように述べています:

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')
    ));
    // ...
}

上記のコード例では、結果の変数は次のようになります。

$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',
    )

)

クエリを少し異なる方法で計画し、リスト検索に対応するようにデータベースを計画する必要があります。

2
Andrew Myers

はい、問題は、ID /値の出力用に設計されたリストを使用していることです。おそらく、find( 'all')を実行してから、自分でリストを作成する必要があります。

2
PetersenDidIt

場合によっては、いくつかのキーを使用してグループ化したいが、結果内に一意の要素が必要な場合があります。たとえば、2種類のイベントを含むカレンダーアプリケーションがあるとします。 1日目の1つのイベントと、1か月目の2日目の別のイベント。そして、すべてのイベントを日ごとおよびタイプごとにグループ化して表示またはカウントしたいとします。 DISTINCTのみを使用する場合、それは非常に困難です。最も簡単な解決策は、2回グループ化することです。

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

はい、「list」を使用して一意の結果を取得しようとしましたが、機能しません。次に、「all」を使用して問題を修正しました。

2
Muthukumaran

2.7-RCバージョンでは、これは機能しています

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

区別したいフィールドでグループ化するか、Set::extract()を使用してからarray_unique()を使用します。

1
Eric Wong