insert if not exists Codeigniter - mysql

my controller:
function getFeed()
{
$feed_url = $this->input->get("url");
$content = file_get_contents($feed_url);
$x = new SimpleXmlElement($content);
foreach($x->channel->item as $entry) {
$feeds[] = array(
'title' => (string)$entry->title,
'url'=> (string)$entry->link,
'username' => $this->session->userdata('username')
);
$this->load->model('membership_model');
$this->membership_model->feeds($feeds);
}
Model:
function feeds($feeds_data)
{
$this->db->insert_batch('feeds', $feeds_data);
}
Is there a function to insert if only the row doesn't exists in the table? I have a table with 4 column : id,title,url,username. I have an anchor when i click him it calls geFeed function and insert the info into table. But i want to insert only if not exists.

I had the same challenge, so i eventually come up with a function which might be helpful to you.
function safe_update_batch($table_name,$records,$filter_field)
{
$filters=array();
foreach($records as $record)$filters[]=$record[$filter_field];
$this->db->query("SET SESSION group_concat_max_len=10000000");
$query=$this->db->select("GROUP_CONCAT($filter_field) AS existing_keys",FALSE)->where_in($filter_field, $filters)->get($table_name);
$row=$query->row();
$found_fields=explode(',',$row->existing_keys);
$insert_batch=array();
$update_batch=array();
foreach($records as $record)
{
if(in_array($record[$filter_field],$found_fields))$update_batch[]=$record;
else $insert_batch[]=$record;
}
if(!empty($insert_batch))$this->db->insert_batch($table_name,$insert_batch);
if(!empty($update_batch))$this->db->update_batch($table_name,$update_batch,$filter_field);
}
//sample usage
$this->safe_update_batch('feeds', $feeds_data,'title');

You can try this in your model!!
function insertClient($array)
{
$this->db->from('MyTable');
$this->db->where('Id', $array['Id']);
$query = $this->db->get();
if($query->num_rows() != 0){
$data = array(
'name'=>$array['name'],
'phone'=>$array['phone'],
'email'=>$array['email']
);
$this->db->where('Id', $array['Id']);
$this->db->update('CLIENTS', $data);
}else{
$data = array(
'name'=>$array['name'],
'phone'=>$array['phone'],
'email'=>$array['email']
);
$this->db->insert('CLIENTS',$data);
}
}
In controller:
$this->site_model->insertClient($_POST);

Sadly if you are using the active record class an INSERT IF NOT EXISTS function doesn't exist. You could try
Extending the active record class (easier said than done)
You could set indexes on certain columns as UNIQUE so that MySQL will check to see if it already exists
You could do some kind of SELECT before your INSERT to determine if the record is already there
For the queries where you need to do INSERT IF NOT EXISTS do $this->db->query('INSERT IF NOT EXISTS...')

function getFeed()
{
// Load the model up here - otherwise you are loading it multiple times
$this->load->model('membership_model');
$feed_url = $this->input->get("url");
$content = file_get_contents($feed_url);
$x = new SimpleXmlElement($content);
foreach($x->channel->item as $entry) {
// check if the feed is unique, if true then add to array
if( $this->membership_model->singleFeedIsUnique($entry) == TRUE ){
$feeds[] = array(
'title' => (string)$entry->title,
'url'=> (string)$entry->link,
'username' => $this->session->userdata('username')); }
} //foreach
// check to make sure we got any feeds with isset()
// if yes, then add them
if (isset($feeds)){ $this->membership_model->feeds($feeds); }
}

You can try this in your model and leave you controller without changes
function feeds($feeds_data)
{
$data = array(
title => $feeds_data[0],
url => $feeds_data[1],
username => $feeds_data[2]
);
$this->db->select('*');
$this->db->from('mytable');
$this->db->where('title',$feeds_data[0]);//you can use another field
if ($this->db->count_all_results() == 0) {
$query = $this->db->insert('mytable', $data);//insert data
} else {
$query = $this->db->update('mytable', $data, array('title'=>$feeds_data[0]));//update with the condition where title exist
}
}
you can check the id if you have it, adding in the data array and use it to check if exist

Related

Last inserted id Inside transaction with Lumen/Laravel

How can I get the last inserted id
I use the following code which works:
DB::insert("INSERT INTO members (name,email)values($name,$email)");
$lastID = DB::getPdo() -> lastInsertId();
But the following code doesn't give me the last inserted id.
DB::transaction(function () {
$result = DB::insert("INSERT INTO members (name,email)values($name,$email)");
$lastID = DB::getPdo() -> lastInsertId();
}, 5);
return $lastID;
Even when I use the variable($lastID) outside the transaction it still doesn't work.
What am I doing wrong here?
When using the query builder, Laravel has the function insertGetId which inserts the row and returns the newly created id.
$lastid = DB::table('members')->insertGetId(['name' => $name, 'email' => $email]);
Please see sample code below. Hope it helps.
public function testModel($data) {
$id = DB::transaction(function() use ($data) {
$record_id = DB::table('users')->insertGetId($data);
DB::update('update users set votes = 100 where name = ?', ['John']);
return $record_id;
});
return $id; // this will return the last inserted id which is the $record_id inside the DB::transaction
}
You can get it easily:
$last_id = DB::table('members')->insertGetId(['name => $name, 'email => $email]);
this worked for me
public function testModel($data) {
$last_id = DB::transaction(function() use ($data) {
Table::create($data);
return DB::getPdo()->lastInsertId();
});
return $last_id; // this will return the last inserted id
}
The trick should be quite simple if you use Model. Let's assume you've Member model. So when you try to insert record it returns the inserted record in response.
/** Insert record **/
$member = Member::create(['name' => $name, 'email' => $email])
/** your last inserted id will be in $member **/
$lastInsertedId = $member->id
Hope this works for you.

Save into multiple tables using stored procedure

I have 2 models: ReceivedGoodsDetail and StockInventory.
When model ReceivedGoodsDetail do actionCreate then StockInventory automatically also will be inserted into table StockInventory.
I use this stored procedure, this what I've tried:
public function actionCreate($id) {
$model = new ReceivedGoodsDetail();
$connection = \Yii::$app->db;
$transaction = $connection->beginTransaction();
$model->ID_Received_Goods = $id;
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
$connection = Yii::$app->db;
$command = $connection->createCommand('{call usp_T_Received_Goods_Detail#InsertData(:ID_Received_Goods,:ID_Item, :Qty, :User)}');
$ID_Received_Goods = $model->ID_Received_Goods;
$ID_Item = $model->ID_Item;
$Qty = $model->Qty;
$User = Yii::$app->user->identity->username;
$command->bindParam(":ID_Received_Goods",$ID_Received_Goods,PDO::PARAM_STR);
$command->bindParam(":ID_Item", $ID_Item, PDO::PARAM_STR);
$command->bindParam(":Qty", $Qty, PDO::PARAM_INT);
$command->bindParam(":User", $User, PDO::PARAM_STR);
if ($command->execute() == 0) {
$transaction->commit();
} else {
$transaction->rollBack();
foreach ($model->getErrors() as $key => $message) {
Yii::$app->session->setFlash('error', $message);
}
}
return $this->redirect(['receivedgoodsheader/view', 'id' => $model->ID_Received_Goods]);
} else {
return $this->render('create', [
'model' => $model,
]);
}
}
But I'm confused if use 2 models like the case above
Do not be afraid to do such things, here is nothing bad to use stored procedures. But in general your code is not clean and pretty confusing.
First of all, if you are using stored procedure, then why do not make a trigger for ReceivedGoodsDetail (on INSTERT)? IMHO everything will be much simpler with trigger.
Here are some remarks for your implementation.
Why do you open transaction before first if? If validation fails then your transaction will not be closed
manually.
I cant't see here using of 2 models, just one - ReceivedGoodsDetail, and StockInventory
as i can understand will be created in stored procedure usp_T_Received_Goods_Detail#InsertData?
Why do you redirect user to the item view even if transaction fails?
Using ActiveRecord. Then here is no need to start transaction manually. Just define what operations
you wish to be transactional for this model in transactions() method.
Using ActiveRecord. It is better practice to get db connection from your model class, not application.
It will be Yii::$app->db by default, but later you can easily change connection for this particular model.
It will be better for you (for example) to extend ActiveRecord (if not yet) and overload insertInternal() method
for ReceivedGoodsDetail.
In class ReceivedGoodsDetail:
public function transactions() {
return [
'default' => self::OP_INSERT
];
}
protected function insertInternal($attributeNames = null) {
if (!$this->beforeSave(true)) {
return false;
}
$values = $this->getDirtyAttributes($attributes);
/* overrided part of code */
$connection = static::getDb();
$command = $connection->createCommand('{call usp_T_Received_Goods_Detail#InsertData(:ID_Received_Goods,:ID_Item, :Qty, :User)}');
$ID_Received_Goods = $model->ID_Received_Goods;
$ID_Item = $model->ID_Item;
$Qty = $model->Qty;
$User = Yii::$app->user->identity->username;
$command->bindParam(":ID_Received_Goods",$ID_Received_Goods,PDO::PARAM_STR);
$command->bindParam(":ID_Item", $ID_Item, PDO::PARAM_STR);
$command->bindParam(":Qty", $Qty, PDO::PARAM_INT);
$command->bindParam(":User", $User, PDO::PARAM_STR);
if($command->execute() != 0) {
return false;
}
/* end of overrided part */
$changedAttributes = array_fill_keys(array_keys($values), null);
$this->setOldAttributes($values);
$this->afterSave(true, $changedAttributes);
return true;
}
In your action:
public function actionCreate($id) {
$model = new ReceivedGoodsDetail();
$model->ID_Received_Goods = $id;
if ($model->load(Yii::$app->request->post()) && $model->save(true)) {
return $this->redirect(['receivedgoodsheader/view', 'id' => $model->ID_Received_Goods]);
} else {
foreach ($model->getErrors() as $key => $message) {
Yii::$app->session->setFlash('error', $message);
}
return $this->render('create', [
'model' => $model,
]);
}
}
And then catch your flash messages on create form.
P.S. One more moment. It is strange practice to use path/to/model/{id} endpoint
with predefined ID to create new instance. Usually this looks like POST path/to/model. But this can be subject of your business logic, so i don't know if it can be improved or not
P.P.S. This example was not tested (obviously) so here can be some mistakes

