how to retrieve a table with many tables with PDO - php

Recently I've been using PDO
and I'd like to get a table with hasmany related table.
I can get a table with the tables like this
array (
0 =>
stdClass::__set_state(array(
'order_id' => '170',
'purchase_id' => '222',
'product_option_id' => '014',
)),
1 =>
stdClass::__set_state(array(
'order_id' => '170',
'purchase_id' => '600',
'product_option_id' => '015',
)),
)
with SQL query like this
SELECT ord.order_id,puc.purchase_id,puc.product_option_id
FROM order ord
JOIN purchase puc
ON ord.order_id = puc.order_id
WHERE ord.order_id = '170'
However I'd like to get this data like this
array (
0 =>
array(
'order_id' => '170',
'purchase_id' => '222',
'purchase' => array(
0 =>
array(
'purchase_id' => '222',
'product_option_id' => '014',
),
1 =>
array(
'purchase_id' => '600',
'product_option_id' => '015',
),
)
)
)
How do get the data like this with PDO?
Thank you

Luckily, you CAN have it with PDO.
Were you need anything but id from orders, the mission were impossible.
But as long as you need only unique value from orders, you can get the thing like this
array (
170 =>
array(
0 =>
array(
'purchase_id' => '222',
'product_option_id' => '014',
),
1 =>
array(
'purchase_id' => '600',
'product_option_id' => '015',
),
)
)
)
with as simple code as
$sql = "your sql";
$pdo->query($sql)->fetchAll(PDO::FETCH_GROUP);
However, I see very little sense in fetching the same order ID usedto filter the data. May be it should be some other query that is closer to your real needs? Like one that is fetching several orders?

You can't get it like this with PDO, but you can rearrange the results. A possible way to do it would be to use the array_reduce function.
$orders = array_reduce($results, function ($carry, $item) {
if (!isset($carry[$item->order_id])) {
$carry[$item->order_id] = array(
'order_id' => $item->order_id,
'purchase' => array(array(
'purchase_id' => $item->purchase_id,
'product_option_id' => $item->product_option_id,
));
);
} else {
$carry[$item->order_id]['purchase'][] = array(
'purchase_id' => $item->purchase_id,
'product_option_id' => $item->product_option_id,
);
}
return $carry;
}, array());

Related

php insert key/value into associative array

I'm trying to insert a couple of new Key/Value pairs into an associative array at a specific place. From other reading I've done on SO, I'm pretty sure I have to loop through the array and insert the new values when a condition is set.
Here is the current array
array(
(int) 0 => array(
'Product' => array(
'id' => '59',
'title' => ' Blue Dress',
'Review' => array(
'id' => '7',
'product_id' => '59',
'Review' => array(
(int) 0 => array(
'average' => '3.0000'
)
)
)
)
)
(int) 1 => array(
'Product' => array(
'id' => '60',
'title' => 'Red Dress',
'Review' => array()
)
)
)
The key Review does not always have data, but when it does I want to insert a new key-value similar to the following excerpt
(int) 0 => array(
'Product' => array(
'id' => '59',
'title' => ' Blue Dress',
'Review' => array(
'id' => '7',
'product_id' => '59',
'Review' => array(
(int) 0 => array(
'average' => '3.0000'
'some_value' => '5'
)
)
)
)
)
I've tried a few things without success.
Any help is much appreciated thanks.
You can do something like this:
if(!empty($your_array[index]['Product']['Review'])){
$your_array[index]['Product']['Review']['Review'][index]['some_value'] = 'new_value';
}
In your example it could be:
if(!empty($your_array[0]['Product']['Review'])){
$your_array[0]['Product']['Review']['Review'][0]['some_value'] = 'new_value';
}
Again, you didn't mention your code. So, it's hard to figure out what you want exactly!
You should iterate through Your array and pass current value be reference:
// Notice & sign before variable
foreach ($data as &$product)
{
if ($product['Product']['Review'])
{
// or iterate through Review array
$product['Product']['Review']['Review'][0]['some_value'] = 5;
}
}

CakePHP return find('all') using 'id' as array Index

