【问题标题】:Serverside Datatables finds entries marked as deleted服务器端数据表查找标记为已删除的条目
【发布时间】:2013-03-17 09:58:48
【问题描述】:

我正在使用服务器端数据表(和 CodeIgniter)来显示数据。

我不能直接从数据库中删除条目(不幸的是,该项目的指导方针),所以我正在使用已删除标志,数据库表中名为“已删除”的列(tinyint(1),因为 MySQL 自动更改它从 BOOLEAN 到那个)。

对于服务器端处理,我使用https://github.com/blake-nouribekian/codeigniter-datatables/blob/master/data.php 提供的脚本,做了一些小改动

// Columns use for SELECT part of the query. These names are not being escaped, so subqueries etc are possible.
$aColumns = array('events.id AS id', 'title', "FROM_UNIXTIME(start, '%d.%m.%Y') AS start", "FROM_UNIXTIME(start, '%H:%i') AS start_time", '(SELECT COUNT(*) FROM event_bookings WHERE id_event = events.id AND confirmed IS NOT NULL) AS participants', 'max_participants');
// Column names for WHERE clause (important for stuff like subqueries).
$aColumnNames = array('id', 'title', "start", "start", '(SELECT COUNT(*) FROM event_bookings WHERE id_event = events.id AND confirmed IS NOT NULL)', 'max_participants');
// Column for deleted flag in the DB.
$deleted_column = 'deleted';
// DB table to use
$sTable = 'events';
// no deleted entries
$this->db->where(Event_Model::$dbDeletedFlag, 0);

最初,数据显示正确,没有显示标记为已删除的条目。但是,只要我在搜索字段中输入内容,它就会找到与“... LIKE %input%”匹配的所有条目。我对 $this->db->where(Event_Model::$dbDeletedFlag, 0);命令,把它放在每一个可能的行,仍然没有改善。它显示标记为已删除的条目。当使用搜索字段时,where 命令不知何故不起作用。

有什么建议可以解决这个问题吗?

编辑:

感谢到目前为止的回答。我在这里发布整个函数:

public function server_processing() {
    // EDIT THIS
    // -----
    // Columns use for SELECT part of the query. These names are not being escaped, so subqueries etc are possible.
    $aColumns = array('events.id AS id', 'title', "FROM_UNIXTIME(start, '%d.%m.%Y') AS start", "FROM_UNIXTIME(start, '%H:%i') AS start_time", '(SELECT COUNT(*) FROM event_bookings WHERE id_event = events.id AND confirmed IS NOT NULL) AS participants', 'max_participants');
    // Column names for WHERE clause (important for stuff like subqueries).
    $aColumnNames = array('id', 'title', "start", "start", '(SELECT COUNT(*) FROM event_bookings WHERE id_event = events.id AND confirmed IS NOT NULL)', 'max_participants');
    // Column for deleted flag in the DB.
    $deleted_column = 'deleted';
    // DB table to use
    $sTable = 'events';
    // no deleted entries
    $this->db->where(Event_Model::$dbDeletedFlag, 0);
    // -------

    $iDisplayStart = $this->input->get_post('iDisplayStart', true);
    $iDisplayLength = $this->input->get_post('iDisplayLength', true);
    $iSortCol_0 = $this->input->get_post('iSortCol_0', true);
    $iSortingCols = $this->input->get_post('iSortingCols', true);
    $sSearch = $this->input->get_post('sSearch', true);
    $sEcho = $this->input->get_post('sEcho', true);

    // Paging
    if (isset($iDisplayStart) && $iDisplayLength != '-1') {
      $this->db->limit($this->db->escape_str($iDisplayLength), $this->db->escape_str($iDisplayStart));
    }

    // Ordering
    if (isset($iSortCol_0)) {
      for ($i = 0; $i < intval($iSortingCols); $i++) {
        $iSortCol = $this->input->get_post('iSortCol_' . $i, true);
        $bSortable = $this->input->get_post('bSortable_' . intval($iSortCol), true);
        $sSortDir = $this->input->get_post('sSortDir_' . $i, true);

        if ($bSortable == 'true') {
          $this->db->order_by($aColumnNames[intval($this->db->escape_str($iSortCol))], $this->db->escape_str($sSortDir));
        }
      }
    }

    /*
     * Filtering
     * NOTE this does not match the built-in DataTables filtering which does it
     * word by word on any field. It's possible to do here, but concerned about efficiency
     * on very large tables, and MySQL's regex functionality is very limited
     */
    if (isset($sSearch) && !empty($sSearch)) {
      for ($i = 0; $i < count($aColumns); $i++) {
        $bSearchable = $this->input->get_post('bSearchable_' . $i, true);

        // Individual column filtering
        if (isset($bSearchable) && $bSearchable == 'true') {
          $this->db->or_like($aColumnNames[$i], $this->db->escape_like_str($sSearch));
        }
      }
    }

    // Select Data
    $this->db->select('SQL_CALC_FOUND_ROWS ' . str_replace(' , ', ' ', implode(', ', $aColumns)), false);
    $rResult = $this->db->get($sTable);


    // Data set length after filtering
    $this->db->select('FOUND_ROWS() AS found_rows');
    $iFilteredTotal = $this->db->get()->row()->found_rows;

    // Total data set length
    $iTotal = $this->db->count_all($sTable);

    // Output
    $output = array(
        'sEcho' => intval($sEcho),
        'iTotalRecords' => $iTotal,
        'iTotalDisplayRecords' => $iFilteredTotal,
        'aaData' => array()
    );

    $output['aaData'] = array();
    foreach ($rResult->result_array() as $aRow) {
      // EDIT THIS
      // --------
      $row = array(
          '<a class="detail_link link" href="javascript:void(0);" data-event-id="' . $aRow['id'] . '">' . $aRow['title'] . '</a>',
          $aRow['start'],
          $aRow['start_time'],
          $aRow['participants'] . ' / ' . $aRow['max_participants']
      );
      if ($this->auth->access(Auth::Admin, true, false)) {
        $row[] = '<img class="edit_link" data-event-id="' . $aRow['id'] . '" src="' . base_url() . 'img/icons/glyphicons_150_edit.png"> <img class="delete_link" data-event-id="' . $aRow['id'] . '" src="' . base_url() . 'img/icons/glyphicons_192_circle_remove.png">';
      }
      // --------
      $output['aaData'][] = $row;
    }

    echo json_encode($output);
  }

