Need a more efficient join query - mysql

It's been a long time since I last did something with database so my knowledge has beenyet rusted. I have 2 SQL tables:
data(id, attr);
dependency(child, parent);
#**child** and **parent** are the id from table **data**
I need to query all the attr corresponding to the entries in table dependency. Following is my attempt:
SELECT
(SELECT data.attr FROM data WHERE data.id = child) AS child_attr,
(SELECT data.attr FROM data WHERE data.id = parent) AS parent_attr
from dependency;
It works but very slow. I'm sure there's a better way to do it with join query but cannot come up with it yet.
Can someone please help?
Thanks,

You could join the dependency table to the data table twice to get the information you need:
SELECT d1.attr AS ChildAttr, d2.attr AS ParentAttr
FROM dependency AS dep
INNER JOIN data AS d1 ON dep.child = d1.id
INNER JOIN data AS d2 ON dep.parent = d2.id

try this:
SELECT t2.attr, t3.attr
FROM dependency as t1
INNER JOIN data as t2 on t1.child = t2.id
INNER JOIN data as t3 on t1.parent = t3.id

Related

Alternative for Subquery Other Than a View

Thanks for looking at my post, any help/guidance is appreciated. My SQL skills are lacking and I have tried several solutions without success. Anyway, I need to create a VIEW for the following query:
CREATE VIEW open_orders AS
SELECT
t1.orderID,
DATE_FORMAT(t1.orderDate,'%m-%d-%Y') AS orderDate,
t6.colorName,
t1.originID,
t1.rackNumber,
t2.locationNumber AS originNumber,
t2.locationName AS originName,
t3.locationName AS destinationName,
t4.locationStatusName,
COUNT(t5.orderID) AS totalCount
FROM `order` AS t1
JOIN `location` AS t2 ON t1.originID = t2.locationID
JOIN `location` AS t3 ON t1.destinationID = t3.locationID
JOIN `locationStatus` AS t4 ON t1.locationStatusID = t4.locationStatusID
LEFT JOIN (SELECT * FROM `orderItem` WHERE `productStatusID` = 02 OR `productStatusID` = 03) AS t5 ON t1.orderID = t5.orderID
JOIN `color` AS t6 ON t1.requestedColorID = t6.colorID
WHERE t1.orderStatusID = 01
GROUP BY t1.orderID
ORDER BY t1.orderDate DESC, t1.orderID DESC;
The problem is with the subquery. Because I can't use a subquery within the FROM statement I attempted to use a VIEW. However, the table is large and this approach causes too much of a performance issue.
I'm sure there is a way I can accomplish this without using a VIEW or subquery but am having trouble coming up with a solution.
Any help/guidance is appreciated.
You don't need a subquery.
...
LEFT JOIN orderItem AS t5
ON t5.orderID = t1.orderID
AND t5.productStatusID IN (02,03)
JOIN color ...
This does the same thing as your query, but more efficiently since it avoids the derived table.

Joining 1 table twice in the same SQL query

I have joined 1 table twice on the same query, I keep getting error messages that the 'FROM clause have same exposed names. Even using AS does not seem to work, any ideas or suggestions?
here is the query I am using;
select Contact.*, PERSON.*, address.*
from address
full join Contact
on address.uprn = Contact.uprn
full join PERSON
on Contact.contactno = PERSON.contact
full join address
on address.uprn = PERSON.driveruprn
select Contact.*, PERSON.*, a1.*, a2.*
from address a1
full join Contact
on a1.uprn = Contact.uprn
full join PERSON
on Contact.contactno = PERSON.contact
full join address a2
on a2.uprn = PERSON.driveruprn
, however there is no full join in mysql, workaround
select * from t1
left join t2 ON t1.id = t2.id
union
select * from t1
right join t2 ON t1.id = t2.id
You have to alias the second and subsequent usages of a table:
select ...
from address <---first usage
join contact ...
join person ...
join address AS other_address ... <---second usage
^^^^^^^^^^^^^^^^
Doesn't really matter exactly where you do the aliases, but if you use a single table multiple times, all but ONE of those usages have to have unique aliases.
This is probably because you have same field name in different table
change it like this to make sure fieldnames are unique
SELECT
Contact.field1 as c_field1, Contact.field2 as c_field2 ...,
PERSON.field1 as p_field1, PERSON.field2 as p_field2 ...,
address.field1 as a_field1, address.field2 as a_field2 ...
You need to use a separate alias on each of the address table references in your query to avoid the error you are seeing:
SELECT Contact.*, PERSON.*, a1.*, a2.*
FROM address a1 INNER JOIN Contact ON a1.uprn = Contact.uprn
INNER JOIN PERSON ON Contact.contactno = PERSON.contact
INNER JOIN address a2 ON a2.uprn = PERSON.driveruprn
By the way, there is no FULL JOIN in MySQL, so I have replaced them with INNER JOIN which is likely what you had in mind.

SQL Get Order by 2 date colums when join 3 tables

