sql inner join where and - sql

tbl user
+--------+--------+
| UserID | Name |
+--------+--------+
| 1 | John |
| 2 | Anny |
| 3 | Andy |
| 4 | Tom |
+--------+--------+
tbl rol
+--------+--------+
| RolID | Name |
+--------+--------+
| 1 | Manager|
| 2 | Lead |
| 3 | Tester |
| 4 | Develop|
+--------+--------+
tbl user_rol
+--------+--------+
| UserID | RolID |
+--------+--------+
| 1 | 1 |
| 1 | 2 |
| 1 | 4 |
| 2 | 1 |
| 3 | 3 |
+--------+--------+
I have a List of parameters 1,2,4
SELECT u.UserID,Name
FROM [user] u
WHERE u.UserID in(
SELECT ur2.UserID
FROM user_rol ur2
WHERE ur2.ROlID IN(1,2,4)
GROUP BY ur2.UserID
HAVING COUNT(DISTINCT ur2.RolID)=3
)
The response will be:
+--------+--------+
| UserID | Name |
+--------+--------+
| 1 | John |
but if my parameters will be 1,2,3,4 will not work, but i need the response to be like previous
The problem is in count I did not know how much exists in the intermediate table user_rol.

It's hard to tell from you question, but it seems to me are looking to output any user that has more than one role listed in the user_rol table. Here is how you would do that:
SELECT user.userid, user.name
FROM user
INNER JOIN user_rol
ON user.userid = user_rol.userid
GROUP BY user.userid, user.name
HAVING COUNT(*) > 1
Tested here: http://sqlfiddle.com/#!9/35288d

Related

Many to many outer join clause

This is my database schema:
user
| id | firstName |
|----|-----------|
| 1 | Adam |
| 2 | Bob |
permission
| id | title |
|----|-------|
| 1 | Foo |
| 2 | Bar |
| 3 | XYZ |
| 4 | ABC |
user_permissions
| user_id | permission_id |
|---------|---------------|
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
I want to check which permissions the user with id = 1 has and which he doesn't. I tried with this:
select up.permission_id, up.user_id
from permission a
right outer join user_permissions up on a.id = up.permission_id
right outer join user u on u.id = up.user_id
where u.id = 1
but I got:
| permission_id | user_id |
|---------------|---------|
| 1 | 1 |
| 2 | 1 |
and what I want to get is:
| permission_id | user_id |
|---------------|---------|
| 1 | 1 |
| 2 | 1 |
| 3 | NULL |
| 4 | NULL |
Any ideas whats wrong there?
Your where clause states that where u.id = 1, which will filter away the wanted results. you can add an or clause or coalesce function. where u.id = 1 or u.id is null or with coalesce where coalesce(u.id, 1) = 1. (Coalesce returns the value in second parameter if first parameter is null.)

Summarize count of multi table in single SQL query

