Transaction rollback function not work in Codeigniter - php

when i run this code data insert in 3 tables successfully and commit when in give the error in in 3rd table insert query then data insert in 1st and 2nd table and not in 3rd table and also not RollBack function work properly. I want do when 3rd table query not work then 1st and 2nd table insert data will remove and delete.
$this->db->trans_start(TRUE);
// 1st table insert query
$this->db->insert('users',$userInfo);
$userId = $this->db->insert_id();
$query = $this->db->query("SELECT `roleId` FROM `role` WHERE roleName='Clint';");
foreach ($query->result_array() as $row)
{ $roleId = $row['roleId']; }
$user_role = array( 'user_id' => $userId, 'role_id' => $roleId );
// 2nd table insert query
$this->db->insert('user_role', $user_role);
$city_id += [ "projectInfo" => $userId ];
// 3rd table insert query
$this->db->insert('project', $projectInfo);
$this->db->trans_complete();
if ($this->db->trans_status() === FALSE )
{
echo "Flase";
$this->db->trans_rollback();
}
else
{
echo "True";
$this->db->trans_rollback();
}

You are manually rolling back transactions! In this case, you should use
$this->db->trans_begin(); NOT $this->db->trans_start();
CI automatically rolls back transactions, you dont need do it manually.
If you use $this->db->trans_start, you dont need $this->db->trans_rollback().
Comment out $this->db->trans_rollback(), or leave those and use $this->db->trans_begin(), then check results.
https://www.codeigniter.com/user_guide/database/transactions.html
Good luck!

Related

I want affected rows data and column which has affected by update query in codeigniter