My tables:
T1 = Projects
T2 = bid_details
T3 = bid_submission_details
T4 = quote_submission_details
This is how Data flow Works:
SQL Code:
"SELECT *,T3.bidsubmit_date,T4.Quotesubmit_date FROM `Projects` T1
LEFT JOIN `bid_details` T2 ON(T2.proj_reff = T1.proj_reff)
LEFT JOIN `bid_submission_details` T3 ON(T3.bid_reff = T2.bid_reff)
LEFT JOIN `quote_submission_details` T4 ON(T4.proj_reff = T1.proj_reff)
ORDER BY T3.bidsubmit_date,T4.Quotesubmit_date ASC";
Result View:
I have tried many ways to ORDER BY the submission date. but nothing worked. In the result view blue highlighted row is 2014 dated but it not going at the top of the list when I Order by Ascending order.
It always Orders the result from Quote Submission table first and then Order the result from Bid Submission table. Project types can be seen the in the result view.
i want a way to get Order by submission date no matter what type of project it is!
using COALESCE() function to the filed from the other three tables together.
SELECT *,T3.bidsubmit_date,T4.sub_date,
COALESCE(T3.bidsubmit_date,T4.sub_date) AS SubmiDates
FROM `$SQLTable` T1
LEFT JOIN `quote_submission_details` T4 ON(T4.pro_ref_no = T1.ref_no)
LEFT JOIN `bid_details` T2 ON(T2.pro_ref_no = T1.ref_no)
LEFT JOIN `bid_submission_details` T3 ON(T3.bid_ref_no = T2.bid_ref_no)
ORDER BY SubmiDates ASC";
after many very much goggling found a solution !!!

MySQL query with joins on a table where second table name comes from a column in the first table

I think my title says it all, but in essence, this is what I want to do:
SELECT t1.*, t2.friendly_name, CONCAT_WS(" ",t3.name,t3.surname) AS user FROM activity
LEFT JOIN t1.typedb AS t2 ON t1.typeid = t2.id
LEFT JOIN users AS t3 on t1.loginid = t2.loginid
ORDER BY time DESC, user ASC
But as you can imagine, this will give me an error.
I can do a normal select on the activity db and then do a loop in php and run queries to fetch the info. But there has to be a way to do this in one query in MYSQL.
Please help.
So there is a table name in typedb? Then no, SQL doesn't support this. This is not how a relational database is supposed to work.
You can try something along the lines of
SELECT
t1.*,
coalesce(x1.friendly_name, x2.friendly_name, x3.friendly_name) as friendly_name,
CONCAT_WS(" ",t3.name,t3.surname) AS user
FROM activity t1
LEFT JOIN tableX AS x1 ON t1.typeid = x1.id and t1.typedb = 'TABLEX'
LEFT JOIN tableY AS x2 ON t1.typeid = x2.id and t1.typedb = 'TABLEY'
LEFT JOIN tableZ AS x3 ON t1.typeid = x3.id and t1.typedb = 'TABLEZ'
LEFT JOIN users AS t3 on t1.loginid = coalesce(x1.loginid,x2.loginid,x3.loginid)
ORDER BY time DESC, user ASC;
But this is not very efficient. It's just not what SQL is made for. So use a programming language and build dynamic SQL, or even better: change your database design.

Retrieving the last filtered record in each group

I read a while back this excellent answer by #Bill Karwin:
https://stackoverflow.com/a/1313293/317889
This pretty much answers the question however, I have recently had to update my query to filter on the joined tables status.
I have written two queries below, similar to the queries in the post above. The first query which is the slow one works with the joined tables status filtering:
SELECT m.*, t1.* FROM mood m
LEFT JOIN temper t ON ( m._id = t.mood_id )
WHERE grantee_username = "username"
AND m.status_id != 1 // NOT INTERESTED IN THIS FILTER
AND t.status_id != 1 // FILTERING
GROUP BY m._id;
With the second query I have no idea how to add the filtering to get it to work as above:
SELECT m.*, t1.* FROM mood m
LEFT JOIN temper t1 ON ( m._id = t1.mood_id )
LEFT JOIN temper t2 ON ( t1.mood_id = t2.mood_id AND t1._id < t2._id )
WHERE t2._id IS NULL
AND m.grantee_username = "username"
AND m.status_id != 1; // NOT INTERESTED IN THIS FILTER
The first query works perfectly but is deemed to be slower than the second query.
The second query works at brining back all mood records with their relating last temper record however that last temper record may have a status of 1 which I don't want.
Any insight would be of interest. I could always just go with the first query but for the sake of performance I would like to figure out how to add the t.status_id filtering to the second query if possible.
I think your second query is missing the GROUP BY at the end.
This version adds the filter in the subquery:
SELECT m.*, t1.*
FROM mood m LEFT JOIN
(select t.*
from temper t
where t.status_id != 1
) t1
ON m._id = t1.mood_id LEFT JOIN
temper t2
ON t1.mood_id = t2.mood_id AND t1._id < t2._id
WHERE t2._id IS NULL AND
m.grantee_username = "username"
GROUP BY m._id;
Do you also want the filter on t2?
By the way, you are using a feature in MySQl called Hidden Columns -- you are aggregating on one column but returning rows, with no aggregation functions, on other columns. This feature is only in MySQL.
Ok, works out that it wasn't too dificult after all:
SELECT m.*, t1.* FROM mood m
LEFT JOIN temper t1 ON ( m._id = t1.mood_id AND t1.status_id !=1)
LEFT JOIN temper t2 ON ( t1.mood_id = t2.mood_id AND t1._id < t2._id AND t2.status_id !=1 )
WHERE t2._id IS NULL
AND m.grantee_username = "username"
AND m.status_id != 1; // NOT INTERESTED IN THIS FILTER
The filter (status_id) needs to be added to each JOIN.