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')
Related
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!
I am trying to select from a table the column name, but would like to get it all caps, using UPPER.
I would like to to it without using Knex raw SQL, but it doesn't work.
That's what I am trying to do:
const usersJornadasComites = await Database.table('tb_usuario_jornada')
.where('tb_usuario_jornada.jornada_id', lastJornad.id)
.where('tb_usuario_jornada.comite_id', params.id)
.where('tb_usuario_jornada.ativo', 1)
.select(
'tb_usuario.id',
'UPPER(tb_usuario.nome)',
'tb_usuario.email',
'tb_usuario.celular',
'tb_usuario.dt_nascimento',
'tb_usuario_jornada.criado_em',
'tb_usuario.id',
'tb_usuario_jornada.usuario_id'
)
.leftJoin(
'tb_usuario',
'tb_usuario_jornada.usuario_id',
'tb_usuario.id'
)
It gives me an error saying that UPPER(tb_usuario.nome) is not a valid column name.
Any ideas?
Many thanks,
Gines
just to inform if somebody else has the same issue.
The solution I used was to instead of using ORM syntax, I used the knex.raw select and it worked properly.
U can try to UPPER(tb_usuario.nome) as nome
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.
I am pretty new to hibernate again, so this might be a noobish question ;).
Without to_days, but clustered by timestamp it works like this:
CriteriaQuery<Tuple> query = criteriaBuilder.createQuery(Tuple.class);
Root<Session> sessionRoot = query.from(Session.class);
query.multiselect(
sessionRoot.get("time").alias("time"),
criteriaBuilder.count(sessionRoot).alias("count")
);
query.groupBy(sessionRoot.get("time"));
List<Tuple> results = this.executeQuery(query);
So I recieve:
time|count
13721938721|1
13721938722|2
13721938723|3
13721938724|4
13721938725|2
13721938726|1
13721938727|4
But this are all sessioncounts for each millisecond, but I need those clustered by day and not by timestamp: thus I use to_days in plain mysql.
In mysql I perform this query:
SELECT TO_DAYS(`time`) AS `days`, COUNT(*) as `count` FROM sessions WHERE 1 GROUP BY `days`
This gives me:
days|count
777594|123
777595|60
777596|61
777597|74
But I have no idea, yet: how to achieve the same thing with javax.persistence.criteria.CriteriaBuilder and CriteriaQuery in hibernate?
I dont know how to do it with criteriaBuilder, but i do know how in Hibernate 4 criteria api:
query.setProjection(
Projections.sqlProjection(
"TO_DAYS(time) as days",
new String[]{"days"},
new Type[]{StandardBasicTypes.INTEGER}
)
);
sqlProjection allows you to cast or convert data types, but careful, using a projection will only retrieve the fileds you specify in it, and the resulting list will come up like this:
List<Object[]> results = this.executeQuery(query);
But you can make hibernate do a alias match with the properties using a result transformer:
query.setResultTransformer(new AliasToBeanResultTransformer(Session.class));
and the list comes out like it normally does:
List<Session.class> results = this.executeQuery(query);
Sorry i could not provide a criteriaBuilder solution, but i hope this gets you in the right track.
After some investigation, it turned out, that HQL does not support TO_DAYS. Since I want to make it possible for MySQL and other databases, this is my final solution:
Query q = entityManager.createQuery("SELECT concat(day(e.time), '-', month(e.time), '-', year(e.time)) AS days, COUNT(*) FROM Event e GROUP BY concat(day(e.time), '-', month(e.time), '-', year(e.time))");
The result is:
3-5-2012|980
4-5-2012|200
10-6-2012|123
12-6-2012|144
13-11-2012|500
So afterwards I convert all ugly date strings into proper milliseconds in java and have the data, which I need.
any hint on what's wrong with the below query?
return new ItemPricesViewModel()
{
Source = (from o in XpoSession.Query<PRICE>()
select new ItemPriceViewModel()
{
ID = o.ITEM_ID.ITEM_ID,
ItemCod = o.ITEM_ID.ITEM_COD,
ItemModifier = o.ITEM_MODIFIER_ID.ITEM_MODIFIER_COD,
ItemName = o.ITEM_ID.ITEM_COD,
ItemID = o.ITEM_ID.ITEM_ID,
ItemModifierID = o.ITEM_MODIFIER_ID.ITEM_MODIFIER_ID,
ItemPrices = (from d in o
where d.ITEM_ID.ITEM_ID == o.ITEM_ID.ITEM_ID && d.ITEM_MODIFIER_ID.ITEM_MODIFIER_ID == o.ITEM_MODIFIER_ID.ITEM_MODIFIER_ID
select new Price()
{
ID = o.PRICE_ID,
PriceList = o.PRICELIST_ID.PRICELIST_,
Price = o.PRICE_
}).ToList()
}).ToList()
};
o in subquery is in read and I got the message "Could not find an implementation of the query pattern for source type . 'Where' not found."
I would like to have distinct ItemID, ItemModifier: should I create a custom IEqualityComparer to do it?
Thank you!
It seems like XPO it's not able to respond to this scenario. For reference this is what you could do with DbContext.
It sounds like maybe you want a GroupBy. Try something like this.
var result = dbContext.Prices
.GroupBy(p => new {p.ItemName, p.ItemTypeName)
.Select(g => new Item
{
ItemName = g.Key.ItemName,
ItemTypeName = g.Key.ItemTypeName,
Prices = g.Select(p => new Price
{
Price = p.Price
}
).ToList()
})
.Skip(x)
.Take(y)
.ToList();
Probable cause
In general, XPO does not support "free joins" in most of the cases. It was explicitelly written somewhere in their knowledgebase or Q/A site. If I hit that article again, I'll include a link to it.
In your original code example, you were trying to perform a "free join" in the INNER query. The 'WHERE' clause was doing a join-by-key, probably navigational, but also it contained an extra filter by "modifier" which probably is not a part of the definition of the relation.
Moreover, the query tried to reuse the IQueryable<PRICE> o in the inner query - what actually seems somewhat supported by XPO - but if you ever add any prefiltering ('where') to the toplevel 'o', it would have high odds of breaking again.
The docs state that XPO supports only navigational joins, along paths formed by properties and/or xpcollections defined in your XPObjects. This applies to XPO as whole, so XPQuery too. All other kinds of joins are called "free joins" and either:
are silently emulated by XPO by fetching related objects, extracting key values from them and rewriting the query into a multiple roundtrips with a series of partial queries that fetch full objects with WHERE-id-IN-(#p0,#p1,#p2,...) - but this happens only in the some simpliest cases
or are "not fully supported", meaning they throw exceptions and require you to manually split the query or rephrase it
Possible direct solution schemes
If ITEM_ID is a relation and XPCollection in PRICE class, then you could rewrite your query so that it fetches a PRICE object then builds up a result object and initializes its fields with PRICE object's properties. Something like:
return new ItemPricesViewModel()
{
Source = (from o in XpoSession.Query<PRICE>().AsEnumerable()
select new ItemPriceViewModel()
{
ID = o.ITEM_ID.ITEM_ID,
ItemCod = o.ITEM_ID.ITEM_COD,
....
ItemModifierID = o.ITEM_MODIFIER_ID.ITEM_MODIFIER_ID,
ItemPrices = (from d in o
where d.ITEM_ID.ITEM_ID == ....
select new Price()
.... .... ....
};
Note the 'AsEnumerable' that breaks the query and ensures that PRICE objects are first fetched instead of just trying to translate the query. Very probable that this would "just work".
Also, splitting the query into explicit stages sometimes help the XPO to analyze it:
return new ItemPricesViewModel()
{
Source = (from o in XpoSession.Query<PRICE>()
select new
{
id = o.ITEM_ID.ITEM_ID,
itemcod = o.ITEM_ID.ITEM_COD,
....
}
).AsEnumerable()
.Select(temp =>
select new ItemPriceViewModel()
{
ID = temp.id
ItemCod = temp.itemcod,
....
ItemPrices = (from d in XpoSession.Query<PRICE>()
where d.ITEM_ID.ITEM_ID == ....
select new Price()
.... .... ....
};
Here, note that I first fetch the item-data from server, and then conctruct the item on the 'client', and then build the required groupings. Note that I could not refer to the variable o anymore. In these precise case and examples, unsuprisingly, the second one (splitted) would be probably even slower than the first one, since it would fetch all PRICEs and then refetch the groupings through additional queries, while the first one would just fetch all PRICEs and then would calculate the groups in-memory basing on the PRICEs already fetched. This is not an a sideeffect of my laziness, but it is a common pitfall when rewriting the LINQ queries, so I included it as a warning :)
Both of these code examples are NOT RECOMMENDED for your case, as they would probably have very poor performace, especially if you have many PRICEs in the table, which is highly likely. I included them to present as only an example of how you could rewrite the query to siplify its structure so the XPO can eat it without choking. However, you have to be really careful and pay attention to little details, as you can very easily spoil the performance.
observations and real solution
However, it is worth noting that they are not that much worse than your original query. It was itself quite poor, since it tried to perform something near O(N^2) row-fetches from the table just to perform to group te rows by "ITEM_ID" and then formatting the results as separate objects. Properly done, it would be something like O(N lg N)+O(N), so regardless of being supported or not, your alternate attempt with GroupBy is surely a much better approach, and I'm really glad you found it yourself.
Very often when you are trying to split/simplify the XPQuery expressions as I did above, you implicitely rethink the problem and find an easier and simplier way to express the query that was initially not-supported or just were crashing.
Unfortunatelly, your query was in fact quite simple. For a really complex queries that cannot be "just rephrased", splitting into stages and making some of the join-filter work at 'client' is unavoidable.. But again, doing them on XPCollections or XPViews with CritieriaOperators is impossible too, so either we have to bear with it or use plain direct handcrafted SQL..
Sidenote:
Whole XPO has problems with "free joins", they are "not fully supported" not only in XPQuery, but also there's not much for them in XPCollection, XPView, CriteriaOperators, etc, too. But, it is worth noting that at least in "my version" of DX11, the XPQuery has very poor LINQ support at all.
I've hit many cases where a proper LINQ query was:
throwing "NotSupportedException", mostly in FreeJoins, but also very often with complex GroupBy or Select-with-Projection, GroupJoin, and many others - sometimes even Distinct(!) seemed to malfunction
throwing "NullReferenceExceptions" at some proper type conversions (XPO tried to interprete a column that held INT/NULL as an object..), often I had to write some completely odd and artificial expressions like foo!=null && foo.bar!=123 instead of foo = 123 despite the 'foo' being an public int Foo {get;set;}, all because the DX could not cope properly with NULLs in the database (because XPO created nullable-INT column for this property.. but that's another story)
throwing other random ArgumentException/InvalidOperation exceptions from other constructs
or even analyzing the query structure improperly, for example this one is usually valid:
session.Query<ABC>()
.Where( abc => abc.foo == "somefilter" )
.Select( abc => new { first = abc, b = abc } )
.ToArray();
but things like this one usually throws:
session.Query<ABC>()
.Select( abc => new { first = abc, b = abc } )
.Where ( temp => temp.first.foo == "somefilter" )
.ToArray();
but this one is valid:
session.Query<ABC>()
.Select( abc => new { first = abc, b = abc } )
.ToArray()
.Where ( temp => temp.first.foo == "somefilter" )
.ToArray();
The middle code example usually throws with an error that reveals that XPO layer were trying to find ".first.foo" path inside the ABC class, which is obviously wrong since at that point the element type isn't ABC anymore but instead a' anonymous class.
disclaimer
I've already noted that, but let me repeat: these observations are related to DX11 and most probably also earlier. I do not know what of that was fixed in DX12 and above (if anything at all was!).