Is there a way to obtain only the affected columns after an update query?
After an update query, that involves 10 columns, I know that only 2 columns are
really updated (because the values of the other cols don't change).
I need to know the names of the changed cols, for logging purpose.
$this->db->query("UPDATE `table1` SET name = $name,......................,column10=10 WHERE id=$id")->result();
$this->db->affected_rows();
This code gives number of affected rows but i want the data and updated
column information.
As far as I know there are no built-in CodeIgniter functionality for that. You could compare old value with new value though :
$last_record = $this->db->get_where('table1', array('id' => $id))->row_array();
$this->db->query("UPDATE `table1` SET name = $name,......................,column10=10 WHERE id=$id")->result();
// $this->db->affected_rows();
$new_record = $this->db->get_where('table1', array('id' => $id))->row_array();
$affected_columns = array_diff($new_record, $last_record);
foreach ($affected_columns as $field => $value) {
echo "[field] : $field\r\n";
echo "[old_value] : $last_record[$field]\r\n";
echo "[new_value] : $value\r\n";
echo "\r\n";
}
This will print each of the of the updated column with it's old-new value respectively.

How do I can skip a duplicate value before adding it to the database?

I have table with favorites programm. I will add with ajax query to database favorite programm id's to table with user id. How I can skip a duplicate programm id with current user id.
I now create this method for skip duplicate values but not working in calling:
public function test($programm_id){
$fav = new \App\Favorite;
$user_id = Auth::id();
$fav_count = $fav::where('id_user', Auth::user()->id)->count();
$getFavorites = $fav::where('id_user', $user_id)->get()->toArray();
$userProgramms = $fav->where('id_user', $user_id)->select('id_program')->get()->toArray();
$bool = true;
foreach ($userProgramms as $array) {
foreach ($array as $value) {
if($value === $programm_id) $bool = false;
}
}
if($fav_count <= 5){
if ($bool){
$fav->id_user = Auth::user()->id;
$fav->id_program = $programm_id;
$fav->save();
}
}
}
Here my table:
Please see my method favorite() in this controller: Controller
My updated code can't more 1 saves to database.
$fav = new \App\Favorite;
$fav_count = $fav::where('id_user', Auth::user()->id)->count();
if($fav_count <= 5)
{
$fav->updateOrInsert(['id_user' => Auth::id()], ['id_program' => $post['id_program']]);
}
Every user can add to table max 6 favorite id programms
Add an unique index on the table:
ALTER TABLE `tableName` ADD UNIQUE `unique_index`(`id_user`, `id_program`);
and use the INSERT INTO ... OR UPDATE:
INSERT INTO t1 (a,b,c) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE c=c+1;
UPDATE t1 SET c=c+1 WHERE a=1;
In that manner your query will insert a new record if there isn't already a record with the same couple of id_user and id_program values, in case of it it'll perform an update on that row.
If you want to do it in PHP and assuming your values are stored in an array, you can use array_unique().
Check it out here: http://php.net/manual/en/function.array-unique.php

Query using MAX

I have multiple user accounts and each of them running incremental set of integer for their own transactions.
So, everytime a user open a transaction, I will query the last max digit within his transaction and plus 1.
But, sometimes I found the result is returning the maximum ID from another user transaction. Supposedly user A has the last ID = 5402, and user Z has last ID = 19201. Sometimes, the user A gets the 19202 instead of 5403.
This is my query:
SELECT MAX(CAST(id AS UNSIGNED)) as max_id FROM `transaction` WHERE `user_id` = 'A'
The transaction table is like:
id INT PK
user_id INT
... etc
This is a web application and multiple users connect simultaneously and I'm using mysql as database, and php as the programming language.
I'm using CI, here is the code I use to obtain max ID
function get_max($table, $max_col, $col_id = NULL, $id = NULL) {
if (!empty($col_id) && !empty($id)) {
$this->db->where($col_id, $id);
}
$this->db->select("MAX(CAST($max_col AS UNSIGNED)) as max_$max_col");
$query = $this->db->get($table);
if ($query->num_rows() > 0) {
return intval($query->row_array()["max_$max_col"]);
}
return 0;
}
Once I obtained the id, I insert as below:
$new_data['id'] = $this->model_share->get_max('transaction', 'id', 'user_id', $user_id) + 1;
$new_data['user_id'] = $user_id;
$this->model_share->insert('transaction', $new_data); // save data
and this is the detail of insert function
function insert($table, $data) {
$this->db->insert($table, $data);
$id = $this->db->insert_id();
if ($id <= 0)
return $this->db->affected_rows() > 0;
else return $id;
}
Codeigniter has a query function to get max value from column from database table,$this->db->select_max()
$this->db->select_max('your_column');
$query = $this->db->get('table');
And for database transaction add this before when you start any query and end it at the last query.
$this->db->trans_start();
$this->db->query('AN SQL QUERY...');
$this->db->query('ANOTHER QUERY...');
$this->db->query('AND YET ANOTHER QUERY...');
$this->db->trans_complete();
Note: Database transaction is useful when you use it when you are doing many database related query like you are inserting something and then updating just before it.
Here is the reference link
Query_builder
Transactions
Edit:
You have a syntax error in this lines because of max_$max_col this.
//Error Line1
$this->db->select("MAX(CAST($max_col AS UNSIGNED)) as max_$max_col");
//Error Line 2
return intval($query->row_array()["max_$max_col"]);

MySQL trigger keeps adding two rows for every update

I am trying to update a 'ticketHistory' table after every update of my 'tickets' table. I have the following trigger set up to run whenever my 'tickets' table is updated (usually when a field is edited):
TRIGGER `ticket_edit` AFTER UPDATE ON `tickets` FOR EACH ROW INSERT INTO ticketHistory
(ticketId, action, originator, assigned, date)
VALUES
(NEW.ticketId, "Edited", NEW.userId, NEW.assigned, NEW.lastUpdated);
Whenever an update is done in my app, the field being edited is updated, as well as the 'lastUpdated' time. I think because two fields are being updated, it is running the trigger twice, resulting in two identical rows being inserted into my 'ticketHistory' table. I only want one row inserted.
Is there a way to limit it to just one row being inserted? Any help is greatly appreciated!
EDIT
All database inserts and updates are being done using CodeIgniter's ActiveRecord.
My model:
public function editTicket($ticket)
{
$q = $this->db->where('ticketId', $ticket['ticketId']);
$q = $this->db->update('tickets', $ticket);
$results = $this->db->affected_rows();
}
My Controller:
public function edit_ticket()
{
$ticketId = $this->uri->segment(3);
$description = str_replace("\n", "\r", $this->input->post('description'));
$ticket = array(
'ticketId' => $ticketId,
'headline' => $this->input->post('headline'),
'description' => $description,
'priority' => $this->input->post('priority'),
'category' => $this->input->post('category'),
'lastUpdated' => date("Y-m-d H:i:s", time())
);
$this->tickets->editTicket($ticket);
}
public function editTicket($ticket)
{
$q = $this->db->where('ticketId', $ticket['ticketId']);
echo "I am here again<br/>";
$q = $this->db->update('tickets', $ticket);
$results = $this->db->affected_rows();
}
I'm not sure why that's adding 2 different rows, but you could just make a primary key field and your DBMS wouldn't allow the duplicate.
Hope this helps!
So, as a solution, I modified my trigger as such:
TRIGGER `ticket_edit` AFTER UPDATE ON `tickets`
FOR EACH ROW
IF NEW.headline <> OLD.headline || NEW.description <> OLD.description || NEW.priority <> OLD.priority
THEN
INSERT INTO ticketHistory
(ticketId, action, originator, assigned, date)
VALUES
(NEW.ticketId, "Edited", NEW.userId, NEW.assigned, NEW.lastUpdated);
END IF
By adding the conditionals, I think it only activated the trigger once, resulting in only one row being inserted.
Hope this helps someone!

Is there a better way to return last inserted ID for multi insert?

I'm using PHP to add 95 new rows to my MySQL DB and return new row ID. The execution time takes around 24 seconds. If I go past 30 seconds, PHP will stop executing (default time limit 30 seconds).
I need to return the row ID for each row inserted so that I can use it to install associated data.
My current solution is this:
/* snippets from my class objects to illustrate my code */
// This foreach takes 24 seconds on just 95 rows
foreach($list as $row) {
$id = $this->importRows($sid,$table)
array_push($id_list,$id);
}
/* PDO insertion */
protected function importRows($row) {
$sql = "INSERT INTO my_table (name, colour)
VALUES $row['name'], $row['colour']";
$result = $this->db->exec($sql);
return $this->db->lastInsertId();
}
To reduce insettion time, I'm hoping I can insert multiple rows in one query
According to MySQL (scroll down to the red lind and the word IMPORTANT) it says:
If you insert multiple rows using a single INSERT statement,
LAST_INSERT_ID() returns the value generated for the first inserted
row only.
The solution they suggest is to create another table and inset the new ID's there, then I can fetch the new id's by a select statement at the end.
Has anyone worked on a similar solution? Any suggestions on how I can make thisa bit more time effective?
this is the trick I used to use in such cases:
$query = "INSERT INTO my_table (name, colour) VALUES";
$i = 0;
foreach( $rows as $row ) {
if( $i ) $query .= ',';
$query .= " ( $row[ 'name' ],
IF( #id$i := LAST_INSERT_ID(), $row[ 'colour' ], $row[ 'colour' ] ) )";
++$i;
}
$result = $this->db->exec( $query );
then have a query like this to fetch the ids:
SELECT #id1, #id2, #id3, ...
lock table
add your data using one 'insert'
unlock table
get last insert id
other id's can be computed: id[n]=last_insert_id+n, where n is number of your inserted line

Categories