Translate a SQL request to Laravel - sql

I have a complicate request that I hope translate with Eloquent ORM or with Query Builder for a Laravel Website, but I can't do this, particularly because of INNER JOIN and the double name on FROM
This is my SQL request
SELECT u.name,
u.photo,
m.*
FROM users u
INNER JOIN messages m ON u.id = m.useridsend
INNER JOIN (
SELECT useridsend,
MAX(created_at) AS created_at
FROM messages
GROUP BY useridsend
) r ON m.useridsend = r.useridsend
AND m.created_at = r.created_at
WHERE m.useridreceive=2
ORDER BY m.created_at DESC;

Here is my attempt at making your query into Eloquent syntax using Raw Expressions. Bear in mind this may not be correct as I haven't tested it, and your use of shorthand makes it awkward to build. You need a lot of raw queries in your code, and I assume the AND statement was for the inner join:
DB::selectRaw("u.name, u.photo, m.* from users u")
->joinRaw("messages m ON u.id = m.useridsend")
->joinRaw("(SELECT useridsend,
MAX(created_at) AS created_at
FROM messages
GROUP BY useridsend)
r ON m.useridsend = r.useridsend
AND m.created_at = r.created_at")
->whereRaw("m.useridreceive=2")
->orderBy('m.created_at', 'DESC')
->get();
Like I said, it might not be 100% correct, but I hope you get the idea of how to use raw queries. Using fewer shorthand names for tables might also make it easier to use standard Eloquent code.
EDIT
Also, could this not be simplified by taking advantage of Models? It looks like you're trying to get all messages sent to a user. With a User model defined as well as a Message model, you could take advantage of some Eager Loading techniques and use something like
User::where('id', '=', '2')->with('messages')->get();

Related

I have a huge but not complex sql query that must convert to django orm query

