SQL Nested Inner Joins - mysql

Im trying to use the results of an inner join in another query and having trouble getting my head around how.
This is the first query i am running:
SELECT projects.Project_ID, projects.Name
FROM projects
INNER JOIN assigned_users
ON assigned_users.Project_ID=projects.Project_ID AND assigned_users.User_ID=4;
This is getting all of the assigned projects for a particular user. The Project_ID's this query returns i want to use to find all the related requirements for those projects.
SELECT *
FROM requirements
WHERE requirements.Project_ID=1;
So instead of finding the requirements for project '1' i want to get the requirements for all projects assigned to a particular user. Any help would be appreciated.
Cheers

If I understand correctly, you would just add another JOIN:
SELECT . . .
FROM assigned_users au JOIN
projects p
ON au.Project_ID = p.Project_ID JOIN
requirements r
ON r.Project_ID = p.Project_ID
WHERE au.User_ID = 4;

To the existing query, we can just add:
JOIN requirements
ON requirements.Project_ID = projects.Project_ID
We add expressions to the SELECT list to retrieve values of columns from requirements.
SELECT projects.Project_ID, projects.Name
, requirements.some_column
, requirements.some_other_column
It's likely that we also want to add an ORDER BY clause so that the rows are returned in a predictable sequence.
Note that if there are no matching rows in requirements for a given Project_ID, then that project will not be returned. To return those rows, we can specify an outer join.
Current query:
SELECT projects.Project_ID
, projects.Name
FROM projects
JOIN assigned_users
ON assigned_users.Project_ID=projects.Project_ID
AND assigned_users.User_ID=4
Proposed query with outer join to requirements table:
SELECT projects.Project_ID
, projects.Name
, requirements.Requirement_ID
, requirements.Requirement_Name
FROM projects
JOIN assigned_users
ON assigned_users.Project_ID=projects.Project_ID
AND assigned_users.User_ID=4
LEFT
JOIN requirements
ON requirements.Project_ID = projects.Project_ID
ORDER
BY projects.Project_ID
, requirements.Requirement_ID
Equivalently, we could relocate the condition assigned_users.User_ID=4 from the ON clause of the inner join to a WHERE clause, before the ORDER BY.

You can use either:
SELECT *
FROM requirements req
INNER JOIN projects pro
ON req.Project_ID = pro.Project_ID
INNER JOIN assigned_users u
ON u.Project_ID=pro.Project_ID
WHERE u.User_ID=4;
or
SELECT *
FROM requirements
WHERE requirements.Project_ID=(
SELECT Project_ID
FROM projects
INNER JOIN assigned_users
ON assigned_users.Project_ID=projects.Project_ID AND assigned_users.User_ID=4;
);

Related

to get different columns from single query

Consider the data about projects and members stored in tables below.

Projects(id, title)
Members(id, name, project_id)

Generate a report to list all the projects, members working on them. Also list the projects that do not have any employees assigned yet and also the employees who are available as free resources.
Table-
Projects(id, title)
Members(id, name, project_id)
can someone optimize the query as i applied outer join and i got all answers together.i need to separate the columns as per required question.
Select p.title, m.id
From projects p FULL OUTER JOIN
Members m
where p.id = m.project_id;
MySQL does not support full join. So do this in two steps:
Select p.title, m.id
From projects p LEFT JOIN
Members m
ON p.id = m.project_id
union all
select null, m.id
from members m
where not exists (select 1 from projects p where p.id = m.project_id);

GROUP_CONCAT(SELECT * FROM table) is something like this possible?

