Updating multiple rows using Yii's updateAll() - php

I'm trying to update multiple rows in Yii:
$list = array(1, 2, 3, 4, 5);
foreach($list as $id) {
$query = "UPDATE products SET photos=crawler.photos, status=crawler.status WHERE id=crawler.product_id AND crawler.product_id=$id;";
}
I'm new to Yii. Basically, I want to update rows from table products with the values from table scrape (using specific id, which are coming from $list). But not with foreach(), but with updateAll().

Active directory pattern. Good to write mode.
$movies_updated = SomeModel::updateAll([
'language' => 'pl',
'age' => 3,
], ['id' => 1]); # condition

I think should be somethings like this
public function actionMyProductsUpdate($id)
{
foreach ($queue as $item) {
$myUpdate = "UPDATE products as a join crawler as b
on ( a.id=b.product_id and b.product_id= $item->id)
SET a.photos=b.photos, a.status=b.status;";
\Yii::$app->db->createCommand($myUpdate)->execute();
}
}
version 2
public function actionMyProductsUpdate($id)
{
$myUpdate = "UPDATE products as a join crawler as b
on ( a.id=b.product_id and b.product_id in $list )
SET a.photos=b.photos, a.status=b.status;";
\Yii::$app->db->createCommand($myUpdate)->execute();
}

I know this is an old question, but I happened across it whilst researching something a little more complex. If I'm understanding the intention correctly, this should work:
Yii::$app->db->createCommand(
"UPDATE products p, crawler c
SET p.photos = c.photos, p.status = c.status
WHERE p.id = c.product_id;"
)->execute();
(I prefer the direct join syntax, particularly where the join is being used in an update.)

Related

How to group my results and have all rows shown?

