簡體   English   中英

PHP和MySQL-如果特定列為NULL則替換為INTO

[英]PHP and MySQL - REPLACE INTO if NULL on a specific column

我試圖使用REPLACE INTO來更改列的值,除非它為NULL。

這是代碼的一部分:

  // Set query  
  $this->db->query('REPLACE INTO sessions VALUES (:id, :access, :data, :identifier)');

  // Bind data
  $this->db->bind(':id', $id);
  $this->db->bind(':access', $access);  
  $this->db->bind(':data', $data);
  $this->db->bind(':identifier', $rnd_id);

它是PDO的一部分,因此我將沿途綁定變量以幫助防止SQL注入。

我只想在列為NULL時才替換“標識符”,但是我不確定SQL查詢應該是什么。

編輯
僅提供更多信息。 上面的當前代碼用於創建一個會話表,其中包含會話ID,上次訪問會話的時間,會話數據和唯一標識符。 該標識符最終將用於客戶端cookie。

執行查詢后,會話行將更新。 ID保持不變,訪問權限和數據已更新。 我需要一種更新id / access / data的方法,但是僅當標識符為null時才更新。

上面的代碼基於本教程: http : //culttt.com/2013/02/04/how-to-save-php-sessions-to-a-database/

我正在嘗試適應。

這是我到目前為止所擁有的一切:

database.class.php
這提供了PDO連接和功能

<?php
class Database{
    private $host      = DB_HOST;
    private $user      = DB_USER;
    private $pass      = DB_PASSWORD;
    private $dbname    = DB_NAME;
    private $stmt;

    private $dbh;
    private $error;

    public function __construct(){
        // Set DSN
        $dsn = 'mysql:host=' . $this->host . ';dbname=' . $this->dbname;
        // Set options
        $options = array(
            PDO::ATTR_PERSISTENT    => true,
            PDO::ATTR_ERRMODE       => PDO::ERRMODE_EXCEPTION
        );
        // Create a new PDO instanace
        try{
            $this->dbh = new PDO($dsn, $this->user, $this->pass, $options);
        }
        // Catch any errors
        catch(PDOException $e){
            $this->error = $e->getMessage();
        }
    }

    public function query($query){
       $this->stmt = $this->dbh->prepare($query);
    }

    public function bind($param, $value, $type = null){
       if (is_null($type)) {
           switch (true) {
               case is_int($value):
                   $type = PDO::PARAM_INT;
                   break;
               case is_bool($value):
                   $type = PDO::PARAM_BOOL;
                   break;
               case is_null($value):
                   $type = PDO::PARAM_NULL;
                   break;
               default:
                   $type = PDO::PARAM_STR;
           }
       }
       $this->stmt->bindValue($param, $value, $type);
   }

   public function execute(){
      return $this->stmt->execute();
   }

   public function resultset(){
      $this->execute();
      return $this->stmt->fetchAll(PDO::FETCH_ASSOC);
   }

   public function single(){
       $this->execute();
       return $this->stmt->fetch(PDO::FETCH_ASSOC);
   }

   public function rowCount(){
       return $this->stmt->rowCount();
   }

   public function lastInsertId(){
       return $this->dbh->lastInsertId();
   }

   public function beginTransaction(){
      return $this->dbh->beginTransaction();
   }

   public function endTransaction(){
       return $this->dbh->commit();
   }

   public function cancelTransaction(){
       return $this->dbh->rollBack();
   }

   public function close(){
       return $this->dbh=NULL;
   }
}
?>

session.php
該代碼取代了PHP默認的會話處理,並將數據保存到具有ID(會話ID),訪問(上次訪問時間)和數據(會話數據)列的會話表中。

include_once('database.class.php');


class Session {