感谢您的努力!

编辑 2

我认为,问题在于,当使用 Search 字段时,生成的 SQL 语句看起来像这样:

SELECT fields FROM table WHERE deleted = 0 OR field LIKE %input%

而应该是:

SELECT fields FROM table WHERE field LIKE %input% AND deleted = 0

我真的不知道,Active 记录是如何构建 SQL 语句的,以解决这个问题

【问题讨论】:

  • 您正在使用相同的查询来检索原始记录并过滤数据?我什至没有看到上面的代码 LIKE %input% 。不幸的是,从表中删除记录会破坏索引,要求重建它们并消除它们的有效性。您只需将记录标记为已删除即可。
  • 你能显示更多的控制器(或模型)代码吗?我想看看$aColumns$aColumnNames等是如何使用的,我想看看所有有效的活动记录语句。谢谢。
  • 哦,好的,所以不再从数据库中删除 :) 我编辑了帖子并提供了整个功能。
  • @PatrickManser 我根据您更新的信息重新编写了我的帖子。准备好后请查看。
  • 工作就像一个魅力!非常感谢您的帮助:)

标签: php jquery codeigniter activerecord datatables


【解决方案1】:

根据您的 cmets,问题似乎在于 Active Record 如何构建 WHERE 子句的 LIKE 片段。

if (isset($sSearch) && !empty($sSearch)) {
    // Build up the SQL manually. First, initialize SQL string.  
    // This clause will be ANDed to the other WHERE clauses; 
    // Use parentheses to isolate the OR in the inner clauses
    $sql = "("; // 
    for ($i = 0; $i < count($aColumns); $i++) {
      $bSearchable = $this->input->get_post('bSearchable_' . $i, true);

      // Individual column filtering
      if (isset($bSearchable) && $bSearchable == 'true') {
        //$this->db->or_like($aColumnNames[$i], $this->db->escape_like_str($sSearch));
        $sql_tag = ($i==0) ? "" : " OR "; // don't need OR before the first field
        $sql .= $sql_tag . $aColumnNames[$i] . " LIKE " . $this->db->escape_like_str($sSearch);
      }
    }
    $sql .= ")"; // close parentheses
    $this->db->where($sql);  // this will add to the WHERE clause using AND
}

我要做的是手动构建LIKE 子句。您需要允许多个字段可搜索。如果我的详细信息正确,您的最终查询应该类似于:

SELECT fields FROM table WHERE deleted = 0 
  AND (field1 LIKE '%input%' OR field2 LIKE '%input%' OR field3 LIKE '%input%')

假设您要搜索三个字段。

【讨论】:

  • 是的,最初是 $this->db->where($deleted_column, 0);结果相同,所以我尝试了 Event_Model::$dbDeletedFlag 。但是,实际上它们之间没有区别,它们都只是保留了“已删除”的值。对不起,忘了提这个。并且数据库中的 0 表示,它没有被删除
  • 太棒了!当您发布查询字符串时,我看到了问题所在,非常感谢您努力澄清事情。万事如意!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-20
  • 1970-01-01
  • 2015-01-09
相关资源
最近更新 更多