I have a data table with 7 columns and 400 records. One of them is budget. I want to group the 400 rows by budget so that I get an array like this:
[budget]=>array(
[0]=>array(
[column1]=>'1',
[column2]=>'sand'
),
[1]=>array(
[column1]=>'2',
[column2]=>'clay'
)
)
[budget2]=>array(
[0]=>array(
[column1]=>'3',
[column2]=>'silt'
),
[1]=>array(
[column1]=>'4',
[column2]=>'stone'
)
)
So far I have been playing around with Yii's CdbCommand and CdbDataReader and PHP's PDOStatement but nothing is working right. I tried the following code
public function actionBidCostByBudget(){
$command = Yii::app()->db
->createCommand()
->Select('*')
->From('bid_cost')
# ->Query()
;
echo '<pre>';
echo get_class($command);
$pdostatement=$command->getPdoStatement();
if($pdostatement) echo get_class($pdostatement);
# print_r($statement->fetchall(PDO::FETCH_COLUMN|PDO::FETCH_GROUP));
# print_r($command->readall());
# print_r($statement->fetch());
# $columnsArray = BidCost::attributeLabels();
//print_r($rowsArray);
//$this->layout='\\layout';
}
The attempts to print_r all print out with nothing. getPdoStatement equals nothing. I have been trying to use PDO::FETCH_COLUMN|PDO::FETCH_GROUP as per the Php.net website, but it does not work either because I get nothing.
One of Yii's strengths is it's ActiveRecord, so why not use it?
Make your budget to a separate table (so you can generate a model from it). Reference it from your "datatable".
CREATE TABLE budget (
id INTEGER PRIMARY KEY,
name TEXT
);
CREATE TABLE datatable(
column1 TEXT,
column2 TEXT,
...
budget_id INTEGER,
FOREIGN KEY(budget_id) REFERENCES budget(id)
);
Next generate models with Gii, and now you can use your newly made relations like this:
$budget = Budget::model()->findByAttributes( ["name"=>"budget2"] );
foreach( $budget->datatables as $dt ) {
echo $dt->column1;
echo $dt->column2;
}
(I know. Not the array you asked for. Sorry if I'm way off with this.)
Alright, the bottom line is that I was not able to find a way to do this right thru Yii, so I did it with a more hands-on approach.
The first thing I did was basically initiate a database connection thru Yii.
$command = Yii::app()->db //outputs CDbConnnection
The next thing I did was get a PDO class from the connection:
$pdoinstance = $command->getPdoInstance(); //outputs PDO class
From this point, it was help obtained from PHP.net and another question posted on this forum:
$pdostatement=$pdoinstance->prepare('SELECT BUDGET_CODE,
PAY_ITEM, ITEM, DESCRIPTION FROM bidcost');
$pdostatement->execute();
//default fetch mode could not be set
# $pdostatement->setfetchmode(PDO::FETCH_GROUP|PDO::FETCH_ASSOC);
//returns array
$testarray=$pdostatement->fetchAll(PDO::FETCH_GROUP|PDO::FETCH_ASSOC);
Related
I have the following code to get an array of looped posts that the user has a status of 'active'.
In that array I have multiple entries for "slug" like this.
["slug"]=>string(9) "the_bbc""
I can't pull in the data based on string number - "string(9)" as they're all different.
How can I echo "the_bbc" by searching for ["slug"] and return all results.
<?php $user_id = get_current_user_id();
$active_memberships = wc_memberships_get_user_memberships( $user_id, 'active' ); // userID and active user ?>
<pre><?php var_dump ($active_memberships, $product_id); ?></pre>
Yes this looks quite novice and have been told yesterday by another person but I'm in my first year in college studying php.
Thanks
If you have multiple "slug" in an array you can loop through it with a foreach(), ex:
foreach ( $active_memberships['slug'] as $slug) {
//do whatever with this variable
}
I hope that I understood you correctly. Please provide a better description next time.
On my models I try to write a php model that will get me a associative array from a database. But I don't quite know how to approach this.
So after I execute this SQL query:
SELECT balance_events.weight,balance_events.added_date,
balance_entries.mid FROM balance_events, balance_entries
WHERE balance_entries.added_date BETWEEN '2016-08-02' AND '2016-08-03'
AND balance_entries.ptid =12
AND balance_entries.beid = balance_events.id
I will get this table:
And from that table I want to extract a asociative array that it will look like this:
count = ['13'=>1, '6'=>4, '16'=>3, '4'=>3]
where 'mid'=>number of how many times that mid can be found in the table.
ex. mid '13'=>1 cause you can found it only once.
I think that I will have to use SQL COUNT function, but how I can aggregate all of this in a PHP model in codeigniter? I know how to configure controller and view, but I don't know how to actually do the actual php model that will get me the desired array.
Try this query may help you ,
$result = $this->db->select('balance_events.weight,balance_events.added_date,COUNT(balance_entries.mid) as mid_count')
->from('balance_events, balance_entries')
->where('balance_entries.added_date BETWEEN "2016-08-02" AND "2016-08-03" ')
->where('balance_entries.ptid','12')
->where('balance_entries.beid','balance_events.id')
->group_by('balance_entries.mid')
->get();
return $result->result_array();
I'm not sure how you would create this in SQL but since you tagged php, I wrote a function that would do just this.
<?php
$query = array(array("mid"=>13), array("mid"=>2), array("mid"=>13), array("mid" =>6), array("mid" => 13), array("mid" => 6));
function createMidArray($queryResult){
$returnArray = array();
foreach ($queryResult as $qr){
$returnArray[$qr['mid']]++;
}
return $returnArray;
}
print_r(createMidArray($query));
?>
The output of this was Array ( [13] => 3 [2] => 1 [6] => 2 ) which matches up to my inputted $query (which is a 2D array). I'm expecting the output of your query is stored in a similar array, but with more data and keys
I have run into a problem I have never seen before. The code is too much and large and too many classes, so pardon me for not going into much detail.
The interesting bit is this:
$copy = clone $this;
$copy->workerid = $new_workerid;
if ( $copy->mysql_create_row( $this->pending_table ) )
return $copy;
This runs as expected. When I go into the database, I see a new entry in table Pending.
When however I run multiple queries in succession:
$copy = clone $this;
$copy->workerid = $new_workerid;
if ( $copy->mysql_create_row( $this->pending_table ) )
if ( $this->mysql_delete_row( $this->pending_table ) )
if ( $this->mysql_create_row( $this->cancelled_table ) )
return $copy;
Then for some unexplainable reason, the wrong id column is inserted at one of the tables.
In specific method $copy->mysql_create_row, among other things, does this:
if ( $con = db_connect() ) {
$res = mysqli_query( $con, "INSERT INTO $table (`workerid`,`time`,`location`,`tasks`) VALUES ('$this->workerid','$this->datetime','$this->location','$this->tasks');" )
or error_log( "mysql_create_row Error: " . mysqli_error( $con ) );
if ( $res ) {
$this->contactid = mysqli_insert_id( $con );
foreach ( $this->attendees as $att ) {
$att->__setContactId( $this->contactid );
if ( !$att->mysql_create_row( $this->attendee_table ) ) {
error_log( " Contact->mysql_create_row Error: Did not create attendee MySQL row" );
return false;
}
Delegation through object method $att->mysql_create_row( $this->attendee_table ) works the same way, it is merely an INSERT query.
Now this is where the things make no sense:
Whereas the newly inserted $copy object inserts the correct id at $copy->mysql_create_row, the $att->mysql_create_row does not !!!
It inserts the old id.
Furthermore, when I echo out the query from $att->mysql_create_row, it echoes out the correct (new id)!!!
But when I go into the actual database, it has inserted the old id. This makes absolutely no sense to me.
I have tried to create custom __clone() methods, try to make sure that I have copies and not references (damn you php) but it still produces the same error.
The problem seems to be with the successive queries, as when I do not do the delete or the new insert, I do not have any problems.
The delete works fine, and the second insertion also works fine, without any errors whatsoever.
What could possibly force the MySQLi api to insert the wrong id, while the query echoes the correct one ?
I could only thing of some form of background/multithreaded corruption, but since I have no control over this sort of thing, I do not even know how to tackle the problem.
When echoing out the query from $att->mysql_create_row, I get:
before query id: 305
'INSERT INTO XXXXXXXX.attendees
(contactid,title,forenames,surname,relationship,gender,age,arrived,left,supervised,ics_number)
VALUES ('305','Mr',
'Alex','Werner','','M','29/08/1981','0','','','0');'
after query id: 305
But when I actually go into the database, the value inserted is the old id value (say 294).
The table column is not Auto-incrementing, is not unique or primary, it is simply a int(11).
What on earth could be causing this ?
Your problem could be that you are using mysql_last_insert_id to get the id of the last inserted row. As you are inserting multiple rows, it could be possible that you don't get the correct id.
Replace mysql_last_insert_id call with a select query that returns the id of your last insertion and look if your problem is solved.
I am a little confused. I actively use PHP RedBean as ORM within my direct mail service and I run into curious situation - I have a table with unique key constraint (i.e. subscriber_id, delivery_id) and two scripts that is writing data into this table.
There is source code that is inserting or updating table:
public static function addOpenPrecedent($nSubscriberId, $nDeliveryId)
{
$oOpenStatBean = \R::findOrDispense('open_stat', 'delivery_id = :did AND subscriber_id = :sid', array(':did' => $nDeliveryId, ':sid' => $nSubscriberId));
$oOpenStatBean = array_values($oOpenStatBean);
if (1 !== count($oOpenStatBean)) {
throw new ModelOpenStatException(
"Ошибка при обновлении статистики открытий: пара (delivery_id,
subscriber_id) не является уникальной: ($nDeliveryId, $nSubscriberId).");
}
$oOpenStatBean = $oOpenStatBean[0];
if (!empty($oOpenStatBean->last_add_dt)) {
$oOpenStatBean->precedent++;
} else {
$oOpenStatBean->delivery_id = $nDeliveryId;
$oOpenStatBean->subscriber_id = $nSubscriberId;
}
$oOpenStatBean->last_add_dt = time('Y-m-d H:i:s');
\R::store($oOpenStatBean);
}
It is called both from two scripts. And I have issues with corruption unique constraint on this table periodically, because race conditions occurs. I know about SQL "INSERT on duplicate key update" feature. But how can I obtain same result purely using my ORM?
Current, that I know if, Redbean will not issue an
INSERT ON DUPLICATE KEY UPDATE
as the discussion of this cited in the comments above indicates that Redbean's developer considers upsert to be a business logic thing that would pollute the ORM's interphase. This being said, it is most likely achievable if one were to extend Redbean with a custom Query Writer or plugin per the Documentation. I haven't tried this because the method below easily achieves this behavior without messing with the internals and plugins of the ORM, however, it does require that you use transactions and models and a couple of extra queries.
Basically, start your transaction with either R::transaction() or R::begin() before your call to R::store(). Then in your "FUSE"d model, use the "update" FUSE method to run a query that checks for duplication and retrieves the existing id while locking the necessary rows (i.e. SELECT FOR UPDATE). If no id is returned, you are good and just let your regular model validation (or lack thereof) continue as usual and return. If an id is found, simply set $this->bean->id to the returned value and Redbean will UPDATE rather than INSERT. So, with a model like this:
class Model_OpenStat extends RedBean_SimpleModel{
function update(){
$sql = 'SELECT * FROM `open_stat` WHERE `delivery_id`=? AND 'subscriber_id'=? LIMIT 1 FOR UPDATE';
$args = array( $this->bean->deliver_id, $this->bean->subscriber_id );
$dupRow = R::getRow( $sql, $args );
if( is_array( $dupRow ) && isset( $dupRow['id'] ) ){
foreach( $this->bean->getProperties() as $property => $value ){
#set your criteria here for which fields
#should be from the one in the database and which should come from this copy
#this version simply takes all unset values in the current and sets them
#from the one in the database
if( !isset( $value ) && isset( $dupRow[$property] ) )
$this->bean->$property = $dupRow[$property];
}
$this->bean->id = $dupId['id']; #set id to the duplicates id
}
return true;
}
}
You would then modify the R::store() call like so:
\R::begin();
\R::store($oOpenStatBean);
\R::commit();
or
\R::transaction( function() use ( $oOpenStatBean ){ R::store( $oOpenStatBean ); } );
The transaction will cause the "FOR UPDATE" clause to lock the found row or, in the event that no row was found, to lock the places in the index where your new row will go so that you don't have concurrency issues.
Now this will not solve one user's update of the record clobbering another, but that is a whole different topic.
I would like to insert an array into a MYSQL database, preferably using Yii's active record.
For example, I have a an array:
User = array(
fname => "Joe"
lname => "Schmidt"
)
with a User table in my database with columns id, fname and lname. One of the options is creating an object and doing:
$user = new User;
$user->fname = User['fname'];
$user->lname = User['lname'];
$user->save();
However, this seems like so much code for such common functionality. Is there a way to insert an array into the database where array keys match corresponding columns without me writing my own function or doing some SQL query hack? Ideally it uses the already present Active record of Yii.
What you want to do is handled by the framework itself.
You can mass assign like:
$user->attributes=$_POST['User'];
Read more about Mass Assignment
I have never worked with Yii before, so I can't offer a solution using that, but you can serialize the array and store it in the single cell in your database, like so:
$user = array("fname" => "Joe", "lname" => "Schmidt");
$serialized = serialize($user);
//Store the $serialized variable in the database
When you are ready to access it:
//Get your data from the database
$unserialized = unserialize($usersFromDB);
$fname = $unserialized['fname']; //Joe
Hope that helps.
the function is pretty straightforward, try this:
function insert($table, $fields_values = array())
{
$q1 = join(",", array_keys($fields_values));
$q2 = "'".join("','", array_values($fields_values))."'";
$query = "INSERT INTO $table($q1) VALUES($q2)";
// do your DB insert here
}
The main trick is the array to query conversion using join and array_keys / array_values.
Depending the amount of data in array you can write you own function e.g
a) check this backUpdate , modify it to insert /remove render view option
b) Follow this thread
c) Possible traps when inserting multiple records
d) check this associated SOQ
If you know what you are doing its easy to do , you just need to take care of
validations
records exists in associated tables ( if there is FKey involved )
option d). will be a posssible answer if you have simple inserts ( with no associated tables)