Duplicate Queries in Laravel- Debugger - laravel

I am trying to update the columns of the records based on the other column records but it results in the duplicate queries since its being executed for each record in the table.I s there a way to avoid it and improve this code.
public function updateReviewColumn(){
$reviewData = $this->pluck('indicator')->toArray();
foreach ($reviewData as $datum) {
if ($datum == 'Y')
$this->where('indicator', $datum)
->update(['reviewindicator' => 'Yes']);
else
$this->where('indicator', $datum)
->update(['reviewindicator' => 'No']);
}
}

I would transform this following query into a eloquent stmt:
UPDATE yourTable
SET indicator = IF(indicator = 'Y', 'Yes','No'),
WHERE indicator= 'Y' OR indicator= 'N'
To have it one shot I think you should go for DB raw query (if you got MySQL behind)
Otherwise you can go for two different Eloquent stmt
MyTable::where('indicator', 'Y')->update(['indicator' => 'Yes']);
MyTable::where('indicator', 'N')->update(['indicator' => 'No']);
Probably you'll face issues if you got safe_updates enabled in MySQL

Related

how to combine queries yii2

I have a query with 2 tables. I want to combine these two queries into one query. how do?
public function actionGroup()
{
$query1 = (new \yii\db\Query())
->select(['lao',new \yii\db\Expression('COUNT(lao)'),'nama_ptgs', new \yii\db\Expression('SUM(outstanding)')])
->from('debitur')
->groupBy('lao')
->all();
$query2 = (new \yii\db\Query())
->select(['lao', new \yii\db\Expression('SUM(tgt_pergeseran)')])
->from('resume')
->groupBy('lao')
->all();
return $this->render('outstanding', [
'query1' => $query1,
'query2' => $query2,
]);
}
example sql
SELECT debitur.lao, debitur.Outstanding, debitur.jumlah, resume.Target FROM ( SELECT lao, SUM(outstanding) as Outstanding, COUNT(lao) as jumlah FROM debitur GROUP BY lao )debitur INNER JOIN ( SELECT lao, SUM(tgt_pergeseran) as Target FROM resume GROUP BY lao ) resume ON debitur.lao = resume.lao
error undefined index
print($query);
result
The raw query you provided does not have any where() condition for the main query
SELECT debitur.lao, debitur.Outstanding, debitur.jumlah, resume.Target
FROM
(SELECT lao, SUM(outstanding) as Outstanding, COUNT(lao) as jumlah FROM debitur GROUP BY lao) debitur
INNER JOIN
(SELECT lao, SUM(tgt_pergeseran) as Target FROM resume GROUP BY lao) resume
ON debitur.lao = resume.lao
If that is the complete and correct query that show you the right results in the phpmyadmin widow, you need to use the sub query like below
$subQueryFrom = new \yii\db\Query();
$subQueryFrom->select(['lao', new \yii\db\Expression('SUM(outstanding) as Outstanding, COUNT(lao) as jumlah')])
->from('debitur')
->groupBy('lao');
$subQueryJoin = new \yii\db\Query();
$subQueryJoin->select(['lao', new \yii\db\Expression('SUM(tgt_pergeseran) as Target')])
->from('resume')
->groupBy('lao');
$query = new \yii\db\Query();
$results = $query->select(['debitur.lao', 'debitur.Outstanding', 'debitur.jumlah', 'resume.Target'])
->from(['debitur' => $subQueryFrom])
->innerJoin(['resume' => $subQueryJoin], 'debitur.lao = resume.lao')
->all();
You can now use the $result in your view which holds the records against your query.
return $this->render('outstanding', [
'results' => $results,
]);
In order to combine the results from 2 queries from 2 different tables you can use the Union Operator. From the link there are necessary conditions though:
Each SELECT statement within UNION must have the same number of
columns
The columns must also have similar data types
The columns in each SELECT statement must also be in the same order
In order for this to work for you, you need to alter your queries as follows:
$query1 = (new \yii\db\Query())
->select(['lao',
new \yii\db\Expression('COUNT(lao) as count_column'),
'nama_ptgs',
new \yii\db\Expression('SUM(outstanding) as sum_column'),
new \yii\db\Expression('NULL as tgt_sum')])
->from('debitur')
->groupBy('lao');
$query2 = (new \yii\db\Query())
->select(['lao',
new \yii\db\Expression('NULL as count_column'),
new \yii\db\Expression('NULL as nama_ptgs'),
new \yii\db\Expression('NULL as sum_column'),
new \yii\db\Expression('SUM(tgt_pergeseran) as tgt_sum'),
])->from('resume')
->groupBy('lao');
In short if your first table contains columns a and b, and your second contains columns a and c. Then what you need to do is select(['a','b','NULL as c']) from the first and select(['a','NULL as b','c']) from the second so that you can combine the two results
Then the combined query is simply:
$combinedQuery = $query1->union($query2);

Eloquent: Do I need to do this query raw?

I'm rewriting parts of legacy software using laravel/eloquent.
my understanding of typical eloquent is good and I've done some projects in laravel but not so much for legacy code.
I'm trying to do this in eloquent which creates 79 rows:
INSERT IGNORE INTO `ps_module_shop` (`id_module`, `enable_device`, id_shop) (SELECT `id_module`, `enable_device`, 555 FROM ps_module_shop WHERE `id_shop` = 1);
I've read you can only do bulk insert with model::insert but I'm not sure how to do so with this query specifically, other than pure sql.
This is how I'm doing it for now, but raw sql feels more elegant for this query:
$blkInsert = [];
$tplModuleShop = ModuleShop::where('id_shop', 1)->get();
foreach($tplModuleShop as $mshop) {
$blkInsert[] = [
'id_module' => $mshop->id_module,
'enable_device' => $mshop->enable_device,
'id_shop' => $shop->id_shop,
];
}
ModuleShop::insert($blkInsert);
Note: I know this is a pivot table, but it is legacy db that uses composite keys so I decided to treat it as its own model.
Honestly this might just be easier using your sql statement... here is my attempt:
DB::table('ps_model_shop')
->insert(DB::table('ps_module_shop')
->select(['id_module', 'enable_device'])
->where('id_shop', 1)
->get()
->map(function($module){
$module['id_shop'] = 555;
})
->toArray()
);
We found a way to do it with DB::select (although still doing the sql part "raw")
$fixCollection = function($collection) {
return json_decode(json_encode($collection), true);
};
ModuleShop::insert(
$fixCollection(
\DB::select("SELECT `id_module`, `enable_device`, {$shop->id_shop} as id_shop FROM ps_module_shop WHERE `id_shop` = 1")
)
);

LINQ select column(s) of table before doing multiple joins

After running the query below and hovering over "usersToWork" when debugging, I can view all of the properties of the single entry that I get returned to me in addition to the other tables that have relations to this value. What I need to display to the user is the "Lines.Id" (Lines being the table and Id being the column in the Lines table) value, however that value gets lost from the SelectMany() statements. Is there anyway to select that "Lines.Id" value to include in the final value that I get from all of my joins? In the code below, I commented out what I want but I can't place that there otherwise I get error on the first SelectMany statement saying 'int' does not contain a definition for 'Shifts' and no extension method 'Shifts' accepting a first argument of type 'int' could be found.'
Correct me if I'm wrong but SelectMany() selects all of the columns from what you want to join on. In this case, in the first SelectMany() I get only values from the "Shifts" table and in the second SelectMany() I get only values from the "Users" table. Why is this different from the SQL join? When joining in SQL you can get every column as you join them together, SelectMany() yields only the values of the second table that you are joining on. Is it even possible to get that value in the "Lines" table or will I have to do another query? Any help would be great.
int idEnteredByUser = 123;
var usersToWork = entityDataModel.Lines
//....NOT IN MY CODE NOW....
// .Select(line => line.Id)//THIS IS WHAT I NEED.
// .Select(line => line.Description, line.Id//OR THIS TO RETURN TWO VALUES IF POSSIBLE
//This is my current code, I need to include on of the select lines above.
.SelectMany(line => line.Shifts) //Join lines on shifts.
.Where(shift => shift.EndTime >= DateTime.Now) //Join restricted times.
.SelectMany(user => user.Users) //Join the restricted shift times on users.
.Where(user => user.UserId == idEnteredByUser ); //Only look for the specific user
This works much easier using LINQ query syntax.
I'm assuming that you made a typo in your posted code and that user is a property of shift.
var idEnteredByUser = 123;
var usersToWork =
from line in entityDataModel.Lines
from shift in line.Shifts
where shift.EndTime >= DateTime.Now
from user in shift.Users
where user.UserId == idEnteredByUser
select new
{
Description = line.Description,
Id = line.Id
};

How do I check whether a value in a query result is null or not? - Active Record - CodeIgniter

I wanted to know how to check whether there is a value present in a table (managers) and then add a 'yes' or 'no' string depending on if there is a value in that table or not.
$this->db->select('employees.first_name, employees.last_name, departments.department_name, departments.department_numb, titles.title');
$this->db->from('employees');
$this->db->where('first_name', $firstname);
$this->db->where('last_name', $lastname);
$this->db->join('department_manager', 'department_manager.emp_numb = employees.emp_numb', 'inner');
$this->db->join('departments', 'departments.department_numb = department_manager.department_numb', 'inner');
$this->db->join('titles', 'titles.emp_numb = employees.emp_numb', 'inner');
$this->db->where('department_name', $dept);
$this->db->where('title', $jobtitle);
$result = $this->db->get();
$data = array();
foreach($result->result() as $row)
{
$entry = array();
$entry['firstname'] = $row->first_name;
$entry['lastname'] = $row->last_name;
$entry['jobtitle'] = $row->title;
$entry['dept'] = $row->department_name;
$entry['deptid'] = $row->department_number;
//$entry['ismanager'] =
$data[] = $entry;
}
return $data;
I want to check whether an employee is present in the table 'department_manager' which is joined by an employees number. So if that employee number is not present in the table 'department_manager' then I want to insert in the array index $entry[ismanager'] a string which says 'no', and if the employee number is present in the table 'department_manager' then I want $entry['ismanager'] to hold the string 'yes'.
But I'm confused as to how to check that the employee is present or not in that table. Do I do it in the active record query or in the foreach loop? And if it is done in the foreach loop then how do I make that comparison as the query is completed?
Why have a field that is basically a calculated value? That's like having fields for quantity per box, quantity of boxes then saving the total items to a third field. Never save to the database something you can gain access to via a quick query. In your query above it's as simple as changing the dept manager join to a left join, including the dept manager id and saying if that field is blank in a record the person is not a manager. Using a LEFT join will return all records whether they have an entry in the management table or not.
Add: department_manager.emp_numb to the select.
The Join:
$this->db->join('department_manager', 'department_manager.emp_numb
= employees.emp_numb', 'left');
Then in the foreach:
if(!$row->department_manager.emp_numb)
{
this person is not a manager;
}
If you feel you really must have that extra field then you can still populate it with the method above.
If you are using MySQL, I think you are looking for:
IFNULL(expr1,expr2)
where:
expr1 == null condition (in your case NULL)
expr2 == replacement value
Source: Control Flow Functions

Entity Framework query

I have a piece of code that I don't know how to improve it.
I have two entities: EntityP and EntityC.
EntityP is the parent of EntityC. It is 1 to many relationship.
EntityP has a property depending on a property of all its attached EntityC.
I need to load a list of EntityP with the property set correctly. So I wrote a piece of code to get the EntityP List first.It's called entityP_List. Then as I wrote below, I loop through the entityP_List and for each of them, I query the database with a "any" function which will eventually be translated to "NOT EXIST" sql query. The reason I use this is that I don't want to load all the attached entityC from database to memory, because I only need the aggregation value of their property. But the problem here is, the looping will query the databae many times, for each EntityP!
So I am wondering if anybody can help me improve the code to query the database only once to get all the EntityP.IsAll_C_Complete set, without load EntityC to memory.
foreach(EntityP p in entityP_List)
{
isAnyNotComoplete = entities.entityC.Any(c => c.IsComplete==false && c.parent.ID == p.ID);
p.IsAll_C_Complete = !isAnyNotComoplete;
}
Thank you very much!
In EF 4, you can do:
var ids = entityP_List.Select(p => p.ID);
var q = (from p in entities.entityP
where ids.Contains(p => p.ID)
select new
{
ID = p.ID,
IsAll_C_Complete = !p.entityCs.Any(c => !c.IsComplete)
}).ToList();
foreach (var p in entityP_List)
{
p.IsAll_C_Complete = q.Where(e.ID == p.Id).Single().IsAll_C_Complete;
}
...which will do the whole thing in one DB query. For EF 1, Google BuildContainsExpression for a replacement for the .Contains( part of the above.
I would base EntityP on a SQL View instead of a table. Then I would define the relationship, and aggregate the value for child table within the view.

Resources