简体   繁体   中英

Where clause with multi AND & OR conditions

I got a table agenda in which the admin can make a reservation for him self or for someone else (another user). If the admin make the reservation for him self in agenda.user_id will be stored the id of admin.

In case that admin make a reservation for another person (another user) in agenda.user_id will be stored the id of the user for which the reservation will be made. The id of the admin will be stored in another column agenda.booked_user .

All the reservations are stored on agenda_users table also. agenda_users has this columns: id , agenda_id , user_id . The agenda_users.user_id it refers to agenda.user_id .

I want to retrieve all the reservations made by the admin which has made reservations for himself and for other users also.

I did a query with some AND & OR:

SELECT agenda.* 
FROM agenda,agenda_users 
WHERE agenda_users.agenda_id=agenda.id 
AND (agenda_users.user_id=$user_id 
AND agenda_users.user_id=agenda.user_id) 
OR (agenda_users.user_id=agenda.user_id 
AND agenda.booked_user=agenda.$user_id) 
AND checkout IS NULL 
AND NOW() < DATE_ADD(date_end, INTERVAL 6 HOUR) ORDER BY type ASC,date_start ASC

Cannot figure out the right solution to 'grab' all the reservations the admin has made for him self and other users.

solving the old-style-joins will leave you with this SQL:

SELECT agenda.* 
FROM agenda
INNER JOIN agenda_users ON agenda_users.user_id=agenda.user_id AND agenda_users.agenda_id=agenda.id
WHERE 
  (agenda_users.user_id=$user_id) OR (agenda.booked_user=agenda.$user_id) 
  AND checkout IS NULL 
  AND NOW() < DATE_ADD(date_end, INTERVAL 6 HOUR) ORDER BY type ASC,date_start ASC;

This SQL is almost human-readable (and understandable).

EDIT: Added extra () because AND has higher precedence than OR.

SELECT agenda.* 
FROM agenda
INNER JOIN agenda_users ON agenda_users.user_id=agenda.user_id AND agenda_users.agenda_id=agenda.id
WHERE 
  ((agenda_users.user_id=$user_id) OR (agenda.booked_user=agenda.$user_id)) 
  AND checkout IS NULL 
  AND NOW() < DATE_ADD(date_end, INTERVAL 6 HOUR) ORDER BY type ASC,date_start ASC;

It is cleaner in my opinion to use UNION instead of a very complex where conditions.

Note that you know the user_id you are filtering for, therefore you don't need to join.

/* The ones for admin created by the user */
SELECT
agenda.*
FROM
agenda A
WHERE
A.user_id = $user_id

UNION ALL

/* the ones where the admin created it, but not for itself */
SELECT
agenda.*
FROM
agenda A
WHERE
A.booked_user_id = $user_id
AND A.user_id <> $user_id

Don't forget to add the rest of the where conditions to both subqueries of the union

This is too long for a comment. So I am posting this as an answer and may adjust it, once you clarify doubts about the data model.

There is a parent table agenda and it has a child table agenda_users . So one agenda has several users. But the agenda table itself has two users, too. One is the person who made the reservation, but rather than using one column for that user, you are song sometimes one column and sometimes the other. You say that when an admin makes a reservation for another user, the admin gets stored in the column booked_user , although it's obviously not the booked user, but the booking user. I wonder whether you have understoodthe data model yourself, because the explanation sounds just wrong.

Then, an agenda should typically be identified by its id (hence the name), so the agenda_users should be linked via its agenda_id only. Are you sure that the user_id of the two tables must match, too? That would mean an agenda.id is unique only in combination with a user_id ? It is possible, but doesn't seem likely.

Your query has some issues, too.

  • agenda.$user_id is probably supposed to mean $user_id only?
  • The parentheses are probably wrong, too, as AND has precedence over OR , so the checkout and date_end criteria will only works for the part after OR .
  • Then you are mising qualifiers. This doesn't make the query wrng, but makes it more difficult to read. What table do checkout and date_end belong to? I assume it's the agenda table and will write my query accordingly, because you mentioned the columns of the agenda_users table and these columns were not mentioned.

You want to select data from agenda . So, do so, don't join another table. If you have criteria based on the other table, then use IN or EXISTS for the lookup. In your case, though, - but I can only guess here - it seems you don't need the agenda_users table at all.

SELECT * 
FROM agenda
WHERE (user_id = $user_id OR booked_user = $user_id)
AND checkout IS NULL 
AND NOW() < DATE_ADD(date_end, INTERVAL 6 HOUR)
ORDER BY type, date_start;

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