SQL Query for Updating Rows with New Values from Temporary Table in Laravel/Eloquent - laravel

I wish to update table B based on source table A so that if a new record is found, we can insert it otherwise update the record if any values have changed. How would I write the query in laravel 4 using eloquent?
Table A Table B
======= =======
Name | Color Name | Color
---------------------- ----------------------
Mickey Mouse | grey Mickey Mouse | red
Donald Duck2 | green Donald Duck | blue
Donald Duck | blue Minnie | red
Goofy | black
Minnie | red
In this example table B should be inserted with the rows Goofy and Donald Duck2 and the row mickey mouse should be updated with the new color grey.

This should work:
$a = A::all();
foreach($a as $current)
{
$b = B::where("name", "=", $current->name)->first();
if(!$b) $b = new B;
if($b->name != $current->name)
{
$b->name = $current->name;
$b->save();
}
}
Or more optimized:
$a = A::all();
// using this script: http://stackoverflow.com/questions/12050892/array-mapping-in-php-w ith-keys
$aFolded = array_reduce($a, function(&$result, $item){
$result[$item->name] = $item->color;
return $result;
}, array());
// so we now have array ( name => color, name2 => color2 )
$b = B::with("a", "name")->get(); // might recheck with laravel doc
foreach($b as $updateMe)
{
if($updateMe->color != $aFolded[$b->name])
{
$updateMe->color = $aFolded[$b->name];
$updateMe->save();
unset($aFolded[$b->name]);
}
}
// after this $aFolded will only contain the names which do not exist in b so we can just insert them all (maybe the insert query could be better)
foreach($aFolded as $name => $color)
{
DB::table("B")->insert(array("name" => $name, "color" => $color));
}

Related

Laravel 5.7 Get data from Pivot Table

I'm trying to get data from my pivot table.
clients table:
---|------
id | name
---|------
1 | John
---|------
2 | Steve
orders table:
---|------
id | description
---|------
1 | Mac
---|------
2 | Keyboard
---|------
3 | Printer
client_order (pivot)table:
id | client_id | order_id
---|-----------|------
1 | 1 1
---|-----------|------
2 | 1 | 2
---|-----------|------
3 | 2 | 3
Client.php
public function orders()
{
return $this->belongsToMany('App\Order','client_order');
}
Order.php
public function clients()
{
return $this->belongsToMany('App\Client','client_order');
}
Now, how can I retrieve data from pivot table? For example:
John | Mac, Keyboard (2 orders)
Steve| Printer (1 orders)
Thank you.
For client:
$client = Client::find(1); //or anyway you create the client
$client->orders; //it gives you a collection that you can get data
in a foreach loop
//for example
foreach($client->orders as $order){
echo $order->description;
}
For order:
$order = Order::find(1); //or anyway you create order
$order->clients; //it gives you a collection too
//for example
foreach($order->clients as $client){
echo $client->name;
}
This is for your new comment. First you select your users and then in a loop you can get the orders:
$clients = Client::all();
foreach($clients as $client){
echo $client->name." | ";
foreach($client->orders as $order){
echo $order->description;
}
echo "(".count($client->orders)." orders)";
}
You can achieve that using the relations as #Rouhollah Mazarei said, but you can also use the own pivot table to retrieve this information:
$clientsOrders = DB::table('client_order')->where('client_id', $clientId)->count()->get();
This will return to you how many orders this client made, you just need to inform his id.

Cakephp 3: belongsToMany contain or matching condition?

Piece of my database looks like database part
Categories use tree behavior.
How can i get a manufacturer's (Producers) Products for current Category?
I tried contain and matching, but i received duplicated data or Producers names without related Products.
EDIT:
$query = $this->Producers->find()->matching('Products.Categories',
function ($q) {
return $q->where(['Categories.id' => 18]);
}
);
Results:
Producent: Canon
-------------------------------------------
| ID | Name | Barcode |
-------------------------------------------
| 1 | EOS 1000D | |
-------------------------------------------
| 18 | Camera | |
-------------------------------------------
| 23 | 18 | |
-------------------------------------------
First row (id = 1) it's what i need.
Now i have to remove from results:
second row (id = 18) this is Category id from table Categories,
thrid row (id = 23) - from Products_Categories table.
Done. There is working query:
$query = $this->Producers->find()
->select(['Producers.id','Producers.name', 'Products.id', 'Products.name'])
->matching(
'Products.Categories', function ($q) use ($categoryId){
return $q->where(['Categories.id' => $categoryId]);
}
);

