Querying a many to many table - sql

I'm trying to query a table and I'm having a hard time figuring out the query.
This are my tables(simplified):
Member
ID | NAME
1 | Frans
2 | Eric
3 | Stephan
4 | Kris
Evenement
ID | NAME
1 | Picknic
2 | Party
3 | Movie
Evenement
ID_EVENEMENT | ID_MEMBER
1 | Kris
1 | Stephan
1 | Eric
2 | Eric
2 | Frans
3 | Frans
3 | Stephan
Alright, the query I want to do is this:
I want to
select
member_evenement.ID_MEMBER and member_evenement.ID_EVENEMENT
from
member_evenement
where
member.ID on member_evenement.ID_MEMBER
where
member_evenement.ID_MEMBER does not exist
for each member_evenement.ID_EVENEMENT
separately.
I'm using sql server 2008 R2
I hope I explained my question well enough.
If these are my base tables
Member
ID | NAME
1 | Frans
2 | Eric
3 | Stephan
4 | Kris
Evenement
ID | NAME
1 | Picknic
2 | Party
3 | Movie
Member_Evenement
ID_EVENEMENT | ID_MEMBER
1 | Kris
1 | Stephan
1 | Eric
2 | Eric
2 | Frans
3 | Frans
3 | Stephan
then the result of my query should look like this:
Evenement
ID_EVENEMENT | ID_MEMBER | MEMBER_NAME | EVENEMENT_NAME
1 | 1 | Frans | Picknic
2 | 3 | Stephan | Party
2 | 4 | Kris | Party
3 | 2 | Eric | Movie
3 | 4 | Kris | Movie

SELECT e.ID AS ID_EVENEMENT, m.ID AS ID_MEMBER,
FROM Evenement e, Member m
EXCEPT
SELECT ID_EVENEMENT, ID_MEMBER
FROM member_evenement;

