Hi so I have an insert statement which works well, but need to create a separate update function which uses array keys and array values, which would be quite like the insert function but updates.
I have this for my insert
$sql = "INSERT INTO $tablename (".implode(",", array_keys($DATA).")" . " DATA ('".implode("','",array_values($DATA))."')";
connect()->query($sql);
This is what I have for my update so far but am stuck with it,
<?php
function updatethis (array $id, array $values, $tablename)
{
$sql = "UPDATE $tablename SET (".implode(",", array_keys($DATA)).")" . " DATA ('".implode("','",array_values($DATA))."')";
dbconnect()->query($sql);
}
?>
Therefore I would like help on the update feature please .
So I am getting an error with the UPDATE syntax
This is the part i am struggling with, i cna give further explanation, but i must have put in the wrong syntax to update the database after i click edit on the index page it calls the function just the syntax is incorrect.
also its php to mySQL
index page for PHP updatee fucntion
{
$values = array();
$idValues = array($idColumn => $id);
foreach($_POST as $key => $value)
{
if(!empty($value) && ($value != "Submit"))
{
$values[$key] = $value;
}
}
$result = update($idValues, $values, $tableName);
}
Edit: Error I am getting
edit has not been successfull from below
if(isset($_POST['Submit']))
{
if($result>0)
{
echo 'Edit has been successful. Return to index page';
}
else
{
echo 'Edit has not been successful.';
}
}
My code
function updateAll(array $id, array $values, $tablename)
{
$sIDColumn = key($id);
$sIDValue = current($id);
$arrayValues = $values;
array_walk($values, function(&$value, $key){
$value = "{$key} = '{$value}'";
});
$sUpdate = implode(", ", array_values($values));
$sql = "UPDATE {$tablename} SET {$sUpdate} WHERE {$sIDColumn} = '{$sIDValue}'";
connect()->query($sql);
}
My aim: takes the input of the unique identifier of the row to be edited as an array of 1 then the value plus the name of the column representing the primary key, an array containing the values indexed by the column names as well as a string representing the table name useing array_keys and array_vaules like th insert but to update
You cannot UPDATE in the same way of INSERT. It should be like this :
$valueSets = array();
foreach($values as $key => $value) {
$valueSets[] = $key . " = '" . $value . "'";
}
$conditionSets = array();
foreach($id as $key => $value) {
$conditionSets[] = $key . " = '" . $value . "'";
}
$sql = "UPDATE $tablename SET ". join(",",$valueSets) . " WHERE " . join(" AND ", $conditionSets);
See details here http://dev.mysql.com/doc/refman/5.7/en/update.html
I believe the pattern you are using is incorrect?
UPDATE table SET (rows) DATA ('values');
I think updates look more like this:
UPDATE table SET row1 = 'value1', row2 = 'value2';
In which case, this may be closer to what you are looking for.
function updatethis(array $id, array $values, $tablename)
{
$sIDColumn = key($id);
$sIDValue = current($id);
$arrayValues = $values;
array_walk($values, function(&$value, $key){
$value = "{$key} = '{$value}'";
});
$sUpdate = implode(", ", array_values($values));
$sql = "UPDATE {$tablename} SET {$sUpdate} WHERE {$sIDColumn} = '{$sIDValue}'";
dbconnect()->query($sql);
}
Using it, I get this query:
$testArray = array(
"id" => 19,
"username" => "test"
);
updatethis(array("id" => 9), $testArray, "users");
UPDATE users SET id = '19', username = 'test' WHERE id = '9'
I hope this at least helps but when it comes to databases, I only know MySQL and it is possible you are using another language.
I think you can try something like this :
$champs : Array of fields to update
$valeurs : Array of value to update fields
$conditions : Array of conditions
protected function modify($table,$champs,$valeurs,$conditions){
$Requete = "UPDATE ".$table." SET ";
$nbChamps = count($champs);
$nbValeurs = count($valeurs);
if($nbChamps == $nbValeurs){
for($i = 0; $i < $nbChamps ; $i++){
if($i < ($nbChamps - 1)){
if(is_numeric($valeurs[$i]))
$Requete = $Requete.$champs[$i]." = ".$valeurs[$i].",";
else
$Requete = $Requete.$champs[$i]." = '".$valeurs[$i]."',";
}
else
if(is_numeric($valeurs[$i]))
$Requete = $Requete.$champs[$i]." = ".$valeurs[$i]." ";
else
$Requete = $Requete.$champs[$i]." = '".$valeurs[$i]."' ";
}
$Requete = $Requete.$this->genereConditions($conditions);
$this->db->query($Requete);
}
else
throw new Exception("Le nombre de champs n'est pas identique au nombre de valeurs", 1);
}
private function genereConditions($conditions){
$condition = "WHERE ";
for($i = 0 ; $i < count($conditions); $i++){
if($i < (count($conditions)) - 1)
$condition = $condition.$conditions[$i]." AND ";
else
$condition = $condition.$conditions[$i];
}
return $condition;
}
Related
I have a function that should be updating a row, no errors what so ever in the logs. From what I see it should be working. I took the function from a update user function and tried to mimic it for the new feature.
Here is the data array posting to it.
$data = array('id' => $vid, 'name' => $vname, 'logo' => $vlogo, 'info' => $vinfo, 'site' => $vsite, 'est' => $vest);
The post works, I am doing a dump on the updatecompany page. So they do get set. I think it may be with the function. Any insight would be wonderful!
public static function updateCompany($toUpdate = array(), $company = null){
self::construct();
if( is_array($toUpdate) && !isset($toUpdate['id']) ){
if($company == null){
echo "No company ID set!";
}
$columns = "";
foreach($toUpdate as $k => $v){
$columns .= "`$k` = :$k, ";
}
$sql = self::$dbh->prepare("UPDATE companys SET {$columns} WHERE `id` = :id");
$sql->bindValue(":id", $company);
foreach($toUpdate as $key => $value){
$value = htmlspecialchars($value);
$sql->bindValue(":$key", $value);
}
$sql->execute();
}else{
return false;
}
}
$vid = $_POST["idnum"];
$vname = $_POST["name"];
$vlogo = $_POST["logo"];
$vinfo = $_POST["info"];
$vsite = $_POST["site"];
$vest = $_POST["est"];
I would maybe try using the bind array into your execute() method since you are just binding the values (I assume this is PDO). Another feature is to use an array to assemble the column portions and implode at the time of use.
public static function updateCompany($toUpdate = array(), $company = null)
{
# Also this may supposed to be: self::__construct(); ?? Notice the "__" before "construct"
self::construct();
if(is_array($toUpdate) && !isset($toUpdate['id'])) {
if(empty($company)){
# Throw exception, catch it in a parent wrapper
throw new \Exception("No company ID set!");
# Stop, no sense in continuing if an important part is missing
return;
}
foreach($toUpdate as $k => $v){
$bKey = ":{$k}";
# I would create a bind array here
$bind[$bKey] = $value;
# I generally save to an array here to implode later
$columns[] = "`{$k}` = {$bKey}";
}
# Add the id here
$bind[":id"] = $company;
# I would use a try here for troubleshooting PDO errors
try {
# Create sql with imploded columns
$sql = self::$dbh->prepare("UPDATE companys SET ".implode(",",$columns)." WHERE `id` = :id");
# Throw the bind array into the execute here
$sql->execute($bind);
}
catch(\PDOException $e) {
# I would only die here to see if there are any errors for troubleshooting purposes
die($e->getMessage());
}
} else {
return false;
}
}
Your update SQL could not work because you have comma in update value set.
See, you attached comma without any consideration:
$columns = "";
foreach($toUpdate as $k => $v){
$columns .= "`$k` = :$k, ";
}
Then the final SQL will look something like this:
UPDATE companys SET `name`=:name, `logo`=:logo, WHERE `id`=:id
Do you notice the comma just before WHERE? it should not be there!
So you should update the code like following:
$columns = "";
foreach($toUpdate as $k => $v){
if ($columns != "") $columns .= ",";
$columns .= "`$k` = :$k ";
}
This should be working.
or to no need to be aware of last comma try this:
$columns = array();
foreach($toUpdate as $k => $v){
$columns[] = "`$k` = :$k";
}
$sql = self::$dbh->prepare("UPDATE `companys` SET ".implode(',', $columns)." WHERE `id` = :id");
I have a CodeIgniter/PHP Model and I want to insert some data into the database.
However, I have this set in my 'raw' SQL query:
ON DUPLICATE KEY UPDATE duplicate=duplicate+1
I am using CodeIgniter and am converting all my previous in-controller SQL queries to ActiveRecord. Is there any way to do this from within the ActiveRecord-based model?
Thanks!
Jack
You can add the "ON DUPLICATE" statement without modifying any core files.
$sql = $this->db->insert_string('table', $data) . ' ON DUPLICATE KEY UPDATE duplicate=LAST_INSERT_ID(duplicate)';
$this->db->query($sql);
$id = $this->db->insert_id();
I hope it's gonna help someone.
The below process work for me in Codeigniter 3.0.6
public function updateOnDuplicate($table, $data ) {
if (empty($table) || empty($data)) return false;
$duplicate_data = array();
foreach($data AS $key => $value) {
$duplicate_data[] = sprintf("%s='%s'", $key, $value);
}
$sql = sprintf("%s ON DUPLICATE KEY UPDATE %s", $this->db->insert_string($table, $data), implode(',', $duplicate_data));
$this->db->query($sql);
return $this->db->insert_id();
}
Following the snippet linked by Pickett, I made a few modifications to:
1) Update it to use the new Query Builder (CI 3), formerly known as Active Record.
2) You can now pass an associative array (key => value) or an array of associative arrays. In the second form, it performs a multi-update.
I only tested it with mysqli, and it works well.
This piece of code goes in system/database/drivers/mysqli/mysqli_driver.php
function _duplicate_insert($table, $values)
{
$updatestr = array();
$keystr = array();
$valstr = array();
foreach($values as $key => $val)
{
$updatestr[] = $key." = ".$val;
$keystr[] = $key;
$valstr[] = $val;
}
$sql = "INSERT INTO ".$table." (".implode(', ',$keystr).") ";
$sql .= "VALUES (".implode(', ',$valstr).") ";
$sql .= "ON DUPLICATE KEY UPDATE ".implode(', ',$updatestr);
return $sql;
}
function _multi_duplicate_insert($table, $values)
{
$updatestr = array();
$keystr = array();
$valstr = null;
$entries = array();
$temp = array_keys($values);
$first = $values[$temp[0]];
foreach($first as $key => $val)
{
$updatestr[] = $key." = VALUES(".$key.")";
$keystr[] = $key;
}
foreach($values as $entry)
{
$valstr = array();
foreach($entry as $key => $val)
{
$valstr[] = $val;
}
$entries[] = '('.implode(', ', $valstr).')';
}
$sql = "INSERT INTO ".$table." (".implode(', ',$keystr).") ";
$sql .= "VALUES ".implode(', ',$entries);
$sql .= "ON DUPLICATE KEY UPDATE ".implode(', ',$updatestr);
return $sql;
}
And this goes into the /system/database/DB_query_builder.php file:
function on_duplicate($table = '', $set = NULL )
{
if ( ! is_null($set))
{
$this->set($set);
}
if (count($this->qb_set) == 0)
{
if ($this->db_debug)
{
return $this->display_error('db_must_use_set');
}
return FALSE;
}
if ($table == '')
{
if ( ! isset($this->qb_from[0]))
{
if ($this->db_debug)
{
return $this->display_error('db_must_set_table');
}
return FALSE;
}
$table = $this->qb_from[0];
}
$is_multi = false;
foreach (array_keys($set) as $k => $v) {
if ($k === $v) {
$is_multi = true; //is not assoc
break;
}
}
if($is_multi)
{
$sql = $this->_multi_duplicate_insert($this->protect_identifiers($table, TRUE, NULL, FALSE), $this->qb_set );
}
else
{
$sql = $this->_duplicate_insert($this->protect_identifiers($table, TRUE, NULL, FALSE), $this->qb_set );
}
$this->_reset_write();
return $this->query($sql);
}
Then you can do this for a single row insert/update:
$this->db->on_duplicate('table', array('column1' => 'value', 'column2' => 'value'));
Or this for a multi insert/update:
$this->db->on_duplicate('table', array(
array('column1' => 'value', 'column2' => 'value'),
array('column1' => 'value', 'column2' => 'value')
));
You can tweak the active record function with minimal addition:
DB_driver.php add inside the class:
protected $OnlyReturnQuery = false;
public function onlyReturnQuery($return = true)
{
$this->OnlyReturnQuery = $return;
}
find function query( ...and add at the very beginning:
if ($this->OnlyReturnQuery) {
$this->OnlyReturnQuery = false;
return $sql;
}
and finally in DB_active_rec.php add function:
public function insert_or_update($table='', $data=array())
{
$this->onlyReturnQuery();
$this->set($data);
$insert = $this->insert($table);
$this->onlyReturnQuery();
$this->set($data);
$update = $this->update($table);
$update = preg_replace('/UPDATE.*?SET/',' ON DUPLICATE KEY UPDATE',$update);
return $this->query($insert.$update);
}
Now you can use it as:
$this->db->insert_or_update('table',array $data);
Pros:
uses all the active record validation
Cons:
it is not the best (the most proper) way of extending the function, because if you are planning to update these files, you will have to redo the procedure.
The link to the forum thread above is broken. I don't know of a better way than just using db->query for the call, if someone has a better solution, please post that.
$result = $this->CI->db->query(
"INSERT INTO tablename (id, name, duplicate) VALUES (1, 'Joe', 1) ".
"ON DUPLICATE KEY UPDATE duplicate=duplicate+1");
I hope this helps someone looking for a solution to this.
Below is a code snippet I use everytime for update on duplicates:
$sql = "insert into table_name (id, name) values(".$id.",'".$name."') on duplicate key update id=".$id.",name='".$name."'";
//Executing queries
$result = $this->db->query($sql, array($id, $name));
Note: column id must be primary or unique
Using $this->db->query() and parameters, this is how I do it. the first 4 parameters are for the insert part and the last three parameters are repeated for the on duplicate key update part.
$sql = "insert into application_committee ".
"(application_id, member1_id, member2_id, member3_id) values (?, ?, ?, ?)".
" on duplicate key update member1_id = ?, member2_id = ?, member3_id = ?";
$this->db->query($sql, array($appid, $member_1, $member_2, $member_3,
$member_1, $member_2, $member_3);
Simply done -
$updt_str = '';
foreach ($insert_array as $k => $v) {
$updt_str = $updt_str.' '.$k.' = '.$v.',';
}
$updt_str = substr_replace($updt_str,";", -1);
$this->db->query($this->db->insert_string('table_name', $insert_array).' ON DUPLICATE KEY UPDATE '.$updt_str);
Update:
Index page is performs the action of the function,
Below is my current code, above this i have a fetch all which works well, but this insert isnt working as it doesn't insert into the database, is it because i need an update all after it before i can test insert?
<?php
function insert(array $values, $tablename)
{
$key = "";
$val = "";
foreach($values as $keys=>$record){
if($keys == ""){
$key .= $keys;
}
else{
$key .= ','.$keys;
}
if($val == ""){
$val .= $record;
insert into $tablename($keys)values($val);
}
else{
$val .= ','.$record;
insert into $tablename($keys)values($val);
}
}
}
?>
Here you have few mistakes
function insert(array $values, $tablename)
$sql = "INSERT INTO $tablename ("$vaules". implode(",", array_keys($pr1)) .") VALUES ('$vaules$, ". implode(",", array_values($pr1)) ")";
Maybe you want something like this
function insert(array $values, $tablename){
$sql = "INSERT INTO $tablename (".implode(",", array_keys($values)).") VALUES ('".implode("','",array_values($values))."')";
}
You are using some $pr1 value that do not exist in function. But also I woul like that you will do something with this query in this function.
let me to be specific.
for example you have a table employee with emp_id, emp_first_name,emp_last_name and email_id fields.
and you have array for values like this
$values = array(
emp_first_name => John,
emp_last_name => Malick,
email_id => john#gmail.com
)
now call insert function from index page using below code
first of all include file in which you placed a insert function.
for example in File1.php you placed a insert function then
include 'File1.php';
$result = insert('employee',$values);
now in insert function,
function insert($tablename,$values){
foreach($values as $keys=>$record){
$key_array[] = $keys;
$myvalue = $record;
if($record == ''){
$value_array[] = "'NULL'";
}else{
$value_array[] = "'".$myvalue."'";
}
}
$keys = implode(",", $key_array);
$values = implode(",", $value_array);
insert into $tablename($keys)values($val);
}
I want to insert an array ($array) into a Mysql table (notification), I tried this but nothing is entering. How do I solve this?
$select = "SELECT * FROM addclique WHERE adder_id = :session_id";
$param1 = array ('session_id' => $_SESSION['id']);
$cliques = $db->query($select, $param1);
foreach($cliques as $key)
{
$array[] = $key['clique_id'];
}
$array[] = $key['clique_id'];
$notijfy = new Notification();
$notijfy->addCircle($array);
function addCircle($id_involve){
$escaped_values = array_map('mysql_real_escape_string', array_values($array));
$sql2 = "INSERT INTO notification(id_involve) VALUES (:id_involve)";
$param2 = array ('id_involve' => implode(", ", $escaped_values));
$result2 = $this->db->query ($sql2, $param2);
}
There are several ways.
I would just do something simple like this:
foreach($cliques as $key){
$array[] = $key['clique_id'];
}
$notijfy = new Notification();
$notijfy->addCircle($array);
function addCircle($array){
$insert_string = '';
$count = 0;
foreach ($array as $k => $v){
$count++;
${$k} = mysqli_real_escape_string($this->db, $v);
$insert_string .= "(" . ${$k} . ")";
if ($count < sizeof($array)){
$insert_string .= ",";
}
}
$sql2 = "INSERT INTO notification(id_involve) VALUES $insert_string;";
$result2= $this->db->query ($sql2, $param2);
}
Your major error is that you are trying to pass ($passing an array when calling the function, but in the function itself your argument is listed as $id_involve, when you obviously need an $array variable that you are using in the function itself. I also can't understand why are you trying to add an element to the $array variable outside of foreach loop in the beginning. Doesn't make any sense.
Instead of $this->db just use your connection variable.
So I'm trying to create a function that generates a SQL query string based on a multi dimensional array.
Example:
function createQueryString($arrayToSelect, $table, $conditionalArray) {
$queryStr = "SELECT ".implode(", ", $arrayToSelect)." FROM ".$table." WHERE ";
$queryStr = $queryStr.implode(" AND ",$conditionalArray); /*NEED HELP HERE*/
return $queryStr;
}
$columnsToSelect = array('ID','username');
$table = 'table';
$conditions = array('lastname'=>'doe','zipcode'=>'12345');
echo createQueryString($columnsToSelect, $table, $conditions); /*will result in incorrect SQL syntax*/
as you can see I need help with the 3rd line as it's currently printing
SELECT ID, username FROM table WHERE
lastname AND zipcode
but it should be printing
SELECT ID, username FROM table WHERE
lastname = 'doe' AND zipcode = '12345'
You're not actually imploding a multidimensional array. $conditions is an associative array.
Just use a foreach loop inside your function createQueryString(). Something like this should work, note it's untested.:
$terms = count($conditionalArray);
foreach ($conditionalArray as $field => $value)
{
$terms--;
$queryStr .= $field . ' = ' . $value;
if ($terms)
{
$queryStr .= ' AND ';
}
}
Note: To prevent SQL injection, the values should be escaped and/or quoted as appropriate/necessary for the DB employed. Don't just copy and paste; think!
function implodeItem(&$item, $key) // Note the &$item
{
$item = $key . "=" . $item;
}
[...]
$conditionals = array(
"foo" => "bar"
);
array_walk($conditionals, "implodeItem");
implode(' AND ', $conditionals);
Untested, but something like this should work. This way you can also check if $item is an array and use IN for those cases.
You will have to write another function to process the $conditionalArray, i.e. processing the $key => $value and handling the types, e.g. applying quotes if they're string.
Are you just dealing with = condition? What about LIKE, <, >?
Forgive me if its not too sexy !
$data = array('name'=>'xzy',
'zip'=>'3432',
'city'=>'NYK',
'state'=>'Alaska');
$x=preg_replace('/^(.*)$/e', ' "$1=\'". $data["$1"]."\'" ',array_flip($data));
$x=implode(' AND ' , $x);
So the output will be sth like :
name='xzy' AND zip='3432' AND city='NYK' AND state='Alaska'
I'd advise against automated conditionals creation.
Your case is too local, while there can be many other operators - LIKE, IN, BETWEEN, <, > etc.
Some logic including several ANDs and ORs.
The best way is manual way.
I am always doing such things this way
if (!empty($_GET['rooms'])) $w[]="rooms='".mesc($_GET['rooms'])."'";
if (!empty($_GET['space'])) $w[]="space='".mesc($_GET['space'])."'";
if (!empty($_GET['max_price'])) $w[]="price < '".mesc($_GET['max_price'])."'";
Though if you still want it with this simple array, just iterate it using
foreach ($conditions as $fieldname => $value)...
and then combine these variables in the way you need. you have 2 options: make another array of this with field='value' pairs and then implode it, or just concatenate, and substr trailing AND at the end.
I use a variation of this:
function implode_assoc($glue,$sep,$arr)
{
if (empty($glue)) {$glue='; ';}
if (empty($sep)) {$sep=' = ';}
if (is_array($arr))
{
foreach ($arr as $k=>$v)
{
$str .= $k.$sep.$v.$glue;
}
return $str;
} else {
return false;
}
};
It's rough but works.
Here is a working version:
//use: implode_assoc($v,"="," / ")
//changed: argument order, when passing to function, and in function
//output: $_FILES array ... name=order_btn.jpg / type=image/jpeg / tmp_name=G:\wamp\tmp\phpBDC9.tmp / error=0 / size=0 /
function implode_assoc($arr,$glue,$sep){
$str = '';
if (empty($glue)) {$glue='; ';}
if (empty($sep)) {$sep=' = ';}
if (is_array($arr))
{
foreach ($arr as $key=>$value)
{
$str .= $key.$glue.$value.$sep;
}
return $str;
} else {
return false;
}
}
I know this is for the case of a pdo mysql type.. but what i do is build pdo wrapper methods, and in this case i do this function that helps to build the string, since we work with keys, there is no possible way to mysql inject, since i know the keys i define / accept manually.
imagine this data:
$data=array(
"name"=>$_GET["name"],
"email"=>$_GET["email"]
);
you defined utils methods...
public static function serialize_type($obj,$mode){
$d2="";
if($mode=="insert"){
$d2.=" (".implode(",",array_keys($obj)).") ";
$d2.=" VALUES(";
foreach ($obj as $key=>$item){$d2.=":".$key.",";}
$d2=rtrim($d2,",").")";}
if($mode=="update"){
foreach ($obj as $key=>$item){$d2.=$key."=:".$key.",";}
}
return rtrim($d2,",");
}
then the query bind array builder ( i could use direct array reference but lets simplify):
public static function bind_build($array){
$query_array=$array;
foreach ($query_array as $key => $value) { $query_array[":".$key] = $query_array[$key]; unset($query_array[$key]); } //auto prepair array for PDO
return $query_array; }
then you execute...
$query ="insert into table_x ".self::serialize_type( $data, "insert" );
$me->statement = #$me->dbh->prepare( $query );
$me->result=$me->statement->execute( self::bind_build($data) );
You could also go for an update easy with...
$query ="update table_x set ".self::serialize_type( $data, "update" )." where id=:id";
$me->statement = #$me->dbh->prepare( $query );
$data["id"]="123"; //add the id
$me->result=$me->statement->execute( self::bind_build($data) );
But the most important part here is the serialize_type function
Try this
function GeraSQL($funcao, $tabela, $chave, $valor, $campos) {
$SQL = '';
if ($funcao == 'UPDATE') :
//Formata SQL UPDATE
$SQL = "UPDATE $tabela SET ";
foreach ($campos as $campo => $valor) :
$SQL .= "$campo = '$valor', ";
endforeach;
$SQL = substr($SQL, 0, -2);
$SQL .= " WHERE $chave = '$valor' ";
elseif ($funcao == 'INSERT') :
//Formata SQL INSERT
$SQL = "INSERT INTO $tabela ";
$SQL .= "(" . implode(", ", array_keys($campos) ) . ")";
$SQL .= " VALUES ('" . implode("', '", $campos) . "')";
endif;
return $SQL;
}
//Use
$data = array('NAME' => 'JOHN', 'EMAIL' => 'J#GMAIL.COM');
GeraSQL('INSERT', 'Customers', 'CustID', 1000, $data);