Mysql
 sql >> база данни >  >> RDS >> Mysql

Сложни заявки за база данни в yii2 с активен запис

Предполагам, въз основа на въпроса, който сте задали тук харесахте в коментари, че предоставихте цялата заявка (няма други полета, които сте извадили само за да покажете примерен код)

следователно, ако имате нужда само от полетата, посочени в SELECT изявление, можете да оптимизирате заявката си доста:

първо, вие се присъединявате с host_machines само за свързване на cameras и events , но имат същия ключ host_machines_idhost_machines и на двете, така че не е необходимо, можете директно:

    INNER JOIN events events
        ON (events.host_machines_idhost_machines =
            cameras.host_machines_idhost_machines))

второ, присъединяването с ispy.staff , единственото използвано поле е idreceptionist в WHERE клауза, това поле съществува в events също така, за да можем да го изхвърлим напълно

последната заявка тук:

SELECT videos.idvideo, videos.filelocation, events.event_type, events.event_timestamp
FROM videos videos
    INNER JOIN cameras cameras
        ON videos.cameras_idcameras = cameras.idcameras
    INNER JOIN events events
        ON events.host_machines_idhost_machines =
                cameras.host_machines_idhost_machines
WHERE     (events.staff_idreceptionist = 182)
        AND (events.event_type IN (23, 24))
        AND (events.event_timestamp BETWEEN videos.start_time
               AND videos.end_time)

трябва да изведе същите записи като този във вашия въпрос, без никакви идентични редове
някои дубликати на видео все още ще съществуват поради връзка един към много между cameras и events

сега от yii страна на нещата,
трябва да дефинирате някои отношения във Видеоклиповете модел

// this is pretty straight forward, `videos`.`cameras_idcameras` links to a 
// single camera (one-to-one)
public function getCamera(){
    return $this->hasOne(Camera::className(), ['idcameras' => 'cameras_idcameras']);
}
// link the events table using `cameras` as a pivot table (one-to-many)
public function getEvents(){
    return $this->hasMany(Event::className(), [
        // host machine of event        =>  host machine of camera (from via call)
        'host_machines_idhost_machines' => 'host_machines_idhost_machines'
    ])->via('camera');
}

VideoController и самата функция за търсене

public function actionIndex() {
    // this will be the query used to create the ActiveDataProvider
    $query =Video::find()
        ->joinWith(['camera', 'events'], true, 'INNER JOIN')
        ->where(['event_type' => [23, 24], 'staff_idreceptionist' => 182])
        ->andWhere('event_timestamp BETWEEN videos.start_time AND videos.end_time');

    $dataProvider = new ActiveDataProvider([
        'query' =>  $query,
    ]);

    return $this->render('index', [
        'dataProvider' => $dataProvider,
    ]);
}

yii ще третира всеки видеоклип като единичен запис (въз основа на pk), което означава, че всички дубликати на видео са премахнати. ще имате единични видеоклипове, всеки с множество събития, така че няма да можете да използвате 'event_type' и 'event_timestamp' в изгледа, но можете да декларирате някои гетери във Video модел, за да покаже тази информация:

public function getEventTypes(){
    return implode(', ', ArrayHelper::getColumn($this->events, 'event_type'));
}

public function getEventTimestamps(){
    return implode(', ', ArrayHelper::getColumn($this->events, 'event_timestamp'));
}

и изгледът използва:

<?= GridView::widget([
    'dataProvider' => $dataProvider,
    'columns' => [
        ['class' => 'yii\grid\SerialColumn'],
        'idvideo',
        'eventTypes',
        'eventTimestamps',
        'filelocation',
        //['class' => 'yii\grid\ActionColumn'],
    ],
]); ?>

редактиране :
ако искате да запазите дубликатите на видеоклипа, декларирайте двете колони от events вътре Видео модел

public $event_type, $event_timestamp;

запазете оригиналния GridView настройка и добавете select и indexBy това към заявката във VideoController :

$q  = Video::find()
    // spcify fields
    ->addSelect(['videos.idvideo', 'videos.filelocation', 'events.event_type', 'events.event_timestamp'])
    ->joinWith(['camera', 'events'], true, 'INNER JOIN')
    ->where(['event_type' => [23, 24], 'staff_idreceptionist' => 182])
    ->andWhere('event_timestamp BETWEEN videos.start_time AND videos.end_time')
    // force yii to treat each row as distinct
    ->indexBy(function () {
        static $count;
        return ($count++);
    });

актуализация

директен staff във връзка с Video в момента е малко проблематичен, тъй като е на повече от една таблица от него. има проблем за него тук

обаче добавяте staff таблица, като я свържете сСъбитието модел,

public function getStaff() {
    return $this->hasOne(Staff::className(), ['idreceptionist' => 'staff_idreceptionist']);
}

което ще ви позволи да правите заявки по следния начин:

->joinWith(['camera', 'events', 'events.staff'], true, 'INNER JOIN')

Филтриране ще изисква някои малки актуализации на контролера, изгледа и SarchModel
ето минимална реализация:

class VideoSearch extends Video
{
    public $eventType;
    public $eventTimestamp;
    public $username;

    public function rules() {
        return array_merge(parent::rules(), [
            [['eventType', 'eventTimestamp', 'username'], 'safe']
        ]);
    }

    public function search($params) {
        // add/adjust only conditions that ALWAYS apply here:
        $q = parent::find()
            ->joinWith(['camera', 'events', 'events.staff'], true, 'INNER JOIN')
            ->where([
                'event_type' => [23, 24],
                // 'staff_idreceptionist' => 182
                // im guessing this would be the username we want to filter by
            ])
            ->andWhere('event_timestamp BETWEEN videos.start_time AND videos.end_time');

        $dataProvider = new ActiveDataProvider(['query' => $q]);

        if (!$this->validate())
            return $dataProvider;

        $this->load($params);

        $q->andFilterWhere([
            'idvideo'                => $this->idvideo,
            'events.event_type'      => $this->eventType,
            'events.event_timestamp' => $this->eventTimestamp,
            'staff.username'         => $this->username,
        ]);

        return $dataProvider;
    }
}

контролер:

public function actionIndex() {
    $searchModel = new VideoSearch();
    $dataProvider = $searchModel->search(Yii::$app->request->queryParams);

    return $this->render('test', [
        'searchModel'  => $searchModel,
        'dataProvider' => $dataProvider,
    ]);
}

и изглед

use yii\grid\GridView;
use yii\helpers\ArrayHelper;

echo GridView::widget([
    'dataProvider' => $dataProvider,
    'filterModel'  => $searchModel,
    'columns'      => [
        ['class' => 'yii\grid\SerialColumn'],
        'idvideo',
        'filelocation',
        [
            'attribute' => 'eventType',     // from VideoSearch::$eventType (this is the one you filter by)
            'value'     => 'eventTypes'     // from Video::getEventTypes() that i suggested yesterday
            // in hindsight, this could have been named better, like Video::formatEventTypes or smth
        ],
        [
            'attribute' => 'eventTimestamp',
            'value'     => 'eventTimestamps'
        ],
        [
            'attribute' => 'username',
            'value'     => function($video){
                return implode(', ', ArrayHelper::map($video->events, 'idevent', 'staff.username'));
            }
        ],
        //['class' => 'yii\grid\ActionColumn'],
    ],
]);


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как да се обърна към OSError:грешка mysql_config не е намерена по време на внедряването на Elastic Beanstalk?

  2. ИЗТРИВАНЕ ОТ БРОЙ (*) в MySQL

  3. Как да използвам .format() низ в MySQL оператор?

  4. Дължина на индекса на MySQL varchar

  5. Как да получите записи за последните 15 дни в MySQL