So I'd like to join two tables using an association table because table 'a' connects to multiple rows in table 'b', and I'd like to get all the results from each table that matches my a.value but the values from table 'b' should be concatenated somehow.
Right now my query looks like this:
SELECT *,
GROUP_CONCAT(DISTINCT g.group_name) group_name,
GROUP_CONCAT(DISTINCT g.group_profile_id) group_profile_id,
GROUP_CONCAT(DISTINCT g.group_publications) group_publications,
GROUP_CONCAT(DISTINCT g.group_followers) group_followers,
GROUP_CONCAT(DISTINCT g.group_ongoing_projects) group_ongoing_projects,
GROUP_CONCAT(DISTINCT g.group_finished_projects) group_finished_projects,
GROUP_CONCAT(DISTINCT g.group_members) group_members
FROM projects_groups pg
LEFT JOIN projects p on p.projectid = pg.projectid
RIGHT JOIN groups g on g.groupid = pg.groupid
WHERE p.projectid IN ($projectIds)
GROUP BY p.projectid
The problem is that I'm not even selecting the half of the columns of the groups table but I'd like to get all of them. I could write down all the columns like above, but it looks really ugly and also i'd have to modify this every time I alter my table.
To further explain the issue a project can connect to multiple groups, and I'd like to get the project data with all the data of its groups. I could query the groups separately but that doesn't seem logical, cause i'd have to do it for each project (e.g. for 100 projects). So i get all the projects in one query and then a query for each project to get its groups. Or I could get the projects in one query joined with the association table and then get the ids from the association table and make a second query using these ids to get all the groups through the association, but I'm looking for a simpler solution.
Pity there is no sample data nor expected result included with this question, however there are a few syntax issues worth mentioning. You start your FROM clause with this:
FROM projects_groups pg
LEFT JOIN projects p on p.projectid = pg.projectid
This allows all rows from projects_groups even if there is no associated project. If there is no associated project then all projects.* columns would be NULL. However in the where clause you require this: WHERE p.projectid IN ($projectIds) which means that any NULLs from the projects table would be ignored and hence that LEFT JOIN is useless.
So as the projects seems to be the primary concern, use it with FROM and then join to the other tables appropriate to your needs. Now my guess is you can have a project without a project group (even if only temporarily) so you might use a left join here and so the query may look like this
FROM projects p
LEFT JOIN projects_groups pg on p.projectid = pg.projectid
WHERE p.projectid IN ($projectIds)
but note you would only do that if you wanted to list projects even if they have no associated project groups. So making the assumption you do need that then continue this left join to groups as well:
FROM projects p
LEFT JOIN projects_groups pg on p.projectid = pg.projectid
LEFT JOIN groups g on g.groupid = pg.groupid
WHERE p.projectid IN ($projectIds)
If the assumption is wrong, then it will be more efficient to use inner joins:
FROM projects p
INNER JOIN projects_groups pg on p.projectid = pg.projectid
INNER JOIN groups g on g.groupid = pg.groupid
WHERE p.projectid IN ($projectIds)
Now we need to look at the SELECT & GROUP BY clauses. MySQL has historically allowed a very non-standard GROUP BY syntax and the default settings allowed a query like yours where only one column is listed to GROUP BY.
e.g. in the past this was allowed:
select p.* from projects p group by p.id
This is very bad practice and now current versions of MySQL now default to standard SQL syntax. Under standard SQL syntax rules you MUST SPECIFY every "non-aggregating column" in the group by clause. and so the example immediately above would produce a syntax error
e.g. you should always be precise about the group by columns
select p.id, p.name, count(*) from projects p group by p.id, p.name
So to help avoid syntax errors you might prefer to use a "derived table" like this:
SELECT
p.*
, d.*
FROM projects p
INNER JOIN (
SELECT
p.projectid
, GROUP_CONCAT(DISTINCT g.group_name) group_name
, GROUP_CONCAT(DISTINCT g.group_profile_id) group_profile_id
, GROUP_CONCAT(DISTINCT g.group_publications) group_publications
, GROUP_CONCAT(DISTINCT g.group_followers) group_followers
, GROUP_CONCAT(DISTINCT g.group_ongoing_projects) group_ongoing_projects
, GROUP_CONCAT(DISTINCT g.group_finished_projects) group_finished_projects
, GROUP_CONCAT(DISTINCT g.group_members) group_members
FROM projects p
LEFT JOIN projects_groups pg on p.projectid = pg.projectid
LEFT JOIN groups g on g.groupid = pg.groupid
WHERE p.projectid IN ($projectIds)
GROUP BY
p.projectid
) d on p.projectid = d.projectid

MySQL JOIN tables with COUNT values