So I'm trying to return a find 'all' array using the id of a 'Product' as the index key for each Product.
Typically it returns:
array(
(int) 0 => array(
'Product' => array(
'id' => '1232',
'category_id' => '330',
'name' => 'Product #1',
)
),
(int) 1 => array(
'Product' => array(
'id' => '1245',
'category_id' => '310',
'name' => 'Product #2',
)
),
(int) 2 => array(
'Product' => array(
'id' => '1248',
'category_id' => '312',
'name' => 'Product #3',
)
)
)
Whereas ideally I'd like it to return:
array(
(int) 1232 => array(
'Product' => array(
'id' => '1232',
'category_id' => '330',
'name' => 'Product #1',
)
),
(int) 1245 => array(
'Product' => array(
'id' => '1245',
'category_id' => '310',
'name' => 'Product #2',
)
),
(int) 1248 => array(
'Product' => array(
'id' => '1248',
'category_id' => '312',
'name' => 'Product #3',
)
)
)
Is this possible? And how do I go about doing it?
I have an excel spreadsheet of records that I need to match ID's to, so currently I have it iterating each spreadsheet row and performing a 'first' find to get any results, then act upon them if they do.
It works, but the recordset has grown to over 28000 and so performing one find for each has noticeable overhead.
If I can do this simply in the 'find' operation it would be great, if not, any noticeable increase in performance would be appreciated.
You can get this result as after find all :
$result = Hash::combine($data, '{n}.Product.id', '{n}.Product');
Where $data is the result of find all.
You can have your find method extended in AppModel like this
public function find($type = 'first', $query = array()) {
switch($type) {
case 'keysid':
if($results = parent::find('all', $query)){
if(isset($results[0][$this->alias]['id'])){
return Hash::combine($results, '{n}.'.$this->alias.'.id', '{n}');
}else{
return $results;
}
}
break;
default:
return parent::find($type, $query);
break;
}
}
And afterwards you can call your find method as follows:
$this->Product->find('keysid');
Then you will have a result array as you specified. However you can also do this with one line of code if you need it once. Say $products is your array from the find('all')
if($products = $this->Product->find('all')){
$alteredProducts = Hash::combine($products, '{n}.Product.id', '{n}');
}
Have a look at the Hash utility

Push array inside another array