SELECT i.itemsname
, i.itemsprice
, i.itemsdescrip
, c.catname
, c.catdes
, c.status
, c.collapse
, c.catid
FROM items i
LEFT
JOIN categories c
ON c.catid = i.catid
WHERE i.restid
AND c.restid =12
GROUP
BY c.catid
that is my query at the moment but I would like to have something like this....
but this is what I'm getting:
Ok, I lied in the comments, so With PDO (haven't tested it)
$stmt = $PDO->prepare('SELECT
categories.catname,
items.itemsname,
items.itemsprice,
items.itemsdescrip,
categories.catdes,
categories.status,
categories.collapse,
categories.catid
FROM items
LEFT JOIN categories ON items.catid=categories.catid
WHERE items.restid AND categories.restid = :restid');
$stmt->execute([':restid' => 12]);
$data = $stmt->fetchAll(\PDO::FETCH_GROUP);
foreach($data as $catname => $rows){
//echo group html stuff
//echo "<dl>";
//echo "<dt>$catname</dt>".;
foreach($rows as $row){
//echo row data stuff
// echo "<dd> {stuff} </dd>";
}
//echo "</dl>";
}
I'll leave the html up to you. But as I said you want a data structure like this
[
'BREAKFASTS' => [
0 => [ name => "wimpy hamburger", description => "bla bla", price => "$100,000"],
1 => [ ... ]
],
'SINGLE BURGERS' => [ ...]
]
note that the first field after "SELECT" is by default the field used by FETCH_GROUP
See in this way, the first foreach can output the title of the category, which is BREAKFASTS for example. Then the inner foreach can do the individual rows in the table.
Personally I would use a dl, dt, dd tag setup as my structure (hinted in the comments, i really am to lazy today to code all the html, <sigh>)
https://www.w3schools.com/tags/tag_dt.asp
UPDATE
You may want to check your query
...
WHERE
items.restid AND ...
Seems to be flawed, just saying. I saw this while optomizing the query for sorting.
SELECT
c.catname,
i.itemsname,
i.itemsprice,
i.itemsdescrip,
c.catdes,
c.status,
c.collapse,
c.catid
FROM
(
SELECT c0.catid FROM categories AS c0 WHERE c0.restid = :restid SORT BY c0.catname
) AS t
JOIN
categories AS c ON t.catid=c.catid
LEFT JOIN
items AS i ON items.catid=categories.catid
WHERE
items.restid = ? //< this is the error/omission/strangeness i pointed out above.
So a few things to note, first you should base the query off the categories, as an empty category should be shown, while an item without a category will blow it all to bits ( basically, ie how can you group them by the category if they have none ) You'll wind up with some hodgepoge of items with no category at the end, of course based on your example I'm assuming a Many to One relationship. For example One category can have Many items, and Many items can belong to a category. (it's probably more ideal to do a Many to Many, but that's another story for another day)
The reason the above query is more optimized is the inner query, creates only a small temp table using the catid, And sorts on just the data from the cat table and only the data that is pulled by the where.
Then as we move to the outer query, they basically inherent the sort from the join, and we can pull the rest of the data from that. It's typically about 2-10x faster this way (of course I haven't test this particular query) in theory. Of course this is a bit more complex/advanced query and is optional, but it should improve sort performance if my mind is in the right place tonight... lol
Also I abbreviated your table names (alias), as I said I am lazy like that. Sadly my answers are always so long, dont ask me how I see all these issues, it's just experience or how my dyslexic brain works?
Lastly, if you really must use mysqli, you can manually group them with something like this.
$data = [];
while(false !== ($row = $res->fetch_assoc())){
$key = $row['catname'];
if(!isset($data[$key])) $data[$key] = [];
$data[$key][] = $row;
}
It's all so prosaic (common place, non-poetic) at this point for me.
Good luck.
$cat = mysqli_query($connect, "SELECT
categories.catname,
items.itemsname,
items.itemsprice,
items.itemsdescrip,
categories.catdes,
categories.catid
FROM items
LEFT JOIN categories ON items.catid=categories.catid
WHERE items.restid AND categories.restid = 12");
if($cat === FALSE) {
die(mysqli_error());
}
$data = [];
while ($rowb = mysqli_fetch_array($cat)) {
$key = $rowb['catname'];
if(!isset($data[$key])) $data[$key] = [];
$data[$key][] = $rowb;
foreach($data as $catname => $rowbs){
echo "
<dl><button class='accordiontry'><dt>$catname</dt></button>";
<div class='panel1'>
foreach($rowbs as $rowb){
echo"<div class='rmenu'>
<dd><span class='item'>{$rowb['itemsname']}</span>
<span class='price'>£{$rowb['itemsprice']}</span><br>
<span class='des'>{$rowb['itemsdescrip']}</span> ";
}
echo"</div></dd>
</div></dl>";
}
}
}

SQL query to get value from referenced table

I have two tables called mg_product and mg_product_user_property.
In mg_product there are 3 columns: id, title, price as
In mg_product_user_property table product_id corresponds with id column in mg_product table.
So my goal is to get the value of property_id of "15", which in the picture above will be "Mediatek".
This is my SQL:
$sql = "SELECT *
FROM mg_product AS products
INNER JOIN mg_product_user_property AS properties
ON products.id = properties.product_id
WHERE title LIKE '%$search%')";`
PHP:
$resultSet = DB::query($sql);
if ($resultSet->num_rows > 0) {
while ($rows = $resultSet->fetch_assoc()) {
$title = $rows['title'];
$price = $rows['price'];
}
} else {
$output = "No results";
}
Now I need to assign to a php variable the value of property_id=15 so I will be able to print "Mediatek" on my website. How can I achieve that? Sorry for my English.
You are pretty close to what you want, but a couple things are going to either be a mess, or unwanted. So, since there are different ways one can go with this, I will only present a very stripped example (and am INTENTIONALLY leaving out a bunch of code here).
You may not want to do a JOIN like that in the initial search, as for each property, it will also return another of the same product. So looping through that will result in dozens of the same product.
However, if _ALL_YOU_WANT_ is to show the Product Title, Price, and Property 15... you can reduce some headwork with a simpler query:
SELECT p.title, p.price, pr.value
FROM mg_product AS p
LEFT JOIN mg_product_user_property AS pr
ON p.id = pr.product_id AND pr.property_id = 15
WHERE p.title LIKE '%$search%'
The LEFT JOIN means if the property doesn't exist, it will still return the product. But with an empty property value. And this should not return dozens of the same product for every other property in the table.
--
The OTHER way you could go about doing it, using the SQL query you already have (and the dozens of results of the same product it will return), you can alter your php loop like so:
$found_products = array();
while ($row = $resultSet->fetch_assoc()) {
if ($row['property_id'] == 15) {
$found_products[$row['product_id']] = array(
'title' => $row['title'],
'price' => $row['price'],
'prop' => $row['value']
);
}
}
// now you have a clean array of found products that have the property
--
Also I am forced to point out that you should use a prepared statement here, replacing inserting $search directly into the code. But showing you all of how to do that is beyond the scope of this question/answer.

