Mysql query to proper Laravel $query - mysql

I have this logic query that doesn't work because I need to Join like 4 different tables, which is insane but please help me out, I will find a better way in the future.
select * from approvals
where approvable_type =
(select model from permission_configs
where variable = (
select permission_slug from role_permission
where role_id = (
select role_id from role_user
where user_id = approvals.user_id) ) )
Please give me the above query in Eloquent with multiple join! I will forever be grateful to you.

You could refactor your query using inner join instead of where and subquery
select *
from approvals a
INNER JOIN permission_configs p ON a.approvable_type = p.model
INNER JOIN role_permission r ON p.variable = r.permission_slug
INNER JOIN role_user u ON r.role_id = u.role_id
WHERE u.user_id = a.user_id
once done, you could take a look at Eloquent for join

Related

Combining select queries

I am working with a MySQL database. I am suppose to combine three select queries, to "improve performance". Each select below is dependent on the previous ID retrieved.
So far, I've tried the following...
# multiple select from tables
select user.name, group.ID
from user as u, group as g
where u.name = <name_here>
# inner join...
select user.ID, group.ID,
from user
inner join group
on user.ID = group.ID
I need to select the user.name and group.ID based on a username param. Is there a way to query this data in a single statement?
I don't know if I understand your need, lets try:
Try to use this query:
select pGroupMatch.GroupID, ProfileData.ID
from pUserMatch
inner join pGroupMatch on pGroupMatch.GroupID = pUserMatch.GroupID
inner join ProfileData on ProfileData.id = pGroupMatch.ProfileID
where pUserMatch.username = "<username>";
Check if you can create indexes for improve your query, if you can try it:
CREATE INDEX idx_pUserMatch_01 ON pUserMatch (GroupID);
CREATE INDEX idx_pGroupMatch_01 ON pGroupMatch (ProfileID);
Please use join for your requirement. Please try below query
select t3.* from Profiles.pUserMatch t1
left join Profiles.pGroupMatch t2 ON t2.GroupID=t1.GroupID
left join Profiles.ProfileData t3 ON t3.ID=t2.ProfileID
where t1.username = "<username>";
I hope above query will help you.Please feel free to comment. Thanks.
This is the query you get by joining the tree queries you already have:
SELECT pd.*
FROM Profiles.ProfileData pd
# ... where ID = "<profile_id>", profile_id = select ProfileID from ...
INNER JOIN Profiles.pGroupMatch pm ON pd.ID = pm.ProfileID
# ... where GroupID = "<group_id>", group_id = select GroupID from ...
INNER JOIN Profiles.pUserMatch pu ON pm.GroupID = pm.GroupID
WHERE pm.username = "<username>"
I put in comments the fragments of your queries that gets converted to JOIN subclauses.
Read more about the syntax of the JOIN subclause of the SELECT statement.
You don't need foreign keys to join stuff:
select p.* from Profiles.pUserMatch u
join Profile.pGroupMatch g on u.GroupID = g.GroupID
join Profile.ProfileData p on g.ProfileID = p.ID
where u.username = ?

MYSQL: Using a join after and AND

the MYSQL query below combines a number of tables. However, as you can see, I would like to add a LEFT JOIN at the end on the receipt table. The query returns an error when I add the LEFT JOIN. Anybody know the best way to LEFT JOIN the receipt table to the rest of the query. Sorry if this is a newbie question. Thanks !!
SELECT user_name, expense_category, merchant_name, expense_cost, expense_date, expense_status, receipt_image, expense_comment
FROM users, expenses, merchants, receipts
WHERE ".$adminId." = expenses.admin_id
AND expenses.user_id = users.user_id
AND expenses.merchant_id = merchants.merchant_id
AND LEFT JOIN (receipts)
ON expenses.receipt_id = receipts.receipt_id
Here is a clean approach of doing it, note that I have added alias for the tables for better readability so you may use the alias name in the select statement to fetch the column from the proper table.
SELECT
u.user_name,
ex.expense_category,
mer.merchant_name,
ex.expense_cost,
ex.expense_date,
ex.expense_status,
re.receipt_image,
ex.expense_comment
FROM users u
JOIN expenses ex on ex.user_id = u.user_id
JOIN merchants mer on mer.merchant_id = ex.merchant_id
LEFT JOIN receipts re on re.receipt_id = ex.receipt_id
where
ex.admin_id = '$adminId'
Try this,
SELECT user_name, expense_category, merchant_name, expense_cost, expense_date, expense_status, receipt_image, expense_comment
FROM users, expenses, merchants, receipts
LEFT JOIN receipts ON expenses.receipt_id = receipts.receipt_id
WHERE ".$adminId." = expenses.admin_id
AND expenses.user_id = users.user_id
AND expenses.merchant_id = merchants.merchant_id
Use join clauses instead of where clause. I.e.
SELECT user_name, expense_category, merchant_name, expense_cost, expense_date, expense_status, receipt_image, expense_comment
FROM users
INNER JOIN expenses on users.user_id = expenses.expenses_id
INNER JOIN merchants on merchants.merchant_id = expenses.merchant_id
LEFT JOIN (receipts)
ON expenses.receipt_id = receipts.receipt_id
WHERE ".$adminId." = expenses.admin_id
Note that any columns from the receipts will be NULL in the select statement whenever there's no matching record.

Select Query based on values in result set

