Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Truy vấn cơ sở dữ liệu phức tạp trong yii2 với Active Record

tôi sẽ giả định, dựa trên câu hỏi bạn đã hỏi tại đây bạn đã thích trong các nhận xét bạn đã cung cấp toàn bộ truy vấn (không có trường nào khác mà bạn lấy ra chỉ để hiển thị mã mẫu)

do đó, nếu bạn chỉ cần các trường được chỉ định trong SELECT , bạn có thể tối ưu hóa truy vấn của mình một chút:

trước hết, bạn đang tham gia với host_machines chỉ để liên kết camerasevents , nhưng có cùng một khóa host_machines_idhost_machines trên cả hai, vì vậy điều đó không cần thiết, bạn có thể trực tiếp:

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

thứ hai, tham gia với ispy.staff , trường được sử dụng duy nhất là idreceptionist trong WHERE mệnh đề, trường đó tồn tại trong events cũng như để chúng tôi có thể bỏ nó hoàn toàn

truy vấn cuối cùng ở đây:

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)

sẽ xuất ra các bản ghi giống như bản ghi trong câu hỏi của bạn, không có bất kỳ hàng nhận dạng nào
một số video trùng lặp sẽ vẫn tồn tại do mối quan hệ từ một đến nhiều giữa camerasevents

bây giờ về phía bạn,
bạn phải xác định một số mối quan hệ trên Video mô hình

// 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 và chính chức năng tìm kiếm

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 sẽ coi mỗi video là một bản ghi duy nhất (dựa trên pk), điều đó có nghĩa là tất cả các video trùng lặp đều bị xóa. bạn sẽ có các video đơn lẻ, mỗi video có nhiều sự kiện nên bạn sẽ không thể sử dụng 'event_type''event_timestamp' trong chế độ xem nhưng bạn có thể khai báo một số cửa sổ bên trong Video mô hình để hiển thị thông tin đó:

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

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

và chế độ xem sử dụng:

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

chỉnh sửa :
nếu bạn muốn giữ video trùng lặp, hãy khai báo hai cột từ events bên trong Video mô hình

public $event_type, $event_timestamp;

giữ nguyên GridView thiết lập và thêm selectindexBy này cho truy vấn bên trong 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++);
    });

cập nhật

một nhân viên staff trực tiếp liên quan đến Video hiện hơi có vấn đề vì cách đó hơn một bảng. Có một vấn đề về nó đây

tuy nhiên, bạn thêm staff bằng cách liên kết nó với Sự kiện mô hình,

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

điều đó sẽ cho phép bạn truy vấn như sau:

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

Lọc sẽ yêu cầu một số cập nhật nhỏ trên bộ điều khiển, chế độ xem và SarchModel
đây là cách triển khai tối thiểu:

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;
    }
}

người điều khiển:

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

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

và chế độ xem

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. Lỗi kết nối MySQL trong Java - com.mysql.jdbc.Driver

  2. Cách chúng ta có thể sử dụng mysql_affected_rows () trong thủ tục được lưu trữ

  3. Tổng quan về Percona XtraDB Cluster Kubernetes Operator

  4. Đặt dữ liệu nhị phân bằng setblob trong trình kết nối mysql / c ++ gây ra lỗi

  5. Không thể tải LibreOffice:'com.mysql.jdbc.driver'