how to get recently affected rows attribute in model of codeigniter

primary key of title table is id and it is an auto-increment when I insert data to the table I need to return the id of currently inserted row.
my model function is,
function addDate($x, $y, $z) {
$sql = "INSERT INTO title (title,no,user) VALUES ('$x','$y','$z')";
$query = $this->db->query($sql );
if($this->db->affected_rows() > 0) {
return "ok";
} else {
return "err";
}
}
Please help me on this.
You are wrong. In your function you are getting these three parameters ($x, $y, $z) But in code you are Inserting ('$t','$n','$a')(Question is edited)
Use $this->db->insert_id() to get last insert id
Try this
function addDate($x, $y, $z) {
$data = array(
'title' => $x ,
'no' => $y ,
'user' => $z
);
if(!$this->db->insert('title', $data)){
return FALSE ;
}
else{
$lastId = $this->db->insert_id(); # add this
return $lastId;
}
}
FYI: Don't use $x, $y, $z. use meaningful names like $title, $no, $user
Codeigniter Active Record Class Version 2.2.0

Insert Data to Database Codeigniter only if item does not exit

I'm having trouble trying to insert batch data.
All is fine with the insert_batch function but i would like to insert only the items that does not exist in database, not update it, just ignore and insert new items.
This is my Controller:
csv file:
col0,col1,col2,col3
data1,data1,data1,data1
data2,data2,data,2,data2
data3,data3,data3,data3
insert batch:
function mres($q) {
if(is_array($q))
foreach($q as $k => $v)
$q[$k] = $this->mres($v); //recursive
elseif(is_string($q))
$q = mysql_real_escape_string($q);
return $q;
}
function inserbatch(){
$csv = 'file.csv';
$arrResult = array();
$handle = fopen("uploads/csv/".$csv, "r");
if( $handle ) {
while (($row = fgetcsv($handle, 0, ",")) !== FALSE) {
$arrResult[] = array(
'col0' => $row[0],
'col1' => $row[1],
'col2' => $row[2],
'col3' => utf8_encode($row[3])
);
}
fclose($handle);
}
$final = $this->mres($arrResult);
$this->model_m->addBatch($final);
}
Model:
public function addBatch($final = array()){
if($this->db->insert_batch('mytable', $final)){
return true;
}
return false;
}
database:
id,col0,col1,col2,col3
col0 contain the unique value and if exist in csv file need to be skipped.
My question is how can i insert only the data that doesnt exist in database the col0 is the unique value and i think need to be like
if data from csv[col0] != database[col0] insert_batch.
Any help is appreciated.
Yes I think you on the right path. You only need to check your db if the value exists.
Something like this:
foreach(csv[col0] as $your_data)
{
$query = $this->db->query("SELECT * FROM my_table WHERE col0 = $your_data");
$rows = $query->num_rows();
if(!$rows)
{
// No record has been found so here you would write the code to insert the data
}
}