Is there anyway to select all from 1 table based on the result of one query which contains multiple values without having to do 2 separate queries?
Say long join query will produce a list of id's
SELECT xyz FROM table long join query WHERE id = array of ids found in result table
added example:
SELECT * FROM tweets as t
where t.user_id
in(
SELECT uff.id, uff.username
FROM users as uf
LEFT JOIN followlinks as fl
ON uf.id = fl.user_id
LEFT JOIN users as uff
ON fl.follow_id = uff.id
WHERE uff.id = 1
)
The bit in the parenthesis returns an id and user name of who the user is following (uff.id=1)
How do i then get all 'tweets' by all the id's in the generated resultset
You can use subquery:
SELECT * FROM `table1` WHERE `id` IN (SELECT `table2`.id FROM `table2` )
You might want to check documentation for syntax
SELECT xyz FROM table_A join table_B WHERE table_A.id IN (SELECT ID FROM table_C);
I think you mean something like
edited after the OP edit
SELECT * FROM tweets as t
WHERE t.user_id
in(
SELECT uff.id //remove the second field, you just need the id
FROM users as uf
LEFT JOIN followlinks as fl
ON uf.id = fl.user_id
LEFT JOIN users as uff
ON fl.follow_id = uff.id
WHERE uff.id = 1
)
After trying the in clause I coudnt get the results I was after but after rethinking what I was trying to do I got my results with an additional join clause
SELECT uff.username, t.content
FROM users as uf
JOIN followlinks as fl
ON uf.id = fl.user_id
JOIN users as uff
ON fl.follow_id = uff.id
JOIN tweets as t
ON t.user_id = uff.id
WHERE uf.id = 1

MySql database selecting count(column) using inner joins

I have three tables
USER : idUser, Username
USERLOCATION : idUser, idLocation
SESSION : idUser, idSession
What I want to find is all the users that are from a particular location and count how many sessions they have had. I'm nearly there with this SQL
SELECT u.idUser, u.Username, s.idSession
FROM rempad.User u
INNER JOIN rempad.UserLocation l ON u.idUser = l.idUser
INNER JOIN rempad.Session s ON u.idUser = s.idUser
WHERE l.idLocation = 12
This returns all the users belonging to a particular location and all the session ids. Where I am stuck is that I really want to be able able to count the the sessions for each user.
I've tried...
SELECT u.idUser, u.Username, COUNT(s.idSession) as SessionCount
but this returns only a single row and counts all the sessions in the session table rather than counting the sessions that belong to each individual user at that location.
Do I need to do a nested SELECT statement? I'm not really sure how to go about writing the query.
Any help much appreciated.
L
Try this:-
SELECT u.idUser, u.Username, count(s.idSession) as x
FROM rempad.User u
INNER JOIN rempad.UserLocation l ON u.idUser = l.idUser
INNER JOIN rempad.Session s ON u.idUser = s.idUser
WHERE l.idLocation = 12
GROUP BY u.iduser,
u.username
I believe it would be better to use Group by along with the above
SELECT u.iduser,
u.username,
Count(s.idsession) AS x
FROM USER u
INNER JOIN userlocation l
ON u.iduser = l.iduser
INNER JOIN session s
ON u.iduser = s.iduser
WHERE l.idlocation = 12
GROUP BY u.iduser,
u.username

Facing problems in multiple table joins

There are 4 tables.
items ( item_id, item_name, item_owner)
groups ( grp_id, grp_name, grp_owner)
users (grp_id, usr_ref)
share (item_id, grp_id)
My objective is to get a list of all those items where item_owner = user_id ( say 123 ) or user_id belongs to a group with which the item is shared.
A basic query implementation to retrieve all items shared with a group to which a particular user_id belongs would be
select i.item_id from items i
left outer join share on share.item_id = i.item_id
left outer join users on users.grp_id = share.grp_id
left outer join groups on groups.grp_id = share.grp_id
where users.usr_ref = user_id
And to include all other elements of which user_id is the owner, i did something like
select * from items where owner = user_id or item_id in (
select i.item_id from items i
left outer join share on share.item_id = i.item_id
left outer join users on users.grp_id = share.grp_id
left outer join groups on groups.grp_id = share.grp_id
where users.usr_ref = user_id )
which i suppose is a very bad implementation as the item_id needs to be searched everytime in the array obtained from the joins. How can i improve my sql statement.
Also is there any other way in which i can redesign my table structure so that i can implement the query in some other way ?
Thanx in advance.
You need INNER JOIN in this case because you need to get an item that has connection on all tables. Your current query uses LEFT JOIN that is why even an item that has not associated on any user will be shown on the list. Give this a try,
SELECT DISTINCT a.*
FROM items a
INNER JOIN `share` b
ON a.item_ID = b.item_ID
INNER JOIN groups c
ON b.grp_ID = c.grp_ID
INNER JOIN users d
ON c.grp_ID = d.grp_ID
WHERE d.usr_ref = user_ID
To further gain more knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins
Perhaps I'm not understanding your question, but can you not just use OR with your first query:
select i.item_id from items i
left outer join share on share.item_id = i.item_id
left outer join users on users.grp_id = share.grp_id
left outer join groups on groups.grp_id = share.grp_id
where i.item_owner = #user_id or users.usr_ref = #user_id
I think this will work.
select i.item_id from items i
inner join share on share.item_id = i.item_id
inner join users on users.grp_id = share.grp_id
inner join groups on groups.grp_id = share.grp_id
where (users.usr_ref = #user_id or #user_id is null) and (i.item_id = #item_id or #item_id is null)
I'm guessing that you will always pass one paramether or the other one, not both, so the other one (the non-passed) will be null
also, why are you using left join? use inner instead, because you don't want null fields