ManyToMany relation - how update attribute in pivot table

I am now learning to work with pivot tables: https://laravel.com/docs/4.2/eloquent#working-with-pivot-tables
I have WeeklyRoutine model. Each routine has several Activities. The assigned activities are attached in a pivot table activity_routine.
Relation defined in the WeeklyRoutine model:
return $this->belongsToMany('App\Models\Activity', 'activity_routine', 'routine_id', 'activity_id')->withPivot('done_at')->withTimestamps();
}
it looks like this:
// activity_routine pivot table (relevant columns only)
| id | activity_id | routine_id | done_at |
| 34 | 1 | 4 | 2016-04-23 09:27:27 | // *1
| 35 | 2 | 4 | null | // *2
*1 this activity is marked as done with the code below
*2 this activity is not yet done
what I have:
I can update the done_at field in the pivot table, thus making it marked as DONE for the given week (a weeklyroutine_id = 4 in the above code
public function make_an_activity_complete($routineid, $activityid) {
$date = new \DateTime;
$object = Routine::find($routineid)->activities()->updateExistingPivot($activityid, array('done_at' => $date));
return 'done!';
}
what I need
I want to UN-DO an activity. When it is already done, that is when the done_at is not null buc contains a date, make it null.
In other words I need to do the below switch of value, but the proper way:
$pivot = DB::table('activity_routine')->where('routine_id, $routineid)->where('activity_id, $activityid)->first();
if($pivot->done_at != null) {
$new_val = new \DateTime;
} else {
$new_val = null;
}
$object = Routine::find($routineid)->activities()->updateExistingPivot($activityid, array('done_at' => $new_val));
How to do it? I have no clue!
Thx.
Your approach seems fine to me. I would probably do it like this.
$routine = Routine::find($routineid);
$activity = $routine->activities()->find($activityid);
$done_at = is_null($activity->pivot->done_at) ? new \DateTime : null;
$routine->activities()->updateExistingPivot($activityid, compact('done_at'));

WebFocus, two title columns and merging cells

If i have a table in a WebFocus Raport design
+--------+---------+--------+---------+
| left_1 | right_1 | left_2 | right_2 |
+--------+---------+--------+---------+
| v11 | p11 | v21 | v21 |
+--------+---------+--------+---------+
| v12 | p12 | v22 | v22 |
....
How to do a such table with syllabus column titles:
+-------+-------+-------+-------+
| One | Two |
+-------+-------+-------+-------+
| left | right | left | right |
+-------+-------+-------+-------+
| v11 | p11 | v21 | v21 |
+-------+-------+-------+-------+
| v12 | p12 | v22 | v22 |
....
Thank you
Sorry for the delay of the answer :)
To rename columns, with the AS command. Example:
TABLE FILE SYSTABLE
PRINT NAME
COMPUTE LEFT1/A3 = 'v11'; AS 'left';
COMPUTE RIGHT1/A3 = 'p11'; AS 'right';
COMPUTE LEFT2/A3 = 'v21'; AS 'left';
COMPUTE RIGHT2/A3 = 'p21'; AS 'right';
IF RECORDLIMIT EQ 10
END
To put the heading columns, you can work with the ACROSS command but it will be more tricky that if u use simply SUBHEAD. With the same example:
TABLE FILE SYSTABLE
PRINT NAME NOPRINT
COMPUTE LEFT1/A3 = 'v11'; AS 'left';
COMPUTE RIGHT1/A3 = 'p11'; AS 'right';
COMPUTE LEFT2/A3 = 'v21'; AS 'left';
COMPUTE RIGHT2/A3 = 'p21'; AS 'right';
IF RECORDLIMIT EQ 10
ON TABLE SUBHEAD
"<+0>One<+0> Two"
ON TABLE PCHOLD FORMAT HTML
ON TABLE SET HTMLCSS ON
ON TABLE SET STYLE *
UNITS=IN, PAGESIZE='Letter',
LEFTMARGIN=0.500000, RIGHTMARGIN=0.500000,
TOPMARGIN=0.500000, BOTTOMMARGIN=0.500000,
SQUEEZE=ON, GRID=OFF, ORIENTATION=LANDSCAPE, $
TYPE=REPORT,FONT='ARIAL',SIZE=9,$
TYPE=TABHEADING,HEADALIGN=BODY,$
TYPE=TABHEADING, LINE=1, ITEM=1, COLSPAN=2, SQUEEZE=ON,$
TYPE=TABHEADING, LINE=1, ITEM=2, COLSPAN=2, SQUEEZE=ON,$
ENDSTYLE
END
Hope it helps!
I'm not entirely sure if you load the headers as a field or if that is the field name
But this might help you
Define fields
TITL1/A3 = 'One';
TITL2/A3 = 'Two';
BLANK/A1 = '';
Edit the Left and Right title fields to remove the _1 or _2
Print the fields BY BLANK NOPRINT
Add
ON BLANK SUBHEAD
"
You can also add more rows to the subhead if you need more titles
You can easily do it by embedding HTML/CSS scripts in report(.fex) file.
just add the HTML/css code at the end of the file.
For eg.
-HTMLFORM BEGIN // to start styling your generated report table with HTML/CSS
TABLE tr
td:first-child // applies on 1st row ONLY.It can be td or th.
{
colspan = "2"; //to merge 2 columns
}
-HTMLFORM END //end HTML.
So the first row must have two cells having title "ONE" and "TWO"(in your case), and both cells must have property of colspan = "2"
Also you can refer:
Colspan propery from here
manipulating first row of table from here
Second option is to write the whole code in a file and save it in .htm/.html format and just insert the file in to WEBFOCUS(.fex) file.For eg.
-HTMLFORM BEGIN
-INCLUDE HTML_FILE.HTML
-HTMLFORM END
Hope it helps.Thanks.

Fastest way to build hierarchical structure

I have a data source, containing the following columns:
ID | Tile | Score | Type
I have several rows in this data source, but of interest is the "Type" column that contains a type definition, each row belongs to, something like:
1 | Apple | 12 | Pipped
2 | Banana | 34 | Flesh
3 | Kiwi | 32 | Flesh
4 | Orange | -1 | Pipped
5 | Grapes | 3 | Pipped
6 | Potato | 5 | Skinned
I need to pull this information into a collection, or a KeyValuePair<string, List<Data>> but cannot find an efficient way to do this.
I'm currently using LINQ to pull a collection for each of the types (enumerator):
var pipped = (from p in dataSource where p.Type != null && p.Type.Equals(enum.Pipped) select p).ToList();
var flesh = (from p in dataSource where p.Type != null && p.Type.Equals(enum.Flesh) select p).ToList();
var skinned = (from p in dataSource where p.Type != null && p.Type.Equest(enum.Skinned) select p).ToList();
SortedDictionary<string, List<dataSource>> items = new SortedDictionary<string, List<dataSource>>();
items.Add("Pipped", pipped);
items.Add("Skinned", skinned);
items.Add("Flesh", flesh);
There must be a more efficient way to do this?
Looks like you want to use a GroupBy with a ToDictionary like this:
var dictionary = (from x in datasource
where x.Type != null
group x by x.Type into x
select x).ToDictionary(x => x.Key, x => x.ToList());
Or if you want to use method syntax:
var dictionary = datasource.Where(x => x.Type != null)
.GroupBy(x => x.Type)
.ToDictionary(x => x.Key, x => x.ToList());

Resources