moving specific field value to another table before deleting the whole row

I have a table with 7 fields, when I delete a row from the table by id i want two fields of that row to be inserted into another table with just two columns.
This is my controller function
public function refund() {
$id = $this->uri->segment(4);
$accounts = $this->accounts_model->get_accounts_data_by_id($id);
foreach ($accounts as $row) {
$data = array(
'barcode' => $row->barcode,
'refunded_amount' => $row->refunded_amount,
);
}
$this->accounts_model->insert_refund($data);
$this->accounts_model->delete_accounts_data($id);
}
these are model functions
public function delete_accounts_data($id) {
$this->db->where('id', $id);
$this->db->delete('accounts');
}
public function insert_refund($data){
$this->db->insert('refund', $data);
}
Suppose this the row i will delete
id|name|barcode|refunded_amount|commission
01|asd |2342342| 53.01 | 5.32
on the other hand i will insert as
id|barcode|refunded_amount
01|2342342| 53.01
You should try and debug your code for general errors, e.g,
1) Try to set the environment to development in index.php.
2) Add some debugging code in your function to check for errors.
function refund(){
$id = $this->uri->segment(4);
$accounts = $this->accounts_model->get_accounts_data_by_id($id);
echo $this->db->last_query(); //will produce the query for fetching the details by id
if( isset( $accounts ) && count( $accounts ) > 0 ){
foreach ($accounts as $row) {
$data = array(
'barcode' => $row->barcode,
'refunded_amount' => $row->refunded_amount,
);
}
print_r( $data );
$this->accounts_model->insert_refund($data);
$this->accounts_model->delete_accounts_data($id);
}else{
echo "NO DATA FOUND";
}
}