Select multiple columns from inner join in Silverstripe 3.1

In my events calendar module for Silverstripe 3.1, i have added some additional fields to CalendarEvent. I want to make use of these in my template, but from my researches i have seen that events are exported as being CalendarDateTime so i can't use my additional fields.
I have found that in getStandardEvents function, there is a inner join which i think is causing the problem, but i can't figure it out to join the columns from CalendarEvent
$list = DataList::create('CalendarDateTime')
->filter(array(
'EventID' => [139, 140, 141, 143]
))
->innerJoin('CalendarEvent', "EventID = \"{CalendarEvent}\".\"ID\"")
->innerJoin("SiteTree", "\"SiteTree\".\"ID\" = \"{CalendarEvent}\".\"ID\"")
->where("Recursion != 1");
Note: In my code, i have some of the columns as variables, so i have written them as the values that are reffering to.
Here is the original code:
$list = DataList::create($datetimeClass)
->filter(array(
$relation => $ids
))
->innerJoin($eventClass, "$relation = \"{$eventClass}\".\"ID\"")
->innerJoin("SiteTree", "\"SiteTree\".\"ID\" = \"{$eventClass}\".\"ID\"")
->where("Recursion != 1");
I have tried to add the 'CalendarEvent' as a second parameter inside DataList::create(), but no result. I have the same output.
So how can i select columns from CalendarDateTime and CalendarEvent tables ?
Any help would be appreciated.Thanks
I have found a manual way:
$list = DB::query('SELECT * FROM "CalendarDateTime" INNER JOIN "CalendarEvent" ON "EventID" = "CalendarEvent"."ID" INNER JOIN "SiteTree" ON "SiteTree"."ID" = "CalendarEvent"."ID" WHERE "Recursion" != 1');
Any other solutions are welcome.

Multiple SQL queries and FOREACH - Can be JOINED to one?

