Reputation: 9702
There are 3 tables:
Users table
------------
|uid|username|
------------
Values table
------------------
|vid|values|checked|
------------------
Relations
-----------
|cid|uid|vid|
-----------
Relations table contains user ids related to value ids. How to select value id from values table that is not related to given user id in relations table?
EDIT:
What I tried so far:
SELECT vid FROM relations where uid=user_id //this gives me array of value ids
SELECT vid FROM values where vid!=vid1 AND vid!=vid2 .....
EDIT2: Basic solution can be found here. But is there more efficient way? If table is very large for both values table and relations table basic solution is not efficient.
Upvotes: 0
Views: 128
Reputation: 984
If a Value is exactly 0 or 1 time in your Relations table, you can use a JOIN
for that:
SELECT `Values`.`vid` FROM `Values`
LEFT JOIN `Relations` ON (`Values`.`vid` = `Relations`.`vid`)
WHERE `Relations`.`uid` != 1;
This will not work if a Value is more than 1 time in the Relations table because the WHERE
would match another row with a different uid in this case. It is the same with a NOT IN
, this could also match a different row with the same vid but another uid.
If every Value is at least once in the Relations table, the most efficient way is to query only the Relations table:
SELECT DISTINCT `Relations`.`vid` FROM `Relations`
WHERE `Relations`.`uid` != 1;
If a Value can be 0, 1, or more times in the Relations table, the best way is to use an EXISTS
(see also taimur's answer):
SELECT `Values`.`vid` FROM `Values`
WHERE NOT EXISTS (
SELECT * FROM `Relations`
WHERE `Relations`.`vid` = `Values`.`vid` AND `Relations`.`uid` = 1
);
However, EXISTS
is a bit slower than the IN
or JOIN
, so you should compare how the execution times are in your case.
Upvotes: 0
Reputation: 1161
select distinct v.vid
from values v
left join relations r on (r.vid=v.vid)
where r.uid != user_id
It's unfortunate that MySQL doesn't support with
; this is not going to perform very well, unfortunately.
Upvotes: 0
Reputation: 8227
I think you can execute a simple query like this (assuming that the data type of user identifier is int
):
DECLARE @givenUserID int --local variable where you store the given user identifier
SELECT vid
FROM Values
WHERE vid NOT IN (SELECT vid FROM Relations where uid = @givenUserID)
Upvotes: 0
Reputation: 113
Which dbms are you using? Does it support the minus clause? If yes you can do something like this
select vid from values
minus
select vid from relations where uid = @user_id
this should give the vid's which are not mapped to a given user id
Another way to do this is through a not-exists clause (handy if your dbms doesn't support the minus clause)
select v.vid from values v where not exists (select 1 from relations r where
r.vid = v.vid and r.user_id = @user_id)
I would caution against using the not in clause though. Its performance is questionable and fails if the inner query returns a null value, which though is not possible in your case, but you should make it a habit to never use the 'not in' clause with a sub-query. Only use it when you have a list of literal values e.g. '... vid not in (1, 2, 3, 4)'. Whenever you have to 'Minus' something from one table based on values in another table use the 'not exists' and never 'not in'
Upvotes: 1
Reputation: 398
I think something simple like this query will suffice.
If there is no uid for a particular entry in the value table, then there shouldn't be an entry in the relations table either.
SELECT vid
FROM values
LEFT JOIN relations on values.vid = relations.vid
WHERE relations.uid IS NULL
Upvotes: 0
Reputation: 16
Is it ok for you ?
select vid from values where vid not in (select vid from relations where uid = user_id)
Upvotes: 0