I have the following tables in my database.I only listed the important columns which can be used for joining.
I need to get the following output
Currently I'm using two seperate queries for each COUNT value
For assigned licenses
select
products.id,products.name,COUNT(assigned_licenses.id)
from
deployment_users
inner join
assigned_licenses
on
deployment_users.id = assigned_licenses.deployment_user_id
inner join
products
on
assigned_licenses.id = products.id
and
deployment_users.customer_id = 10
group by
assigned_licenses.id
;
For total licenses
select
products.id,products.name,COUNT(total_licenses.id)
from
customers
inner join
total_licenses
on
customers.iccode = licenses.iccode
inner join
products
on
total_licenses.id = products.id
and
customers.id = 10
group by
total_licenses.id
;
Since there are more than a 1,000 products that need to be listed,I want to combine them into a single query.How can I do that?
Your specification leaves some room for interpretation (e.g. can a user have assigned licenses without total licenses? if yes my query will fail.) but I would go with this.
SELECT
products.id,
products.name,
Count(Distinct total_licenses.id) As CountTotalLicenses,
Count(Distinct assigned_liceses.deployment_users_id) As CountAssignedLicenses
FROM products
LEFT JOIN total_licenses ON total_licenses.products_id = products.id
LEFT JOIN customers ON customers.iccode = total_licenses.customers_iccode
LEFT JOIN assigned_licenses ON assigned_liceses.total_licenses_id = total_licenses.id
WHERE
customers.id = 10
GROUP BY
products.id,
products.name
For the future it would be awesome if you could paste code as code and not as an image. People cannot simple copy paste snippets of your code and have to type everything again...
Try joining Both of your query
SELECT * FROM (
(First Query) as assigned_licn
INNER JOIN
(Second Query) as total_licn
USING (id)
);

join nested queries in from clause

Can you tell me what I need to manipulate in this query to get it working?
select C.ID from
(select A.ID from CUSTOMERS A inner join PROFILES B on A.ID=B.ID where CTR='67564' and CST_CD in
('G','H')) as C
inner join
(select ID from RELATION_CODES where R_CD='KC') as R
on C.ID=R.ID
The individual inner queries are working just fine and giving correct results, not sure what is the problem with inner join in from clause..
Not completely sure I'm understanding your question, but this should be able to be rewritten without the subqueries:
select c.id
from customers c
join profiles p on c.id = p.id
join relation_codes rc on rc.id = c.id
where ctr = '67564'
and cst_cd in ('G','H')
and rc.r_cd = 'KC'
If this isn't working, please provide your table structure and sample data and expected results. This should get you pretty close though.
I have to ask, is the id field in the relation_codes table and the profiles table the same as the id in the customers table. Perhaps you need to identify how your tables are related.
A Visual Explanation of SQL Joins

Combining join results with an at least function

I'm new to SQL and have managed to pick up the basic functions capably enough, however I'm now trying to find the people with at least two tokens from the results of an inner join:
SELECT
users.[First Name],
users.[Last Name],
IssuedTokens.UserID,
IssuedTokens.TokenID,
Tokens.TokenType
FROM IssuedTokens
INNER JOIN users ON users.ID = IssuedTokens.UserID
INNER JOIN Tokens ON Tokens.number = IssuedTokens.TokenID
GROUP BY IssuedTokens.UserID
HAVING COUNT(*) >= 2
ORDER BY IssuedTokens.UserID
This gives the error:
Column 'Users.First Name' is invalid in the select list because it is
not contained in either an aggregate function or the GROUP BY clause.
I'm comfortable using functions on pre-existing tables, but have not seen how to manipulate the results of a join. If anyone could help it would be much appreciated.
You can do a separate aggregation -- before the join -- to get the users with multiple tokens. Then, the rest of the query doesn't need an aggregation:
SELECT u.[First Name], u.[Last Name], u.UserID, it.TokenID, t.TokenType
FROM IssuedTokens it INNER JOIN
users u
ON u.ID = it.UserID INNER JOIN
Tokens t
ON t.number = it.TokenID INNER JOIN
(SELECT it.UserId
FROM IssuedTokens it
GROUP BY it.UserId
HAVING COUNT(*) >= 2
) itu
ON itu.UserId = it.UserId
ORDER BY it.UserID;