I have three table with below details:
Table 1: worklog
+-----------+------------+-------------+
| worklogid | technician | description |
+-----------+------------+-------------+
| 1 | john | some text |
+-----------+------------+-------------+
| 2 | jack | some text |
+-----------+------------+-------------+
| 3 | john | some text |
+-----------+------------+-------------+
| 4 | jenifer | some text |
+-----------+------------+-------------+
Table 2: task
+--------+-------+-------------+
| taskid | owner | description |
+--------+-------+-------------+
| 1 | john | some text |
+--------+-------+-------------+
| 2 | john | some text |
+--------+-------+-------------+
| 3 | john | some text |
+--------+-------+-------------+
| 4 | jack | some text |
+--------+-------+-------------+
Table 3: request
+-----------+------------+-----------+-------------+
| requestid | technician | title | description |
+-----------+------------+-----------+-------------+
| 1 | john | some text | ... |
+-----------+------------+-----------+-------------+
| 2 | sara | some text | ... |
+-----------+------------+-----------+-------------+
| 3 | john | some text | ... |
+-----------+------------+-----------+-------------+
| 4 | jack | some text | ... |
+-----------+------------+-----------+-------------+
Now I need to SQL query for this result:
+------------+------------------+---------------+------------------+
| technician | count(worklogid) | count(taskid) | count(requestid) |
+------------+------------------+---------------+------------------+
| john | 2 | 3 | 2 |
+------------+------------------+---------------+------------------+
| jack | 1 | 1 | 1 |
+------------+------------------+---------------+------------------+
| jenifer | 1 | 0 | 0 |
+------------+------------------+---------------+------------------+
| sara | 0 | 0 | 1 |
+------------+------------------+---------------+------------------+
What should I do?
One method is to just use union all and aggregation:
select techician, sum(is_workid), sum(is_taskid), sum(is_requestid)
from ((select technician, 1 as is_workid, 0 as is_taskid, 0 as is_requestid
from worklog
) union all
(select owner, 0, 1, 0
from task
) union all
(select technician, 0, 0, 1
from request
)
) t
group by technician;
In Postgres, you can also aggregate before joining:
select *
from (select technician, count(*) as num_workid
from worklog
group by technician
) w full join
(select owner as technician, count(*) as num_task
from task
group by owner
) t
using (technician) full join
(select technician, count(*) as num_request
from request
group by technician
) w
using (technician);
With a full join, I find that using is simpler than on clauses. But the name needs to be the same in all the tables.

Merge columns on two left joins

I have 3 tables as shown:
Video
+----+--------+-----------+
| id | name | videoSize |
+----+--------+-----------+
| 1 | video1 | 1MB |
| 2 | video2 | 2MB |
| 3 | video3 | 3MB |
+----+--------+-----------+
Survey
+----+---------+-----------+
| id | name | questions |
+----+---------+-----------+
| 1 | survey1 | 1 |
| 2 | survey2 | 2 |
| 3 | survey3 | 3 |
+----+---------+-----------+
Sequence
+----+---------+-----------+----------+
| id | videoId | surveyId | sequence |
+----+---------+-----------+----------+
| 1 | null | 1 | 1 |
| 2 | 2 | null | 2 |
| 3 | null | 3 | 3 |
+----+---------+-----------+----------+
I would like to query Sequence and join on both of video and survey tables and merge common columns without specifying the column names (in this case name) like this:
Query Result:
+----+---------+-----------+----------+---------+-----------+-----------+
| id | videoId | surveyId | sequence | name | videoSize | questions |
+----+---------+-----------+----------+---------+-----------+-----------+
| 1 | null | 1 | 1 | survey1 | null | 1 |
| 2 | 2 | null | 2 | video2 | 2MB | null |
| 3 | null | 3 | 3 | survey3 | null | 3 |
+----+---------+-----------+----------+---------+-----------+-----------+
Is this possible?
BTW the below sql doesn't work as it doesn't merge on the name field:
SELECT * FROM "Sequence"
LEFT JOIN "Survey" ON "Survey"."id" = "Sequence"."surveyId"
LEFT JOIN "Video" ON "Video"."id" = "Sequence"."videoId"
This query will show what you want:
select
s.*,
coalesce(y.name, v.name) as name, -- picks the right column
v.videoSize,
y.questions
from sequence s
left join survey y on y.id = s.surveyId
left join video v on v.id = s.videoId
However, the SQL standard requires you to name the columns you want. The only exception being * as shown above.

How to select 2 data from 1 column based on other relations in other table