I am trying to pull a list of Events, also seeing which members have paid for the Events. I then want to see if they are on the committee, to see if they have admin permissions.
I have successfully done this, using three SQL queries, then using three foreach loops to build the Array.
I am SURE this can be done with one SQL query and one foreach loop, however I have not yet mastered the JOIN technique.
I am using Expression Engine, Codeigniter Active Record, I will display to you the SQL output and also what my current EE functions look like.
THANKS FOR THE HELP! :D
SQL to select ALL events which are active
SELECT `id` as event_ID, `name` as event_name, `description` as event_description
FROM (`events`)
WHERE `events_category_id` = '1'
AND `active` = 1
ORDER BY `name` asc
EE CODE to achieve this:
$query = $this->theDb->select('id as event_ID, name as event_name, description as event_description')
->order_by("name", "asc")
->get_where('events', array('event_category_id'=>$event_type,'active'=>1));
**
SQL to find what EVENT IDs the user has paid for
**
SELECT DISTINCT `products`.`event_ID` as joinedID
FROM (`transactions_items`)
JOIN `transactions` ON `transactions`.`id` = `transactions_items`.`id`
JOIN `products` ON `products`.`id` = `transactions_items`.`product_id`
JOIN `events` ON `events`.`id` = `products`.`event_ID`
WHERE `transactions`.`member_id` = 27500
AND `events`.`active` = 1
AND `event_category_id` = '1'
ORDER BY `events`.`name` asc
EE CODE to achieve this
$query = $this->theDb->select('products.event_ID as joinedID')
->distinct()
->order_by("events.name", "asc")
->join('transactions', 'transactions.id = transactions_items.id')
->join('products', 'products.id = transactions_items.product_id')
->join('events', 'events.id = products.event_ID')
->get_where('transactions_items', array('transactions.member_id' => $memberID, 'events.active' => 1,'activity_category_id'=>$activity_type));
SQL to find ADMIN rights
SELECT `events`.`id` as event_ID, `admins`.`admin_role_id` as role_id, `admins_roles`.`name` as role_description
FROM (`admins`)
JOIN `admins_roles` ON `admins`.`admin_role_id` = `admins_roles`.`id`
JOIN `events` ON `events`.`id` = `admins`.`event_ID`
WHERE `admins`.`member_id` = 27500
AND `events`.`active` = 1
EE CODE to achieve this
$query = $this->theDb->select('events.id as event_ID, admins.admin_role_id as role_id, admins_roles.name as role_description')
->join('admins_roles', 'admins.admin_role_id = admins_roles.id')
->join('events', 'events.id = admins.event_ID')
->get_where('admins', array('admins.member_id' => $memberID, 'events.active' => 1));
FOR EACH LOOPS
// Create list of Events setting defaults
foreach($events_list as $row)
{
$combinedEvents[$row->event_ID] = array(
'eventID' => $row->event_ID,
'eventName' => $row->event_name,
'eventDescription' => $row->event_description,
'isJoined' => 0,
'roleID' => 0,
'roleDescription' => "",
);
}
// Add Committee roles
foreach($admin_list as $row)
{
$combinedEvents[$row->event_ID]['roleID'] = $row->role_id;
$combinedEvents[$row->event_ID]['roleDescription'] = $row->role_description;
}
// Add Transactions
foreach($transaction_list as $row)
{
$combinedEvents[$row->joinedID]['isJoined'] = 1;
}
I don't quite understand the FOREACH part because I've never touched PHP - but you should be able to solve the multiple SQL queires using the ;with clause. I have created an example in response to another question here and here. Is this what you're looking for?

Lots and lots of joins in a Zend Query, hopefully just a slight tweak

Apologies for all this code, anyhow Im re-working a query into the Zend query way of working, this is what I have so far:
$db = Zend_Registry::get ( "db" );
$stmt = $db->query('
SELECT recipe_pictures.picture_id, recipe_pictures.picture_filename, course.course_name, cuisines.name, recipes.id, recipes.Title, recipes.Method, recipes.author, recipes.SmallDesc, recipes.user_id, recipes.cuisine, recipes.course, recipes.Created_at, recipes.vegetarian, recipes.Acknowledgements, recipes.Time, recipes.Amount, recipes.view_count, recipes.recent_ips, guardian_writers.G_item, guardian_writers.G_type
FROM recipes
LEFT JOIN course ON recipes.course = course.course_id
LEFT JOIN recipe_pictures ON recipes.id = recipe_pictures.recipe_id
LEFT JOIN cuisines ON recipes.cuisine = cuisines.id
LEFT JOIN guardian_writers ON recipes.author = guardian_writers.G_author
WHERE recipes.id = ?', $id);
$stmt->setFetchMode(Zend_Db::FETCH_ASSOC);
$recipes = $stmt->fetchAll();
return $recipes;
That one above works, trying to get the Zend version properly, my effort is below.
$db = Zend_Registry::get ( "db" );
$select = $db->select()
->from(array('r' => 'recipes'))
->join(array('c' => 'course'),
'r.course = c.course_id')
->join(array('rp' => 'recipe_pictures'),
'r.id = rp.recipe_id')
->join(array('cui' => 'cuisines'),
'r.cuisine = cui.id')
->join(array('gw' => 'guardian_writers'),
'r.author = gw.G_author')
->where(' id = ? ', $id);
$recipes = $db->fetchRow($select);
return $recipes;
If anyone can spot an error Id be very grateful, thanks
Use joinLeft instead of join to produce left joins.
To fetch specific columns from a table, rather than all (*) use this:
->from(array('r' => 'recipes'), array('id', 'title', 'method'))
or
->joinLeft(array('rp' => 'recipe_pictures'),
'r.id = rp.recipe_id',
array('picture_id', 'picture_filename')
)
To fetch no columns from a table, pass an empty array as the third parameter.
The join method provides an sql INNER JOIN. If you want to get a LEFT JOIN you should use joinLeft.

Categories