简体   繁体   中英

SQL query from 3 different tables

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.

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 eg '... 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'

你可以吗?

select vid from values where vid not in (select vid from relations where uid = user_id)

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
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.

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.

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM