Concatenate 2 columns laravel - mysql

I am trying to concatenate 2 columns and researched how to do it but I don't know where the error is, it says column not found, this is my query
public function obtenerCargo() {
if ($this->rcargo_id == null) {
$this->listCargo = recepcionCargo::select(
'recepcion_cargo.id',
'recepcion_cargo.rcargo_id',
'recepcion_cargo.no_factura',
'cargo_id.cargo_id',
'recepcion_cargo.porcentaje',
'recepcion_cargo.cargo_minimo',
'recepcion_cargo.cargo_devolucion',
'recepcion_cargo.cargo_reparacion',
'recepcion_cargo.cargo_almacenaje',
'recepcion_cargo.cargo_visita',
'recepcion_cargo.cargo_traslados',
'recepcion_cargo.cargo_fletes',
'recepcion_cargo.total',
'recepcion_cargo.cargo_porcentaje',
'recepcion_cargo.total_sp',
DB::raw("CONCAT(recepcion_cargo.total,' ',recepcion_cargo.total_sp) AS TOTAL",'recepcion_cargo.id'))
->pluck('TOTAL', 'recepcion_cargo.id')
->join('cargo_id', 'cargo_id.id', '=', 'recepcion_cargo.car_id')->get();
} else {
$this->listCargo = recepcionCargo::select(
'recepcion_cargo.id',
'recepcion_cargo.rcargo_id',
'recepcion_cargo.no_factura',
'cargo_id.cargo_id',
'recepcion_cargo.porcentaje',
'recepcion_cargo.cargo_minimo',
'recepcion_cargo.cargo_devolucion',
'recepcion_cargo.cargo_reparacion',
'recepcion_cargo.cargo_almacenaje',
'recepcion_cargo.cargo_visita',
'recepcion_cargo.cargo_traslados',
'recepcion_cargo.cargo_fletes',
'recepcion_cargo.total',
'recepcion_cargo.cargo_porcentaje',
'recepcion_cargo.total_sp',
DB::raw("CONCAT(recepcion_cargo.total,' ',recepcion_cargo.total_sp) AS TOTAL",'recepcion_cargo.id')
)
->pluck('TOTAL', 'recepcion_cargo.rcargo_id')
->join('cargo_id', 'cargo_id.id', '=', 'recepcion_cargo.car_id')
->where('recepcion_cargo.rcargo_id', '=', $this->rcargo_id)->get();
}
}
I am using my model and db:raw with pluck according to this it should work but it does not, in my view a table is displayed and it is not convenient to have 2 total fields so it is better for me to use concat

What is happening in your queries is:
You are selecting a lot of columns from a table, including one that belongs to another table and a DB::raw statement
You are performing the query and extracting the fields TOTAL and recepcion_cargo.id (that is what pluck does, it first performs the query, then extracts the results, so at this point your query will fall)
You are joining a Illuminate\Support\Collection to another table
I would recommend a couple actions:
First, you should join before executing the query (that is, before calling pluck
Second, to improve the performance, only select the columns that you are going to use
Hope it helps. Good luck!

Related

Multi-parameter search with mysql and node.js

Let me preface by saying I'm very new to SQL (and back end design) in general. So for those annoyed with noob questions, please be gentle.
BACKGROUND:
I'm trying to build a product test database (storing test data for all our products) where I want a user to be able to refine a search to find test data they actually want. For example, they may start by searching for all products of a certain brand name, and then refine it with a product type, and/or refine it with a date range of when the test was done.
PROBLEM:
I'm having a hard time finding information on how to implement multi-parameter searches with mysql and node.js. I know you can do nested queries and joins and such within pure SQL syntax, but it's not abundantly clear to me how I would do this from node.js, especially when certain search criteria aren't guaranteed to be used.
Ex:
CREATE PROCEDURE `procedureName`(
IN brandname VARCHAR(20),
producttype VARCHAR(30))
BEGIN
SELECT * FROM products
WHERE brand = brandname
AND product_type = producttype;
END
I know how to pass data from node.js to this procedure, but what if the user didn't specify a product type? Is there a way to nullify this part of the query? Something like:
AND product_type = ALL;
WHAT I'VE TRIED:
I've also looked into nesting multiple SQL procedures, but passing in dynamic data to the "FROM" clause doesn't seem to be possible. Ex: if I had a brandname procedure, and a product type procedure, I don't know how/if I can pass the results from one procedure to the "FROM" clause of the other to actually refine the search.
One idea was to create tables with the results in each of these procedures, and pass those new table names to subsequent procedures, but that strikes me as an inefficient way to do this (Am I wrong? Is this a completely legit way to do this?).
I'm also looking into building a query string on the node side that would intelligently decide what search criteria have been specified by the front end, and figure out where to put SQL AND's and JOIN's and what-nots. The example below actually works, but this seems like it could get ugly quick as I add more search criteria, along with JOINS to other tables.
// Build a SQL query based on the parameters in a request URL
// Example request URL: http://localhost:3000/search?brand=brandName&type=productType
function qParams(req) {
let q = "SELECT * FROM products WHERE ";
let insert = [];
if(req.query.brand) {
brandname = req.query.brand; // get brandname from url request
q = q + `brand = ?`, // Build brandname part of WHERE clause
insert.push(brandname); // Add brandname to insert array to be used with query.
};
if(req.query.type) {
productType = req.query.type; // get product type from url request
insert.length > 0 ? q = q + ' AND ' : q = q; // Decide if this is the first search criteria, add AND if not.
q = q + 'product_type = ?'; // Add product_type to WHERE clause
insert.push(productType); // Add product_type variable to insert array.
}
// Return query string and variable insert array
return {
q: q,
insert: insert
};
};
// Send Query
async function qSend(req, res) {
const results = await qParams(req); // Call above function, wait for results
// Send query string and variables to MySQL, send response to browser.
con.query(results.q, results.insert, (err, rows) => {
if(err) throw err;
res.send(rows);
res.end;
})
};
// Handle GET request
router.use('/search', qSend);
CONCISE QUESTIONS:
Can I build 1 SQL procedure with all my search criteria as variables, and nullify those variables from node.js if certain criteria aren't used?
Is there way to nest multiple MySQL procedures so I can pick the procedures applicable to the search criteria?
Is creating tables of results in a procedure, and passing those new table names to other procedures a reasonable way to do that?
Building the query from scratch in node is working, but it seems bloated. Is there a better way to do this?
Googling "multi-parameter search mysql nodejs" is not producing useful results for my question, i.e. I'm not asking the right question. What is the right question? What do I need to be researching?
One option is to use coalesce():
SELECT p.*
FROM products p
WHERE
p.brand = COALESCE(:brandname, p.brand)
AND p.product_type = COALESCE(:producttype, p.producttype);
It may be more efficient do explicit null checks on the parameters:
SELECT p.*
FROM products p
WHERE
(:brandname IS NULL OR p.brand = :brandname)
AND (:producttype IS NULL OR p.product_type = :producttype);

Joining other results from same table mysql knex

I would like to get other user_ids from the same table that match the event_ids. I've tried with a sub-query and a this.on function in a leftJoin and outerLeftJoin. Can't get around the 'not unique table/alias' error with the code below.
knex('user_2_event')
.select(
'event.*',
'user_2_event.user_id as main_user_id'
)
.where('user_2_event.user_id',17)
.join('event', 'event.event_id', 'user_2_event.event_id')
.leftOuterJoin('user_2_event', function(){
this.on('user_2_event.event_id', '=', 'event.event_id')
})
or this instead of the above leftOuterJoin, which produces an 'error with my syntax'.
.join(
knex('user_2_event')
.select('user_2_event.user_id as other_user')
.where('user_2_event.event', '=','event.event_id')
)
After searching in various ways for guidance on getting at data in separate ways on the same table (however one expresses that in technical terms), it was suggested to me to use aliases on the same table. Voila, quick and easy without worrying about join functions and sub-queries.
knex('user_2_event as e1')
.select(
'event.*',
'e1.user_id as user_id',
'e2.user_id as other_id'
)
.where('e1.user_id',17)
.join('event', 'event.event_id', 'e1.event_id')
.leftJoin('user_2_event as e2', 'e2.event_id', 'event.event_id')

Laravel Sum column database Eloquent

Trying to get the sum of a int field in one of my table should be pretty easy, unfortunately it is not as I'm getting different result whether I use Laravel, MySQL or Excel.
Laravel 5.4 gives me 20506:
Table::sum('field_name');
MySQL gives me 1830:
Select sum(field_name) from table;
And the data from the Excel sheet before importing it into the database:
Sum gives me 145689
Any idea? I tried to cast to integer before doing the sum but it doesn't work.
All the numbers are pretty big but don't contain comma or dot.
Examples of values I have to sum: (contain sometimes empty cells)
17906774
99630157
28581131
159551532
20312892
668928885
$query = YourModel::query();
$query->withCount([
'activity AS yoursum' => function ($query) {
$query->select(DB::raw("SUM(amount_total) as paidsum"))->where('status', 'paid');
}
]);
You can use laravel aggregate function SUM as :
$result = DB::table('table_name')
->select(DB::raw('SUM(field_name) as total_field_name'))
->get();
For more details you can follow:
https://laravel.com/docs/5.4/queries
Thanks
Try with
$result = DB::table(tablename)
->selectRaw('sum(column)')
->get();
If it still gives you wrong result, maybe wait for someone to give you a better answer. This is all I could think of.

Not retrieving set of values from table. Laravel

I'm trying to get values from my linking table sfees with columns student_id and mfee_id. Here, there might be multiple student_id with different mfee_id. The thing is that, i want to retrieve all mfee_id with same student_id.
I have used following syntax, but it is only returning single value:
public function verify($id,$sid)
{
$sfees = sfee::where('student_id', $sid)->value('mfee_id');//trying to get only mfee_id
return $sfees;
}
How can i solve this problem?
//edited
My table looks like:
You need to do a groupBy -
$sfees = sfee::where('student_id', '=',$sid)->groupBy('student_id')->get();
UPDATE
Try something like this -
$sfees = sfee::where('student_id', '=',$sid)->lists('mfee_id');
Or you can use the Schema Builder like this -
DB::table('sfees')->where('student_id', '=', $id)->lists('mfee_id');

Could not format node 'Value' for execution as SQL

I've stumbled upon a very strange LINQ to SQL behaviour / bug, that I just can't understand.
Let's take the following tables as an example: Customers -> Orders -> Details.
Each table is a subtable of the previous table, with a regular Primary-Foreign key relationship (1 to many).
If I execute the follow query:
var q = from c in context.Customers
select (c.Orders.FirstOrDefault() ?? new Order()).Details.Count();
Then I get an exception: Could not format node 'Value' for execution as SQL.
But the following queries do not throw an exception:
var q = from c in context.Customers
select (c.Orders.FirstOrDefault() ?? new Order()).OrderDateTime;
var q = from c in context.Customers
select (new Order()).Details.Count();
If I change my primary query as follows, I don't get an exception:
var q = from r in context.Customers.ToList()
select (c.Orders.FirstOrDefault() ?? new Order()).Details.Count();
Now I could understand that the last query works, because of the following logic:
Since there is no mapping of "new Order()" to SQL (I'm guessing here), I need to work on a local list instead.
But what I can't understand is why do the other two queries work?!?
I could potentially accept working with the "local" version of context.Customers.ToList(), but how to speed up the query?
For instance in the last query example, I'm pretty sure that each select will cause a new SQL query to be executed to retrieve the Orders. Now I could avoid lazy loading by using DataLoadOptions, but then I would be retrieving thousands of Order rows for no reason what so ever (I only need the first row)...
If I could execute the entire query in one SQL statement as I would like (my first query example), then the SQL engine itself would be smart enough to only retrieve one Order row for each Customer...
Is there perhaps a way to rewrite my original query in such a way that it will work as intended and be executed in one swoop by the SQL server?
EDIT:
(longer answer for Arturo)
The queries I provided are purely for example purposes. I know they are pointless in their own right, I just wanted to show a simplistic example.
The reason your example works is because you have avoided using "new Order()" all together. If I slightly modify your query to still use it, then I still get an exception:
var results = from e in (from c in db.Customers
select new { c.CustomerID, FirstOrder = c.Orders.FirstOrDefault() })
select new { e.CustomerID, Count = (e.FirstOrder != null ? e.FirstOrder : new Order()).Details().Count() }
Although this time the exception is slightly different - Could not format node 'ClientQuery' for execution as SQL.
If I use the ?? syntax instead of (x ? y : z) in that query, I get the same exception as I originaly got.
In my real-life query I don't need Count(), I need to select a couple of properties from the last table (which in my previous examples would be Details). Essentially I need to merge values of all the rows in each table. Inorder to give a more hefty example I'll first have to restate my tabels:
Models -> ModelCategoryVariations <- CategoryVariations -> CategoryVariationItems -> ModelModuleCategoryVariationItemAmounts -> ModelModuleCategoryVariationItemAmountValueChanges
The -> sign represents a 1 -> many relationship. Do notice that there is one sign that is the other way round...
My real query would go something like this:
var q = from m in context.Models
from mcv in m.ModelCategoryVariations
... // select some more tables
select new
{
ModelId = m.Id,
ModelName = m.Name,
CategoryVariationName = mcv.CategoryVariation.Name,
..., // values from other tables
Categories = (from cvi in mcv.CategoryVariation.CategoryVariationItems
let mmcvia = cvi.ModelModuleCategoryVariationItemAmounts.SingleOrDefault(mmcvia2 => mmcvia2.ModelModuleId == m.ModelModuleId) ?? new ModelModuleCategoryVariationItemAmount()
select new
{
cvi.Id,
Amount = (mmcvia.ModelModuleCategoryVariationItemAmountValueChanges.FirstOrDefault() ?? new ModelModuleCategoryVariationItemAmountValueChange()).Amount
... // select some more properties
}
}
This query blows up at the line let mmcvia =.
If I recall correctly, by using let mmcvia = new ModelModuleCategoryVariationItemAmount(), the query would blow up at the next ?? operand, which is at Amount =.
If I start the query with from m in context.Models.ToList() then everything works...
Why are you looking into only the individual count without selecting anything related to the customer.
You can do the following.
var results = from e in
(from c in db.Customers
select new { c.CustomerID, FirstOrder = c.Orders.FirstOrDefault() })
select new { e.CustomerID, DetailCount = e.FirstOrder != null ? e.FirstOrder.Details.Count() : 0 };
EDIT:
OK, I think you are over complicating your query.
The problem is that you are using the new WhateverObject() in your query, T-SQL doesnt know anyting about that; T-SQL knows about records in your hard drive, your are throwing something that doesn't exist. Only C# knows about that. DON'T USE new IN YOUR QUERIES OTHER THAN IN THE OUTER MOST SELECT STATEMENT because that is what C# will receive, and C# knows about creating new instances of objects.
Of course is going to work if you use ToList() method, but performance is affected because now you have your application host and sql server working together to give you the results and it might take many calls to your database instead of one.
Try this instead:
Categories = (from cvi in mcv.CategoryVariation.CategoryVariationItems
let mmcvia =
cvi.ModelModuleCategoryVariationItemAmounts.SingleOrDefault(
mmcvia2 => mmcvia2.ModelModuleId == m.ModelModuleId)
select new
{
cvi.Id,
Amount = mmcvia != null ?
(mmcvia.ModelModuleCategoryVariationItemAmountValueChanges.Select(
x => x.Amount).FirstOrDefault() : 0
... // select some more properties
}
Using the Select() method allows you to get the first Amount or its default value. I used "0" as an example only, I dont know what is your default value for Amount.