Say, I have a table like the following called "name":
| nid | name |
----------------
| 1 | john |
| 2 | mike |
| 3 | tom |
| 4 | jack |
| 5 | will |
| 6 | david | ...
and another table like the following called "relation_father_son":
| rid | fnid | snid |
---------------------
| 1 | 1 | 2 |
| 2 | 1 | 3 |
| 3 | 4 | 5 |
| 4 | 2 | 6 | ...
then I would like a result like the following:
| father | son |
------------------
| john | mike |
| john | tom |
| jack | will |
| mike | david | ...
What the should the SQL query be?
The query would be:
SELECT
f.name AS father,
s.name AS son
FROM relation_father_son
INNER JOIN name AS f
ON (nid = fnid)
INNER JOIN name AS s
ON (nid = snid)
First of all, it is confusing that the first table is named as name. You should rename it to a more distinguished name, such as family_names. Read more at: Is name a reserved word in MySQL?
For the desired result, you can use the following query:
SELECT
(SELECT `name` FROM `family_names` WHERE nid=fnid) AS father,
(SELECT `name` FROM `family_names` WHERE nid=snid) AS son
FROM relation_father_son

SQL compare multiple rows or partitions to find matches

The database I'm working on is DB2 and I have a problem similar to the following scenario:
Table Structure
-------------------------------
| Teacher Seating Arrangement |
-------------------------------
| PK | seat_argmt_id |
| | teacher_id |
-------------------------------
-----------------------------
| Seating Arrangement |
-----------------------------
|PK FK | seat_argmt_id |
|PK | Row_num |
|PK | seat_num |
|PK | child_name |
-----------------------------
Table Data
------------------------------
| Teacher Seating Arrangement|
------------------------------
| seat_argmt_id | teacher_id |
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 1 |
| 5 | 2 |
------------------------------
---------------------------------------------------
| Seating Arrangement |
---------------------------------------------------
| seat_argmt_id | row_num | seat_num | child_name |
| 1 | 1 | 1 | Abe |
| 1 | 1 | 2 | Bob |
| 1 | 1 | 3 | Cat |
| | | | |
| 2 | 1 | 1 | Abe |
| 2 | 1 | 2 | Bob |
| 2 | 1 | 3 | Cat |
| | | | |
| 3 | 1 | 1 | Abe |
| 3 | 1 | 2 | Cat |
| 3 | 1 | 3 | Bob |
| | | | |
| 4 | 1 | 1 | Abe |
| 4 | 1 | 2 | Bob |
| 4 | 1 | 3 | Cat |
| 4 | 2 | 2 | Dan |
---------------------------------------------------
I want to see where there are duplicate seating arrangements for a teacher. And by duplicates I mean where the row_num, seat_num, and child_name are the same among different seat_argmt_id for one teacher_id. So with the data provided above, only seat id 1 and 2 are what I would want to pull back, as they are duplicates on everything but the seat id. If all the children on the 2nd table are exact (sans the primary & foreign key, which is seat_argmt_id in this case), I want to see that.
My initial thought was to do a count(*) group by row#, seat#, and child. Everything with a count of > 1 would mean it's a dupe and = 1 would mean it's unique. That logic only works if you are comparing single rows though. I need to compare multiple rows. I cannot figure out a way to do it via SQL. The solution I have involves going outside of SQL and works (probably). I'm just wondering if there is a way to do it in DB2.
Does this do what you want?
select d.teacher_id, sa.row_num, sa.seat_num, sa.child_name
from seatingarrangement sa join
data d
on sa.seat_argmt_id = d.seat_argmt_id
group by d.teacher_id, sa.row_num, sa.seat_num, sa.child_name
having count(*) > 1;
EDIT:
If you want to find two arrangements that are the same:
select sa1.seat_argmt_id, sa2.seat_argmt_id
from seatingarrangement sa1 join
seatingarrangement sa2
on sa1.seat_argmt_id < sa2.seat_argmt_id and
sa1.row_num = sa2.row_num and
sa1.seat_num = sa2.seat_num and
sa1.child_name = sa2.child_name
group by sa1.seat_argmt_id, sa2.seat_argmt_id
having count(*) = (select count(*) from seatingarrangement sa where sa.seat_argmt_id = sa1.seat_argmt_id) and
count(*) = (select count(*) from seatingarrangement sa where sa.seat_argmt_id = sa2.seat_argmt_id);
This finds the matches between two arrangements and then verifies that the counts are correct.