So I have two arrays that I need to update and set with in MySQL. item_id [1,2,3] and item_order[2,1,3]
Here is the items table before the array insert:
item_id item_order
1 1 //should become 2
2 2 // should become 1
3 3 // should become 3
The arrays should be in pairs for the insert, 1-2, 2-1, 3-3.
How can I do this with a prepared statement efficiently and how can I test if the array items are indeed numbers?
Assuming you have input like this:
$item_id = array(1, 2, 3);
$item_order = array(2, 1, 3);
// and a PDO connection named $pdo
You can try something like this. (I'm also assuming you have PDO configured to throw exceptions when problems arise).
function all_numbers($input) {
foreach($input as $o) {
if(!is_numeric($o)) {
return false;
}
}
return true;
}
if(count($item_id) != count($item_order)) {
throw new Exception("Input size mismatch!");
}
if(!all_numbers($item_id) || !all_numbers($item_order)) {
throw new Exception("Invalid input format!");
}
$pairs = array_combine($item_id, $item_order);
// now $pairs will be an array(1 => 2, 2 => 1, 3 => 3);
if($pdo->beginTransaction()) {
try {
$stmt = $pdo->prepare('UPDATE `items` SET `item_order` = :order WHERE `item_id` = :id');
foreach($pairs as $id => $order) {
$stmt->execute(array(
':id' => $id,
':order' => $order,
));
}
$pdo->commit();
} catch (Exception $E) {
$tx->rollback();
throw $E;
}
} else {
throw new Exception("PDO transaction failed: " . print_r($pdo->errorInfo(), true));
}
But it might be better to redesign your input - only pass the item_ids in the desired order and compute their item_order values automatically.
Here is an example:
UPDATE mytable
SET myfield = CASE other_field
WHEN 1 THEN 'value'
WHEN 2 THEN 'value'
WHEN 3 THEN 'value'
END
WHERE id IN (1,2,3)
Related
I try to select count and group with Laravel query, but they are return same value with different field.
This is my code:
$kategoris = ['NUK', 'Hubkel', 'Sta_kawin'];
foreach ($kategoris as $kategori) {
$raw[] = 'count('.$kategori.') as '.$kategori;
}
$implodeRaw = implode(', ', $raw);
$desas = DB::table('arts')
->select('arts.id', 'KDKEC', 'KDDESA', DB::raw($implodeRaw))
->where(['KDKEC' => $kodeKecamatan])
->groupBy('KDDESA')
->orderBy('KDDESA', 'ASC')
->get();
Result:
results: {
0 => {
'id': 10
'NUK': 6
'Hubkel': 6
'Sta_kawin': 6
}
1 => {
'id': 13
'NUK': 1
'Hubkel': 1
'Sta_kawin': 1
}
}
So, what's wrong with this code? I want the NUK, Hubkel, Sta_kawin return different value because the source data is different.
I have 2 tables :
Product Option Group
id | opt_name | active_flag
------------------------------
1 | Cook level | 0
Product Option List
id | optgrp_id | list_name | active_flag
------------------------------------------
1 | 1 | 25 | 0
2 | 1 | 50 | 1
3 | 1 | 75 | 0
4 | 1 | 100 | 0
Product Option Group Model
public function getOptList()
{
return $this->hasMany(ProdOptlist::className(),['optgrp_id'=>'id']);
}
Product Option List Model
public function getOptGrp()
{
return $this->hasOne(ProdOptgrp::className(),['id'=>'optgrp_id']);
}
Product Option Group Controller
public function actionUpdate($id)
{
$model = $this->findModel($id);
if($model->load(Yii::$app->request->post()) && $model->validate())
{
...
}
else
return $this->render('update', ['model'=>$model]);
}
protected function findModel($id)
{
if (($model = ProdOptgrp::find()
->joinWith('optList')
->where([ProdOptgrp::tableName().'.id'=>$id,
ProdOptgrp::tableName().'.active_flag'=>0,
ProdOptlist::tableName().'.active_flag'=>0])
->one()) !== null) {
return $model;
}
throw new NotFoundHttpException('The requested page does not exist.');
}
Update View
Expected output for print_r($model->optList) :
{
[id] => 1
[optgrp_id] => 1
[list_name] => 25
[active_flag] => 0
},
{
[id] => 3
[optgrp_id] => 1
[list_name] => 75
[active_flag] => 0
},
{
[id] => 4
[optgrp_id] => 1
[optList_name] => 100
[active_flag] => 0
}
Actual output :
{
[id] => 1
[optgrp_id] => 1
[list_name] => 25
[active_flag] => 0
},
{
[id] => 2
[optgrp_id] => 1
[list_name] => 50
[active_flag] => 1
},
{
[id] => 3
[optgrp_id] => 1
[list_name] => 75
[active_flag] => 0
},
{
[id] => 4
[optgrp_id] => 1
[optList_name] => 100
[active_flag] => 0
}
Yii2 debugger showing correct query but output still consist of all 4 elements.
Kindly advice if there is any mistake, thank you in advance :)
Even if you use the joinWith() the where() part of your $model = ProdOptgrp::find()... code only limits the result that is returned by the query executed by one() method call. It doesn't affect what is loaded for relations.
If you want to limit what is loaded for relations you can do it:
1) By modifing the existing relation
This is the solution you've come to. You add the where condition directly to the getOptList() method of your ProdOptgrp model. If you do it this way, the $model->optList will always return filtered relation. Depending on case that might be advantage or disadvantage.
2) By adding second relation
You can create another method in your ProdOptgrp model that will define the filtered relation while keeping the original getOptList() unfiltered.
For example like this:
class ProdOptgrp extends \yii\db\ActiveRecord
{
public function getOptList()
{
return $this->hasMany(ProdOptlist::className(),['optgrp_id'=>'id']);
}
public function getFilteredOptList()
{
return $this->getOptList()->where([
ProdOptlist::tableName() . '.active_flag' => 0
]);
}
}
In this case the $model->optList will still contain unfiltered OptLists and the $model->filteredOptList will contain filtered. This solution is good when you need to use both at different spots of your application.
3) By using callback syntax in joinWith() or with()
In case you want to filter the relation only in one particular case you don't need to modify your model. You can modify the relation with callback that is called before loading the data.
$model = ProdOptgrp::find()
->joinWith([
'optList' => function(\yii\db\ActiveQuery $query) {
$query->where([
ProdOptlist::tableName() . '.active_flag' => 0
]);
}
])->where([
ProdOptgrp::tableName().'.id'=>$id,
ProdOptgrp::tableName().'.active_flag'=>0,
ProdOptlist::tableName() . '.active_flag'=>0,
])->one();
The last condition in where() will cause the $model to be null when the active_flag is 0 in optgrp table but 1 in all related records in optlist table. I'm not sure if that is inteded behavior.
You can do it this way too:
//Controller
protected function findModel($id)
{
if (($model = ProdOptgrp::findOne($id)) !== null && $model->isActive()) {
return $model;
}
throw new NotFoundHttpException('The requested page does not exist.');
}
//Model
/*
*Check if model is active
*/
public function isActive(){
return ($this->active_flag == 0) ? true: false;
}
public function getOptList()
{
return $this->hasMany(ProdOptlist::className(),['optgrp_id'=>'id'])->where([ProdOptgrp::tableName().'.active_flag'=>0]);
}
//View
foreach($model->optList as optItem): // you get filtered result
Hi guys I have a problem in my query in model, I'll show you the code before I explain it.
for($x = 1; $x <= count($this->input->post('subparticulars')); $x++) {
$feetype = $this->input->post('subparticulars')[$x];
$student = $this->input->post('substudentid');
$schoolyear = $this->input->post('subschoolyeardata');
$month = $this->input->post('month');
$payment = $this->input->post('subpaymentamount')[$x];
$this->db->set('statement_amount', '`statement_amount` -'. $payment, FALSE);
$this->db->where(array('feetype_id !=' => 2, 'feetype_id !=' => 3, 'feetype_id' => $feetype, 'student_id' => $student, 'schoolyear_id' => $schoolyear, 'month_id' => $month));
$status3 = $this->db->update('tbl_statement');
}
Here I have an add dynamic add row function which has contains the amounts and particulars of multiple payment in subparticulars and subpayments, I'm running a query that will minus my payments in my statement_amounts, as you can see in the $this->db->set. Now, I have a problem with my where clause, if you will try to understand my where clause this is the conditions.
I want to update all my fees except the one that has the feetype_id: 2 and 3, but the other feetype_id will be updated, How can I achieve this. When I'm running the code it still subtracts the fees that have feetype_id of 2 and 3.
Here's the correct answer
for($x = 1; $x <= count($this->input->post('subparticulars')); $x++) {
$feetype = $this->input->post('subparticulars')[$x];
$student = $this->input->post('substudentid');
$schoolyear = $this->input->post('subschoolyeardata');
$month = $this->input->post('month');
$payment = $this->input->post('subpaymentamount')[$x];
if ($feetype == 2 OR $feetype == 3)
{
$this->db->set('statement_amount', '`statement_amount` -'. $payment, FALSE);
$this->db->where(array('feetype_id' => $feetype, 'student_id' => $student, 'schoolyear_id' => $schoolyear));
$status3 = $this->db->update('tbl_statement');
}
else {
$this->db->set('statement_amount', '`statement_amount` -'. $payment, FALSE);
$this->db->where(array('feetype_id' => $feetype, 'student_id' => $student, 'schoolyear_id' => $schoolyear, 'month_id' => $month));
$status3 = $this->db->update('tbl_statement');
}
}
I have a table of:
id title type expl bubble_content onfocus req dorder label mirror
1 Fullname 1 1 Your fullname Yes 0 0 0 NULL
Then another table of:
id fieldid relid dorder
4 1 2 0
5 1 1 0
How would I join the two tables so that the result would be something like:
0 => array(
'id' => 1,
'title' => 'Fullname',
.... etc ....
'relid' => 2,
'relid' => 1),
1 => array(
.... etc ....
))
I've tried using INNER JOIN / LEFT JOIN but this produces two rows/arrays for each relid, I would really like all the data for the particular fieldid to exist within the same array, as illustrated above.
You can't have 2 keys with the same name in an array. On your example you have 2 'relid', the second one will overwrite the first.
You can code PHP so that it merges those rows into one:
$output = array();
while ($row = mysql_fetch_assoc($result))
{
// Capture all values for this row first.
// If this is the new row from the first table, store.
if (!isset($output[$row['id']]))
{
$output[$row['id']] = $row;
// Make a new array for relids.
$output[$row['id']]['relids'] = array();
}
$output[$row['id']]['relids'][] = $row['relid'];
}
Your output array will look like this:
0 => array(
'id' => 1,
'title' => 'Fullname',
.... etc ....
'relids' => array(2, 1),
1 => array(
.... etc ....
))
I'm using the following statement to insert data in mysql with codeigniter.
$this->db->insert_batch($table, $query);
$query is generated dynamically can have different number of columns on each array element
and maybe the number of elements may differ on condition
array (
0 => array(
'column1'=>'insert1',
'column2'=>'insert2'
),
1 => array(
'column1'=>'insert1';
'column2'=>'insert2',
'column4'=>'insert4'
)
)
could this cause an error or handles codigniter from deafult?
I'm building up the query as it follows
foreach ($sql_xml as $children) {
$children = $this->xml2array($children);
foreach ($children as $index => $child) {
if ($child != 'feed_id') {
$keys[$index] = $child;
}
}
}
switch (strtolower($this->config[0]->affiliate)) {
case 'case1':
$target_xml = $target_xml->productItems;
break;
case 'case2':
$target_xml = $target_xml;
break;
default :
break;
}
$query = array();
$data = array();
foreach ($target_xml as $feeds) {
$feeds = $this->xml2array($feeds);
$columns = new RecursiveIteratorIterator(new RecursiveArrayIterator($feeds));
foreach ($columns as $index => $column) {
if (array_key_exists($index, $keys)) {
if($column != ''){
$data[$keys[$index]] = $column;
$data['feed_id'] = $this->id;
}
//*TODO //$data['affiliate'] = "'.$this->config[0]->affiliate.'";
}
}
$query[] = $data;
}
if (count($query > 0)) {
foreach ($query as $t){
$this->db->insert($table, $t);
}
}
The array's would need to have the same amount of "columns".
So what I would recommend is the following (setting certain columns to null if no there is no data):
array (
0 => array(
'column1' => 'insert1',
'column2' => 'insert2',
'column3' => null,
'column4' => null
),
1 => array(
'column1' => 'insert1',
'column2' => 'insert2',
'column3' => 'insert3',
'column4' => 'insert4'
)
)
Also, your syntax is invalid and it would cause an error since you are using a ; instead of an , on the first column insert.