  /**
   * Db Object
   */
  private $db;




public function __construct(){
  // Instantiate new Database object

  $this->db = new Database;

  // Set handler to overide SESSION
  session_set_save_handler(
    array($this, "_open"),
    array($this, "_close"),
    array($this, "_read"),
    array($this, "_write"),
    array($this, "_destroy"),
    array($this, "_gc")
  );

  // Start the session
  session_start();
}



/**
 * Open
 */
public function _open(){
  // If successful
  if($this->db){
    // Return True
    return true;
  }
  // Return False
  return false;
}

/**
 * Close
 */
public function _close(){
  // Close the database connection
  // If successful
  if($this->db->close()){
    // Return True
    return true;
  }
  // Return False
  return false;
}

/**
 * Read
 */
public function _read($id){
  // Set query
  $this->db->query('SELECT data FROM sessions WHERE id = :id');

  // Bind the Id
  $this->db->bind(':id', $id);

  // Attempt execution
  // If successful
  if($this->db->execute()){
    // Save returned row
    $row = $this->db->single();
    // Return the data
    return $row['data'];
  }else{
    // Return an empty string
    return '';
  }
}

/**
 * Write
 */
public function _write($id, $data){

   //set the random id length 
   $random_id_length = 10; 

   //generate a random id encrypt it and store it in $rnd_id 
   $rnd_id = crypt(uniqid(rand(),1)); 

   //to remove any slashes that might have come 
   $rnd_id = strip_tags(stripslashes($rnd_id)); 

   //Removing any . or / and reversing the string 
   $rnd_id = str_replace(".","",$rnd_id); 
   $rnd_id = strrev(str_replace("/","",$rnd_id)); 

   //finally I take the first 10 characters from the $rnd_id 
   $rnd_id = substr($rnd_id,0,$random_id_length);   


  // Create time stamp
  $access = time();

  // Set query  
  $this->db->query('REPLACE INTO sessions VALUES (:id, :access, :data, :identifier)');


  // Bind data
  $this->db->bind(':id', $id);
  $this->db->bind(':access', $access);  
  $this->db->bind(':data', $data);
  $this->db->bind(':identifier', $rnd_id);

  // Attempt Execution
  // If successful
  if($this->db->execute()){
    // Return True
    return true;
  }

  // Return False
  return false;
}

/**
 * Destroy
 */
public function _destroy($id){
  // Set query
  $this->db->query('DELETE FROM sessions WHERE id = :id');

  // Bind data
  $this->db->bind(':id', $id);

  // Attempt execution
  // If successful
  if($this->db->execute()){
    // Return True
    return true;
  }

  // Return False
  return false;
} 

/**
 * Garbage Collection
 */
public function _gc($max){
  // Calculate what is to be deemed old
  $old = time() - $max;

  // Set query
  $this->db->query('DELETE * FROM sessions WHERE access < :old');

  // Bind data
  $this->db->bind(':old', $old);

  // Attempt execution
  if($this->db->execute()){
    // Return True
    return true;
  }

  // Return False
  return false;
}
}
?>

我在表中添加了新列“標識符”。 我還向_write函數添加了$rnd_id 這將生成一個10個字符的唯一標識符。

當查詢$this->db->query('REPLACE INTO sessions VALUES (:id, :access, :data, :identifier)'); 第一次運行時,我可以在數據庫中看到新行,所有4列均按預期填充。 問題出在隨后的執行中-盡管:id保持不變,但標識符會使用新的10個字符代碼進行更新。 我想防止這種情況的發生,並且只在第一次添加代碼。 隨后的執行應保留標識符不變,或將其替換為相同的值。

您是否正在嘗試做這樣的事情?

UPDATE sessions
    set id = :id,
        access = :access,
        data = :data,
        identifier = :identifier
    where identifier is null and id = :id;

編輯:

我認為您想要的是on duplicate key update

insert into sessions(id, access, data, identifier)
    select :id, :access, :data, :identifier
    on duplicate key update access = :access, data = :data;

您需要確保id是主鍵或唯一鍵。 您可以這樣做:

create unique index idx_sessions_id on sessions(id);

您始終可以通過選擇並coalesce來更新列accessdata以及如果identifierNULL則更新identifier

replace into sessions
select :id, :access, :data, coalesce(identifier, :identifier)
from sessions
where id = :id

雖然,如果沒有給定id現有行,這會中斷。 如果需要插入值,則在沒有此類行時,如果替換失敗,則必須進行插入。

參見SQLFiddle

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM