简体   繁体   中英

“Conditional” Join Based on Field Value?

The site I'm working on has 3 different types of users: admin, applicants, reviewers. Each of these groups will have some basic info that will need to be stored (name, id, email, etc) as well as some data that is unique to each. I have created a users table as well as a table for each of the specific groups to store their unique data.

  • users: id, f_name, l_name, email, user_type
  • users_admin: id, user_id, office, emp_id
  • users_applicant: id, user_id, dob, address
  • users_reviewer: id, user_id, active_status, address, phone

If a user with user_type of "1" (applicant) logs in I will need to JOIN to the users_applicants table to retrieve their full record. I tried using a UNION but my tables have vastly different columns.

Is there a way to, based on a user's type, write a conditional query that will JOIN to the correct table? Am I going about this completely the wrong way?

Thank's in advance for your help!

Well, in the end your tables are already flawed. Why even have a table for each type? Why not put all those fields into the users table, or maybe a user_details table (if you really want an extra table for non-general data fields)? Currently, you're actually creating 4 independent user tables from a relational point of view.

So why do the type-tables have a surrogate key? Why isn't the user_id already the (only) primary key?

If you changed that, all you would need is the user id to retrieve the data you want, and you've already got that (or you wouldn't even be able to retrieve the user type).

Either you do it programmatically, or you can do this with a series of CASE s and LEFT JOIN s.

For simplicity's sake let's do this with a table users where you can have a user of type 1 (normal user), 2 (power user) or 3 (administrator). Normal users have an email but no telephone, power users have an address and a field dubbed "superpower", and administrators have a telephone number and nothing else.

Since you want to use the same SELECT for all, of course you need to place all these in your SELECT :

SELECT user.id, user.type, email, address, superpower, telephone

and you will then need to LEFT JOIN to recover these

FROM user
LEFT JOIN users_data ON (user.id = users_data.user_id)
LEFT JOIN power_data ON (user.id = power_data.user_id)
LEFT JOIN admin_info ON (user.id = admin_info.user_id)

Now the "unused" fields will be NULL , but you can supply defaults:

SELECT
    CASE WHEN user.type = 0 THEN email ELSE 'nobody@nowhere.com' END AS email,
    CASE WHEN user.type = 1 OR user.type = 2 THEN ... ELSE ... END as whatever,
    ...

Specific WHERE conditions you can put in the JOIN itself, eg if you only want administrators from the J sector, you can use

LEFT JOIN admin_info ON (user.id = admin_info.user_id AND admin_info.sector = 'J')

The total query time should not be too bad, seeing as most of the JOIN s will return little (and, if you specify a user ID, they will actually return nothing very quickly).

You could also do the same using a UNION , which would be even faster:

SELECT user.id, 'default' AS email, 'othermissingfield' AS missingfieldinthistable,
  ... FROM user JOIN user_data ON (user.id = user_data.user_id)
  WHERE ...
UNION
SELECT user.id, email, 'othermissingfield' AS missingfieldinthistable,
  ... FROM user JOIN power_data ON (user.id = power_data.user_id)
  WHERE ...
UNION
  ...

Now, if you specify the user ID, all queries except one will fail very fast. Each query has the same WHERE repeated plus any table-specific conditions. The UNION version is less maintainable (unless you generate it programmatically), but ought to be marginally faster.

In all cases, you'll be well advised in keeping updated indexes on the appropriate fields.

Instead i will suggest you reconstruct you tables structure like this.

Create a table

users_types : 
id 
type

Then create another table users with a foreign key

users :     
id 
f_name 
l_name 
email 
office 
emp_id 
dob 
address 
active_status 
phone 
users_types_id

And now when you need to insert data insert null in the fields which are not required for a particular user. And you can simply fetch records on the basis of id. Also using left join will give you the name of user type.

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