I have a site develop in php and I have a function where I want to create an array inside other array.
My query are this (i'm using cakephp but in this case is only a problem of array don't tell me to use contain or something like that from cakephp because is a large query and I need to construct my query and my array in this mode)
My array $product_ingredient contain some value.
foreach ($product_ingredient as $key) {
$ingredient_level1 = $this->ProductIngredientVersion->query('SELECT * FROM ingredients_ingredients
WHERE ingredients_ingredients.ingredient_id = :ingredient_id
AND ingredients_ingredients.product_id = :id
AND ingredients_ingredients.version_id = :version_id
AND ingredients_ingredients.level = 1', array('id' => $id, 'ingredient_id' => $key['products_ingredients']['ingredient_id'], 'version_id' => $key['products_ingredients']['version_id']));
foreach($ingredient_level1 as $key2){
$ingredient_level2 = array($this->ProductIngredientVersion->query('SELECT * FROM ingredients_ingredients
WHERE ingredients_ingredients.ingredient_id = :ingredient_id
AND ingredients_ingredients.product_id = :id
AND ingredients_ingredients.version_id = :version_id
AND ingredients_ingredients.level = 2', array('id' => $id, 'ingredient_id' => $key2['ingredients_ingredients']['ingredient2_id'], 'version_id' => $key2['ingredients_ingredients']['version_id'])));
array_push($ingredient_level1, $ingredient_level2);
}
array_push($ingredient_ingredient, $ingredient_level1);
}
The result is that:
array(
(int) 0 => array(
(int) 0 => array(
'ingredients_ingredients' => array(
'id' => '34',
'level' => '1'
)
),
(int) 1 => array(
(int) 0 => array(
(int) 0 => array(
'ingredients_ingredients' => array(
'id' => '35',
'level' => '2'
)
)
)
)
)
But I would like this result
array(
(int) 0 => array(
(int) 0 => array(
'ingredients_ingredients' => array(
'id' => '34',
'level' => '1',
array(
'ingredients_ingredients' => array(
'id' => '35',
'level' => '2'
)
)
)
)
How can I solve?
Replace
array_push($ingredient_ingredient, $ingredient_level1);
by
array_push(
$ingredient_ingredient[0][0]['ingredients_ingredients'],
$ingredient_level1
);
This pushes the array to the appropriate cascade level. However it is very likely that this is the most efficient way, if you're unable to modify SQL or array structure elsewhere.

Lithium framework multiple 'or' statements in a query (using mongoDB)

I have started work with lithium framework + mongoDB recently. I want to do a really simple query which contains multiple or statements.
I have articles in the DB with publish_up and publish_down fields. I want to fetch only those records/documents which pulbis_down field is highert than now OR null AND publish_up field lower than now OR null.
$items = $article::find('all', array(
'conditions' => array(
'$or' => array(
'$gt' => array('publish_down', $mongoDateNow),
'publish_down' => $mongDateNull
),
'$or' => array(
'$lt' => array('publish_up', $mongoDateNow),
'publish_up' => $mongDateNull
),
)
));
Of course this snippet is wrong hence the second or statement overwrites the first one (because the same array key).
I tried to wrap them into an individual array but gives error.
Any idea?
This query will fetch articles with (publish_down > now OR publish_down = null) AND (publish_up < now OR publish_up = null)
$items = Articles::find('all', array(
'conditions' => array(
'$or' => array(
array('publish_down' => array('$gt' => $mongoDateNow)),
array('publish_down' => null)
),
'$or' => array(
array('publish_up' => array('$lt' => $mongoDateNow)),
array('publish_up' => null)
),
)
));
I don't know about lithium but in PHP you can use multiple $OR as below
$items = $article::find('all', array(
'conditions' => array(
'$or' => array(
array(
'$gt' => array('publish_down', $mongoDateNow),
'publish_down' => $mongDateNull
),
array(
'$lt' => array('publish_up', $mongoDateNow),
'publish_up' => $mongDateNull
)
),
)
));
I think the correct answer is:
'$and' => array(
array(
'$or'=>array(
array('publish_up' => null),
array('publish_up' => array('$lt' => $mongoDateNow))
)
),
array(
'$or'=>array(
array('publish_down' => null),
array('publish_down' => array('$gt' => $mongoDateNow))
)
)
)

SQL select from three Tables and save in PHP array

I am working on a web application and would like to improve my code a little bit.
This is the SQL table structure I made for the application:
Now my question: Is there an easy way in PHP to select (with join or whatever?) the information from one specific event_id on all tables and save them in an array with followed structure for example:
$events = array(
'event_id' => 1,
'event_name' => '{"de":"Weltwirtschaftsforum","fr":"Forum \u00e9conomique mondial","it":"Forum Economico Mondiale"}',
'event_description' => '{"de":"Description DE","fr":"Description FR","it":"Description IT"}',
'event_lastedit' => 2011-12-01 10:23:35,
'locations' => array(
array(
'location_id' => 1,
'location_name' => 'Bern',
'location_date' => '01.01.2012',
'location_deadline' => 1323340607,
'timestamps' => array(
array(
'timestamp_id' => 1,
'timestamp_time' => '10:30',
'timestamp_seats' => 30
),
array(
'timestamp_id' => 2,
'timestamp_time' => '16:30',
'timestamp_seats' => 40
)
)
),
array(
'location_id' => 2,
'location_name' => 'Davos',
'location_date' => '02.02.2012',
'location_deadline' => 1323340607,
'timestamps' => array(
array(
'timestamp_id' => 3,
'timestamp_time' => '12:30',
'timestamp_seats' => 50
),
array(
'timestamp_id' => 4,
'timestamp_time' => '15:30',
'timestamp_seats' => 60
)
)
)
)
);
I hope the question is clear enough.
Greetings
Spinne
Edit:
What i did so far:
$event = $event_db->querySingle("SELECT * FROM rf_events WHERE event_id={$event_id}", true)
$rf_locations = $event_db->query("SELECT * FROM rf_locations WHERE event_id={$event_id}");
$locations = array();
$timestamps = array();
$counter = 0;
// Loop sql query result and save entries in $events array.
while ( $row = $rf_locations->fetchArray() ){
$locations[$counter] = array(
'location_id' => $row['location_id'],
'location_name' => json_decode($row['location_name'], true),
'location_date' => $row['location_date'],
'location_deadline' => $row['location_deadline']
);
$rf_timestamps = $event_db->query("SELECT * FROM rf_timestamps WHERE location_id={$row['location_id']}");
$counter2 = 0;
while ( $row2 = $rf_timestamps->fetchArray() ){
$locations[$counter]['timestamps'][$counter2] = array(
'timestamp_id' => $row2['timestamp_id'],
'timestamp_time' => $row2['timestamp_time'],
'timestamp_seats' => $row2['timestamp_seats']
);
$counter2++;
}
$counter++;
}
SELECT * FROM rf_events, rf_locations, rf_timestamps WHERE
rf_locations.event_id = rf_events.event_id AND
rf_timestamps.location_id = rf_locations.event_id
Then, use add the data into php accordingly.
You can refer to: MYSQL JOIN

Categories