I have to convert the following sql query but i don't know how to convert it to equal query in django orm I would be very happy if you can :)))
select dialog_messages.*,
sender.first_name as sender_first_name,
sender.last_name as sender_last_name,
sender.cell_number as sender_cell_number,
sender.avatar_full_path as sender_avatar_full_path, receiver.first_name as receiver_first_name,
receiver.first_name as receiver_first_name,
receiver.last_name as receiver_last_name,
receiver.cell_number as receiver_cell_number, receiver.avatar_full_path as receiver_avatar_full_path from dialog_messages`` inner join user sender on ``sender``.``user_id`` = dialog_messages``.``sender_id`` inner join user receiver on receiver``.``user_id`` = ``dialog_messages``.``receiver_id`` where `dialog_id`` = ? order by ``dialog_messages``.``id`` desc
You should use select_related (and also look at prefetch_related). You can check the reference at:
select_related
prefetch_related
In your code, without knowing more about your models I think you could start with something like:
DialogMessage.objects.select_related('sender', 'receiver')

How to perform translation from RAW SQL to django queryset

I am struggling with conversion to django query having raw sql
I am new in django and any help will be appreciated
There are simple models:
Winemaker - target model
Wine
Post
Winemaker has 1+ Wines
Wine has 1+ Posts
I know that it should be done with annotations but have no idea how to implement it.
select w2.*,
(select count(wp.id)
from web_winemaker www
inner join web_wine ww on www.id = ww.winemaker_id
inner join web_post wp on ww.id = wp.wine_id
where
ww.status=20
and
wp.status=20
and
www.id = w2.id
) as wineposts_count,
(
select count(w.id)
from web_winemaker www1
inner join web_wine w on www1.id = w.winemaker_id
where
w.status=20
and www1.id = w2.id
) as wines_count
from web_winemaker w2;
You should be able to accomplish this with a Count aggregation expression in an annotate function. I took a guess at your related_name values on your relationship fields, so the following code may not plug in directly, but should give you an idea of how to do what you want.
from django.db.models import Count, Q
wine_makers = Winemaker.objects.annotate(
posts_count=Count(
'wine__post__id',
filter=Q(wines__status=20, wines__posts__status=20),
),
wines_count=Count(
'wines__id',
filter=Q(wines__status=20),
),
)
You may need to supply distinct=True depending on if you're crossing relationships.

Find_by_sql as a Rails scope

r937 from Sitepoint was kind enough to help me figure out the query I need to return correct results from my database.
What I need is to be able to use this query as a scope and to be able to chain other scopes onto this one.
The query is:
SELECT coasters.*
FROM (
SELECT order_ridden,
MAX(version) AS max_version
FROM coasters
GROUP BY order_ridden
) AS m
INNER JOIN coasters
ON coasters.order_ridden = m.order_ridden
AND COALESCE(coasters.version,0) = COALESCE(m.max_version,0)
I tried making a scope like so:
scope :uniques, lambda {
find_by_sql('SELECT coasters.*
FROM (
SELECT order_ridden,
MAX(version) AS max_version
FROM coasters
GROUP BY order_ridden
) AS m
INNER JOIN coasters
ON coasters.order_ridden = m.order_ridden
AND COALESCE(coasters.version,0) = COALESCE(m.max_version,0)')
}
But when I tried chaining another one of my scopes onto it, it failed. Is there a way I can run this query like a normal scope?
find_by_sql returns an Array. But you need an ActiveRecord::Relation to chain additional scopes.
One way to rewrite your query using ActiveRecord methods that will return an ActiveRecord::Relation would be to rearrange it a little bit so that the nesting happens in the INNER JOIN portion.
You may want to try something like:
scope :uniques, lambda {
max_rows = select("order_ridden, MAX(version) AS max_version").group(:order_ridden)
joins("INNER JOIN (#{max_rows.to_sql}) AS m
ON coasters.order_ridden = m.order_ridden
AND COALESCE(coasters.version,0) = COALESCE(m.max_version,0)")
}

Joining tables, counting, and group to return a Model

So I've got a SQL query I'd like to duplicate in rails:
select g.*
from gamebox_favorites f
inner join gameboxes g on f.gamebox_id = g.id
group by f.gamebox_id
order by count(f.gamebox_id) desc;
I've been reading over the rails Active Record Query Interface site, but can't quite seem to put this together. I'd like the query to return a collection of Gamebox records, sorted by the number of 'favorites' a gamebox has. What is the cleanest way to do this in rails?
I believe this will work (works on a similarly structured database locally), though I'm not sure I have the proper models in the proper spots for what you're trying to do, so you might need to move a coule things around:
Gamebox.joins(:gamebox_favorites).
group('"gamebox_favorites"."gamebox_id"').
order('count("gamebox_favorites"."gamebox_id")')
On the console, this should compile to (in the case of PostgreSQL on the back end):
SELECT "gameboxes".* FROM "gamebox_favorites"
INNER JOIN "gamebox_favorites"
ON "gamebox_favorites"."gamebox_id" = "gamebox"."id"
GROUP BY "gamebox_favorites"."gamebox_id"
ORDER BY count("gamebox_favorites"."gamebox_id")
...and I'm guessing that you don't want do just wrap it in a find_by_sql call, such as:
Gamebox.find_by_sql("select g.* from gamebox_favorites f
inner join gameboxes g
on f.gamebox_id = g.id
group by f.gamebox_id
order by count(f.gamebox_id) desc")

Inconsistent results between NHibernate Query and intended results

I have the following query in HQL :
public IEnumerable<Player> PlayersNotInTeam(Team team)
{
return Session.CreateQuery("from Player p where p.Sex = :teamSex and p.Visible and p.Id not in (select pit.Player from PlayerInTeam as pit join pit.Roster as roster join roster.Team as team where team = :teamId)")
.SetParameter("teamId", team.Id)
.SetParameter("teamSex", team.Sex)
.Enumerable<Player>();
}
When I run this query with NHibernate, it will return 2 rows.
If I run the SQL script generated by NH in my database browser (SQLite Explorer):
select player0_.Id as Id26_, player0_.Sex as Sex26_, player0_.FirstName as FirstName26_, player0_.LastName as LastName26_, player0_.DefaultNumber as DefaultN5_26_, player0_.Visible as Visible26_, player0_.DefaultPosition_id as DefaultP7_26_
from Players player0_
where player0_.Sex='Male'
and player0_.Visible=1
and (player0_.Id not in
(select playerinte1_.Player_id
from "PlayerInTeam" playerinte1_
inner join "Roster" roster2_ on playerinte1_.Roster_id=roster2_.Id
inner join Teams team3_ on roster2_.Team_id=team3_.Id,
Players player4_
where playerinte1_.Player_id=player4_.Id
and team3_.Id=2));
I have 3 rows, which is what I should have.
Why are my results different?
Thanks in advance
Mike
I have noticed that sometimes the logged SQL is not exactly the same as the one being really used against the database. The last time I had this issue, it was a problem with trimming the Id value, e.g., where the generated SQL has something like and team3_.Id=2, the SQL being used was actually and team3_.Id='2 ' (or perhaps, player_0.Sex='Male '), which would always fail.
I would suggest you try this HQL:
string hql = #"from Player p where p.Sex = 'Male'
and p.Visible and p.Id not in
(select pit.Player from PlayerInTeam as pit join pit.Roster as roster join roster.Team as team where team = 2)";
return Session.CreateQuery(hql).Enumerable<Player>();
If that works, you need to check if your values have spare whitespaces in them.
I've changed my query like this:
return Session.CreateQuery("from Player p where p.Sex = :teamSex and p.Visible and not exists (from PlayerInTeam pit where pit.Player = p and pit.Roster.Team = :teamId)")
.SetParameter("teamId", team.Id)
.SetParameter("teamSex", team.Sex)
.Enumerable<Player>();
And it now works. I had the idea to use "not exists" after I changed my mappings to try to use LINQ, which gave me the hint.
If you ask why I don't keep LINQ, that's because currently I hide the relationships between my entities as private fields, to force the users of the entities to use the helper functions which associate them. But the wrong thing is that in most cases, that forbids me to use LINQ in my repositories.
But I'm wondering if this wouldn't be better to "un-hide" my relationships and expose them as public properties, but keep my helper functions. This would allow me to use LINQ in my queries.
What do you do in your apps using NH?
Do you think this would be an acceptable trade-off to maintain easy mappings and queries (with the use of LINQ), but with the cost of some potential misuses of the entities if the user doesn't use the helper functions which keep the relationships?