I've read many questions about joining tables where the column value is used as a table name but I do not know how to implement it on my case.
I have multiple tables. First Table is user.
id | user_id | user_role
1 | 1 | admin
2 | 2 | manager
3 | 3 | employee
Second table is admin.
id | fname | lname
1 | A1 | J
2 | A2 | C
3 | A3 | S
Third table is manager.
id | fname | lname
1 | M1 | J
2 | M2 | C
3 | M3 | S
Third table is employee.
id | fname | lname
1 | E1 | J
2 | E2 | C
3 | E3 | S
How can I make it something like this:
SELECT * FROM user u INNER JOIN user.user_role ur ON ur.id = u.user_id
So it would yield something likes
u.id | u.user_id | u.user_role | ur.id | ur.fname | ur.lname
1 | 1 | admin | 1 | A1 | J
2 | 2 | manager | 2 | M2 | C
3 | 3 | employee | 3 | E3 | S
You could use UNION ALL for this:
SELECT *
FROM user u
INNER JOIN ( SELECT 'admin' as user_role, id, fname, lname
FROM admin
UNION ALL
SELECT 'manager' as user_role, id, fname, lname
FROM manager
UNION ALL
SELECT 'employee' as user_role, id, fname, lname
FROM employee
) ur
ON ur.id = u.user_id
AND ur.user_role = u.user_role
Here is working SQL fiddle.
Related
I want to get the firms that dont have contact method main_phone or phone This is my schema
Firms table
+----+-------+
| id | name |
+----+-------+
| 1 | Firm1 |
| 2 | Firm2 |
| 3 | Firm3 |
+----+-------+
Contacts
+----+----------+---------+
| id | label | firm_id |
+----+----------+---------+
| 1 | Contact1 | 1 |
| 2 | Contact2 | 1 |
| 3 | Contact3 | 2 |
| 4 | Contact4 | 3 |
+----+----------+---------+
contact_methods
+----+-------------+------------+
| id | method_type | contact_id |
+----+-------------+------------+
| 1 | main_phone | 1 |
| 2 | main_fax | 1 |
| 3 | email | 1 |
| 4 | main_fax | 4 |
| 5 | main_fax | 3 |
| 6 | phone | 2 |
| 7 | main_mobile | 1 |
| 8 | url | 4 |
+----+-------------+------------+
and this is my query
SELECT
firms.id
FROM firms
JOIN contacts ON (contactable_id = firms.id)
JOIN contact_methods ON contacts.id = contact_methods.contact_id
WHERE
firms.active = 1
AND
contact_methods.method_type NOT IN ('mobile','phone','main_mobile','main_phone')
I am getting all firms :s
Your code checks whether each firm has any contact type that does not belong to the list - while you want to ensure that none of the firm contact does.
One option uses aggregation:
select f.*
from firm f
left join contacts c on c.firm_id = f.id
left join contact_methods cm on cm.contact_id = c.id
group by f.id
having not max(cm.method_type in ('mobile','phone','main_mobile','main_phone')) <=> 1
Alternatively, you can use not exists:
select f.*
from firm f
where not exists (
select 1
from contacts c
inner join contact_methods cm on cm.contact_id = c.id
where c.firm_id = f.id and cm.method_type in ('mobile','phone','main_mobile','main_phone')
)
SELECT *
FROM firms
WHERE NOT EXIST ( SELECT NULL
FROM contacts
WHERE firms.id = contacts.firm_id )
contact_methods not needed in this task.
If you need the same for definite contacts types then use:
SELECT *
FROM firms
WHERE NOT EXIST ( SELECT NULL
FROM contacts
JOIN contact_methods ON contacts.id = contact_methods.contact_id
WHERE firms.id = contacts.firm_id
AND contact_methods.method_type NOT IN ({types list}) )
i want just the firms.id that does not have a contact method in ('mobile','phone','main_mobile','main_phone')
SELECT *
FROM firms
WHERE NOT EXIST ( SELECT NULL
FROM contacts
JOIN contact_methods ON contacts.id = contact_methods.contact_id
WHERE firms.id = contacts.firm_id
AND contact_methods.method_type IN ('mobile', 'phone', 'main_mobile', 'main_phone') )
1. Problem Statement
I am having a difficultly to display the total of COUNT() at the correct row of record.
How do I display the COUNT() to the correct respective service which is
2. Background
I want to display the output of showing the total of the project in charge by staff based on the stage_id and breakdown into project_name.
What I have attemped / tried
SELECT
B.employee_name,
B.project_name,
A.total
FROM
(
SELECT
COUNT( * ) AS total,
services.NAME AS project_name,
services.id AS service_id,
users.id AS member_id,
users.NAME AS member_name
FROM
users
LEFT JOIN projects ON users.id = projects.leader_id
LEFT JOIN services ON projects.service_id = services.id
WHERE
( projects.service_id IN ( 1, 5 ) AND projects.stage_id < 6 )
OR ( projects.service_id IN ( 2, 3, 4, 7 ) AND projects.stage_id < 7 )
GROUP BY
member_name,
service_id
) AS A
RIGHT OUTER JOIN (
SELECT
users.id AS user_id,
users.NAME AS employee_name,
services.NAME AS project_name,
services.id AS service_id
FROM
users,
services
) AS B ON A.service_id = B.user_id RIGHT OUTER JOIN ( SELECT users.id AS user_id, users.NAME AS user_name, services.NAME AS project_name, services.id AS service_id FROM users, services ) AS B ON A.service_id = B.user_id
I used this query to generate the output below
+-------+-------------------+------------------+-------------------+
| id | project_name | employee_name | total |
+-------+-------------------+------------------+-------------------+
| 1 | Projects A | Employee A | 2 |
| 2 | Projects B | Employee A | 2 |
| 3 | Projects A | Employee B | 3 |
| 4 | Projects B | Employee B | 3 |
| 5 | Projects A | Employee C | 1 |
| 6 | Projects B | Employee C | 1 |
| 7 | Projects A | Employee D | 2 |
| 8 | Projects B | Employee D | 2 |
+-------+-------------------+------------------+-------------------+
The total of count assigns into the wrong row of record.
3. SQL Fiddle
This is the example of the output I have created on SQL Fiddle.
http://www.sqlfiddle.com/#!9/08eff4/1/0
4. Expected Output
I am expecting the total of count can be assigned to the correct row of record.
Output Expectation
+-------+-------------------+------------------+-------------------+
| id | project_name | employee_name | total | (COUNT (*) AS total)
+-------+-------------------+------------------+-------------------+
| 1 | Projects A | Employee A | 2 |
| 2 | Projects B | Employee A | NULL |
| 3 | Projects A | Employee B | 3 |
| 4 | Projects B | Employee B | NULL |
| 5 | Projects A | Employee C | 1 |
| 6 | Projects B | Employee C | NULL |
| 7 | Projects A | Employee D | 2 |
| 8 | Projects B | Employee D | NULL |
+-------+-------------------+------------------+-------------------+
I have running out of idea to achieve the expected outcome.
Hence, I would like to seek for help from the experts in this forum.
P/S: The field name might be different from the above because I write the query in a different schema
I managed to find my answer after keep on trying.
SELECT
A.NAME,
B.NAME,
(
SELECT
COUNT( * )
FROM
projects
LEFT JOIN users ON users.id = projects.leader_id
WHERE
(
projects.service_id IN ( 1, 5 )
AND projects.stage_id < 6
AND users.id = A.id
AND projects.service_id = B.id
)
OR (
projects.service_id IN ( 2, 3, 4, 7 )
AND projects.stage_id < 7
AND users.id = A.id
AND projects.service_id = B.id
)
)
FROM
users AS A
CROSS JOIN services AS B
This is the query that output my expected result as below.
+-------+-------------------+------------------+-------------------+
| id | project_name | employee_name | total | (COUNT (*) AS total)
+-------+-------------------+------------------+-------------------+
| 1 | Projects A | Employee A | 2 |
| 2 | Projects B | Employee A | NULL |
| 3 | Projects A | Employee B | 3 |
| 4 | Projects B | Employee B | NULL |
| 5 | Projects A | Employee C | 1 |
| 6 | Projects B | Employee C | NULL |
| 7 | Projects A | Employee D | 2 |
| 8 | Projects B | Employee D | NULL |
+-------+-------------------+------------------+-------------------+
I have
jobs table with fields
jobId, jobTitle, jobDesc
jobQuotes Table with fields
id, user_id, quote
jobQuotes table has the quote of users who gave quote for the job.
I need those jobs for which a specific user has NOT given any quote.
Using LEFT JOIN I get all the jobs irrespective of the jobQuotes table.
And INNER JOIN only gives all the jobs that has a relevant jobQuote.
But I need those jobs for which a specific user has NOT given any quote.
My Query is
SELECT * FROM dummy_jobs J LEFT JOIN jobQuotes JQ ON J.jobId=JQ.jobId WHERE MATCH (J.jobTitle, J.jobDescription) AGAINST ('php, mysql');
How to filter this result set so that output doesn't have specific user_id in jobQuotes?
SELECT jobstable.jobid from jobstable inner join
(SELECT id from jobQuotes where userid = 953 and quote IS NULL) dummy_table
on dummy_table.id == jobstable.jobid;
The Answer is According to the comment you were given
"I want all jobs for which userId= 953 has not given any quote"
An approach might be to associate a specific user with all jobs by using a cross join and then left join to job quotes with a null test to find those not quoted for.
for example
users
+----+----------+
| id | username |
+----+----------+
| 1 | John |
| 2 | Jane |
| 3 | Ali |
| 6 | Bruce |
| 7 | Martha |
+----+----------+
Jobs
+-------+----------+---------+
| jobId | jobTitle | jobDesc |
+-------+----------+---------+
| 1 | a | a |
| 2 | b | b |
| 3 | c | c |
+-------+----------+---------+
Jobquotes
+------+---------+-------+
| id | user_id | quote |
+------+---------+-------+
| 1 | 3 | 10 |
| 2 | 2 | 10 |
+------+---------+-------+
select t.id,t.username,t.jobid,t.jobtitle,t.jobdesc
from
(
select u.id,u.username, s.jobid,s.jobtitle,s.jobdesc
from users u
cross join (select distinct jobid , jobtitle, jobdesc from jobs) s
where u.id = 3
) t
left join jobquotes jq on jq.id = t.jobid and jq.user_id = t.id
where jq.id is null
result
+----+----------+-------+----------+---------+
| id | username | jobid | jobtitle | jobdesc |
+----+----------+-------+----------+---------+
| 3 | Ali | 2 | b | b |
| 3 | Ali | 3 | c | c |
+----+----------+-------+----------+---------+
as the title states, I'm trying to return a query which gets account details from the accounts table, gets the average rating for the account from the reviews table, and limits the rows to the service location associated to the account.
Here are the simplified tables:
accounts
+----+------------+-----------+
| id | first_name | last_name |
+----+------------+-----------+
| 1 | John | Smith |
| 2 | Bob | Doe |
| 3 | Alice | McLovin |
| 4 | Bruce | Wayne |
+----+------------+-----------+
reviews
+----+-------------+-----+--------+
| id | acccount_id | ... | rating |
+----+-------------+-----+--------+
| 1 | 1 | ... | 9 |
| 2 | 1 | ... | 10 |
| 3 | 2 | ... | 7 |
| 4 | 1 | ... | 2 |
| 5 | 4 | ... | 6 |
+----+-------------+-----+--------+
service_area
+----+-------------+---------+
| id | acccount_id | city_id |
+----+-------------+---------+
| 1 | 1 | 1140 |
| 2 | 1 | 1001 |
| 3 | 2 | 1140 |
| 4 | 1 | 1086 |
| 5 | 4 | 1001 |
+----+-------------+---------+
For example, the user may request to view all accounts which have a service area of city_id 1140. The query should then return the first_name, last_name, and average rating for each account within the specified service area. Note that accounts can have multiple service areas (see service_area table).
Thanks in advance!
UPDATE:
The following QUERY did the trick! I needed a LEFT JOIN for the reviews table!
SELECT a.first_name, a.last_name, AVG(r.rating) avg_rating
FROM accounts a
JOIN service_area sa
ON a.id = sa.account_id AND sa.city_id = 1140
LEFT JOIN reviews r
ON a.id = r.account_id
GROUP BY a.id
You can use joins and simple aggregation with group by
SELECT a.*,
AVG(r.rating) avg_rating
FROM accounts a
JOIN reviews r ON a.id = r.acccount_id
JOIN service_area s ON a.id = s.acccount_id
WHERE s.city_id = 1140
GROUP BY a.id
Result set will be like
id first_name last_name avg_rating
------ ---------- --------- ------------
1 John Smith 7.0000
2 Bob Doe 7.0000
Use LEFT join for when there are no reviews available
SELECT a.*,
COALESCE(AVG(r.rating),0) avg_rating
FROM accounts a
LEFT JOIN reviews r ON a.id = r.acccount_id
JOIN service_area s ON a.id = s.acccount_id
WHERE s.city_id = 1140
GROUP BY a.id
DEMO
I have searched and gone through the available topics similar to mine. But, failed to find that satisfies my requirements. Hence, posting it here.
I have four tables as follows:
"Organization" table:
--------------------------------
| org_id | org_name |
| 1 | A |
| 2 | B |
| 3 | C |
"Members" table:
----------------------------------------------
| mem_id | mem_name | org_id |
| 1 | mem1 | 1 |
| 2 | mem2 | 1 |
| 3 | mem3 | 2 |
| 4 | mem4 | 3 |
"Resource" table:
--------------------------------
| res_id | res_name | res_prop |
| 1 | resource1 | prop-1 |
| 2 | resource2 | prop-2 |
| 3 | resource3 | prop-3 |
| 4 | resource4 | prop-4 |
| 5 | resource1 | prop-5 |
| 6 | resource2 | prop-6 |
A constraint of UNIQUE INDEX (res_name, res_prop) is applied in the above table.
"member-resource" table:
--------------------------------------------
| sl_no | mem_id | res_id |
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 1 |
| 4 | 4 | 3 |
| 5 | 3 | 4 |
| 6 | 2 | 3 |
| 7 | 4 | 3 |
| 8 | 1 | 5 |
| 9 | 1 | 6 |
I want to find out the distinct res_name from Resource table that have more than one res_prop for a specific organization. For example, expected output for organization A would be as follows:
| res_name | res_prop_count |
| resource1 | 2 |
| resource2 | 2 |
Any help in this regard will highly be appreciated.
Regards.
When doing things like this you should build your query up logically, so to start get all your resources and props from organisation A
SELECT r.res_name,
r.res_prop
FROM Resource r
INNER JOIN `member-resource` mr
ON mr.res_id = r.res_id
INNER JOIN Members m
ON m.mem_id = mr.mem_id
INNER JOIN Organization o
ON o.org_id = m.org_id
WHERE o.org_name = 'A'
Then you can start thinking about how you want to filter it, so you want to find resource names that have more than one different res_prop, so you need to group by res_name, and apply a HAVING clause to limit it to res_names with more than one distinct res_prop:
SELECT r.res_name,
COUNT(DISTINCT r.res_prop) AS res_prop_count
FROM Resource r
INNER JOIN `member-resource` mr
ON mr.res_id = r.res_id
INNER JOIN Members m
ON m.mem_id = mr.mem_id
INNER JOIN Organization o
ON o.org_id = m.org_id
WHERE o.org_name = 'A'
GROUP BY r.res_name
HAVING COUNT(DISTINCT r.res_prop) > 1;
Example on SQL Fiddle
I'm not entirely sure I understand what you are looking for, but I think this should work:
SELECT Resource.res_name,
COUNT(DISTINCT Resource.res_prop) AS res_prop_count
FROM Resource
INNER JOIN member_resource
USING (res_id)
INNER JOIN Members
USING (mem_id)
INNER JOIN Organization
USING (org_id)
WHERE Organization.org_name = 'A'
GROUP BY res_name
HAVING res_prop_count > 1;
try this:
select
res_name, count(res_prop) as res_prop_count
from
Resource
where
res_id in (select
res_id
from
member_resource
where
mem_id in (select
mem_id
from
Members
where
org_id = (select
org_id
from
Organization
where
org_name = 'A'))) group by res_name
Try this:
If you have Organization ID then use the query below:
SELECT r.res_name, COUNT(DISTINCT r.res_prop) res_prop_count
FROM member-resource mr
INNER JOIN Resource r ON mr.res_id = r.res_id
INNER JOIN Members m ON mr.mem_id = r.mem_id
WHERE m.org_id = 1
GROUP BY r.res_id HAVING res_prop_count > 1;
If you have Organization name then use the query below:
SELECT r.res_name, COUNT(DISTINCT r.res_prop) res_prop_count
FROM member-resource mr
INNER JOIN Resource r ON mr.res_id = r.res_id
INNER JOIN Members m ON mr.mem_id = r.mem_id
INNER JOIN Organization o ON m.org_id = o.org_id
WHERE m.org_name = 'A'
GROUP BY r.res_id HAVING res_prop_count > 1