To return all combinations of member and evenement that are not recorded on the member_evenement table, try the following:
select e.id id_evenement,
m.id id_member,
m.name member_name,
e.name evenement_name
from member m
cross join evenement e
left join member_evenement me
on e.id = me.id_evenement and m.id = me.id_member
where me.id_evenement is null or me.id_member is null
(This assumes that id_member is actually the member's id, and not their name as in the sample data.)

Another possibility, which gives the exact same execution plan as Mark Bannister's and onedaywhen's answer is the following:
SELECT member.id AS memberid, evenement.id AS evenementid
FROM member
CROSS JOIN evenement WHERE
NOT EXISTS(
SELECT NULL AS [Empty]
FROM member_evenement
WHERE member_evenement.memberid = member.id
AND member_evenement.evenementid = evenement.id
)

Related

How to use SQL to add a column of data to a result table, that is based on a logical reference within the same table?

I am trying to add a column to some results not editing the database itself, for the sake of a dashboard program that will be more user friendly, in order to help organize results according to employee supervisors. The supervisors will not know their Employee ID off the top of their heads, and for ease of use, just having their names be the item that is sortable going forward would be useful.
So I want to write a query that will transform TABLE 1 into TABLE 2.
TABLE 1
EmployeeID | Name | SupervisorID |
1 | Dave | 3 |
2 | Jeff | 3 |
3 | Cindy | 4 |
4 | Carol | NULL |
TABLE 2
EmployeeID | Name | SupervisorID | **SupervisorName
1 | Dave | 3 | Cindy
2 | Jeff | 3 | Cindy
3 | Cindy | 4 | Carol
4 | Carol | NULL | NULL
...
select t1.EmployeeID ,t1.Name, t1.SupervisorID, t2.name As SupervisorName
from table1 t1
left join table1 t2 on t1.SupervisorId = t2.EmployeeID

Oracle query using 3 tables, sql

I have a problem with a query for Oracle with this scenario:
Table People
ID | Name
1 | juan
2 | pedro
3 | luis
Table Properties
ID | nombre_inmueble | FK to Table People
1 | house | 1
2 | garden | 1
3 | terrace | 1
4 | moto | 2
5 | jet | 2
Table Accessories
ID | accessories | FK Table Properties
1 | windows | 1
2 | doors | 1
3 | scale | 2
4 | plants | 3
5 | motor | 4
What I want is only the people who have Properties and that have ALL Accessories, in this case the output would be
1 | juan
What would be the query?
Your query will look like this:
SELECT *
FROM People P
WHERE EXISTS(
SELECT 1
FROM Properties T
WHERE T.PEOPLE= P.ID
)
AND NOT EXISTS(
SELECT 1
FROM Properties T
WHERE T.PEOPLE= P.ID
AND NOT EXISTS(
SELECT 1
FROM Accessories A
WHERE A.Properties = T.ID
)
);

SQL query to find the friends in a table

I have two tables, Users and Friends. The tables look like:
USERS
| ID | Name |
| 1 | Sam |
| 2 | Harry |
| 3 | Vivi |
| 4 | sabrina |
FRIENDS
| UId | FriendID|
| 1 | 2 |
| 2 | 3 |
| 4 | 1 |
| 5 | 4 |
| 1 | 3 |
I need to find the names of all the friends for Sam. I tried doing the same using a Union in an SQL query, but I couldn't get the desired output. Can I possibly get the required output doing the same?
declare
#answer nvarchar(max)='{'
select #answer=#answer+u1.Name+',' from USERS u
inner join FRIENDS f on f.UId=u.ID
inner join USERS u1 on u1.ID=f.FriendID
where u.ID=<what ever you want> //1 or 2 or 3 or 4
set #answer=SUBSTRING(#answer,0,len(#answer)-1)+'}'
select #answer
select u.name from users
join friends f on users.id=f.uid
join users u on u.id=f.friendid
where users.name='Sam';

how to sql query 2 tables and group by?

i have 2 tables: activities and users.
users has columns: name, active
activities: name, type, time, user_id.
for example i have these tables:
users
-----
id | name | active
1 | marc | true
2 | john | true
3 | mary | true
4 | nico | true
activities
-----
id | name | type | time | user_id
1 | morn | walk | 90 | 2
2 | morn | walk | 22 | 2
3 | morn | run | 12 | 2
4 | sat | walk | 22 | 1
5 | morn | run | 13 | 1
6 | mond | walk | 22 | 3
7 | morn | walk | 22 | 2
8 | even | run | 42 | 1
9 | morn | walk | 22 | 3
10 | morn | walk | 62 | 1
11 | morn | run | 22 | 3
now i would like to get table that would sum time spent on each type of activity and would group it by user name. so:
result
------
user name | type | time
marc | walk | 84
marc | run | 55
john | walk | 134
john | run | 12
mary | walk | 44
mary | run | 2
nico | walk | 0
nico | run | 0
how should i write this query to get this result?
thanks in advance
gerard
you can use coalesce to get 0 for empty activities and distinct to get all type of possible activities
select
u.name, c.type,
coalesce(sum(a.time), 0) as time
from (select distinct type from activities) as c
cross join users as u
left outer join activities as a on a.user_id = u.id and a.type = c.type
group by u.name, c.type
order by u.name, c.type
sql fiddle demo
Select u.name, a.type, SUM(a.time) FROM
activities a
LEFT JOIN users u
ON a.user_id = u.id
GROUP BY u.name, a.type
FIDDLE
Use this to get zero count as well
SELECT c.name,c.type,aa.time FROM
(Select u.id,u.name, b.type FROM
users u
CROSS JOIN (SELECT DISTINCT type FROM activities) b) c
LEFT JOIN (SELECT a.user_id, a.type, SUM(a.time) as time FROM
activities a
GROUP BY a.user_id, a.type) aa ON
aa.user_id = c.id and c.type = aa.type
Fiddle2
this might work :
select users.name,activities.type,sum(activities.time)
from users left join activities on users.id = activities.user_id
where users.active group by users.name,activities.type

Changing IS NULL with (+) Syntax

I have this query :
SELECT B.id, B.name, D.id, D.name FROM TBB B, TDD D
WHERE (D.id = B.id OR D.id IS NULL)
From what I thought, (D.id = B.id OR D.id IS NULL) will show record that have id in both table TBB and TDD the but also show all of B.id records even if both table doesn't have the same id because of D.id IS NULL
So, Is this the same one like my above query :
SELECT B.id, B.name, D.id, D.name FROM TBB B, TDD D
WHERE B.id = D.id (+)
Thanks in advance!
second query will return all the row exist in TBB table, not matching column in TDD table would return as NULL.
in-case TDD table have any ID that doesn't match with TBB table ID , that row will not return by above two query.
I am pretty sure that your top query would result in a cartesian join to every record in B for records that have a NULL due to the or statement in your query.
Based on that, you would be better off using the outer join.
I also wrote a lengthy Q&A that looks at joins and how to pull data from multiple tables you might be interested in ( How can an SQL query return data from multiple tables ) it covers unions, inner and outer joins as well as subqueries. It has loads of code and output results which are explained in detail. (To the point I hit the answer length limit, so had to post a second answer)
Edit: After running a quick test, this is what I come up with:
mysql> select a.ID, a.Title, b.Name as Author
from books a join authors b
on a.authorID=b.ID or b.id=0;
+----+----------------------+-------------------+
| ID | Title | Author |
+----+----------------------+-------------------+
| 1 | Call of the Wild | Fluffeh |
| 1 | Call of the Wild | Jack London |
| 2 | Martin Eden | Fluffeh |
| 2 | Martin Eden | Jack London |
| 3 | Old Goriot | Fluffeh |
| 3 | Old Goriot | Honore de Balzac |
| 4 | Cousin Bette | Fluffeh |
| 4 | Cousin Bette | Honore de Balzac |
| 5 | Jew Suess | Fluffeh |
| 5 | Jew Suess | Lion Feuchtwanger |
| 6 | Nana | Fluffeh |
| 6 | Nana | Emile Zola |
| 7 | The Belly of Paris | Fluffeh |
| 7 | The Belly of Paris | Emile Zola |
| 8 | In Cold blood | Fluffeh |
| 8 | In Cold blood | Truman Capote |
| 9 | Breakfast at Tiffany | Fluffeh |
| 9 | Breakfast at Tiffany | Truman Capote |
+----+----------------------+-------------------+
18 rows in set (0.00 sec)
mysql> select a.ID, a.Title, b.Name as Author
from books a right outer join authors b
on a.authorID=b.ID;
+------+----------------------+-------------------+
| ID | Title | Author |
+------+----------------------+-------------------+
| NULL | NULL | Fluffeh |
| 1 | Call of the Wild | Jack London |
| 2 | Martin Eden | Jack London |
| 3 | Old Goriot | Honore de Balzac |
| 4 | Cousin Bette | Honore de Balzac |
| 5 | Jew Suess | Lion Feuchtwanger |
| 6 | Nana | Emile Zola |
| 7 | The Belly of Paris | Emile Zola |
| 8 | In Cold blood | Truman Capote |
| 9 | Breakfast at Tiffany | Truman Capote |
+------+----------------------+-------------------+
10 rows in set (0.00 sec)
Which is certainly not the same as an outer join. As I thought (at least in MySQL) the results cartesian in the first statement, but not in the outer join.