简体   繁体   中英

How do I make my MySQL query with joins more concise?

I have a huge MySQL query that depends on JOINs.

SELECT m.id, l.name as location, CONCAT(u.firstName, " ", u.lastName) AS matchee, u.email AS mEmail, u.description AS description, m.time AS meetingTime
FROM matches AS m
LEFT JOIN locations AS l ON locationID=l.id 
LEFT JOIN users AS u ON (u.id=m.user1ID)
WHERE m.user2ID=2

UNION

SELECT m.id, l.name as location, CONCAT(u.firstName, " ", u.lastName) AS matchee, u.email AS mEmail, u.description AS description, m.time AS meetingTime
FROM matches AS m
LEFT JOIN locations AS l ON locationID=l.id 
LEFT JOIN users AS u ON (u.id=m.user2ID)
WHERE m.user1ID=2

The first 3 lines of each sub-statement divided by UNION are identical. How can I abide by the DRY principle, not repeat those three lines, and make this query more concise?

Try in this way, should work:

SELECT m.id, l.name as location, CONCAT(u.firstName, " ", u.lastName) AS matchee, u.email AS mEmail, u.description AS description, m.time AS meetingTime
FROM matches AS m
LEFT JOIN locations AS l ON locationID=l.id 
LEFT JOIN users AS u 
ON ((u.id=m.user1ID AND m.user2ID=2) OR (u.id=m.user2ID AND  m.user1ID=2))
WHERE (m.user1ID=2 OR m.user2ID=2)
SELECT
  s.id,
  s.location,
  CONCAT(u.firstName, " ", u.lastName) AS matchee,
  u.email AS mEmail,
  u.description AS description,
  s.meetingTime
FROM (
  SELECT
    m.id,
    l.name AS location,
    m.time AS meetingTime,
    CASE m.user1ID when @userID THEN m.user2ID ELSE m.user1ID END AS userID
  FROM matches AS m
  LEFT JOIN locations AS l ON m.locationID = l.id
  WHERE m.user1ID = @userID OR m.user2ID = @userID
) AS s
LEFT JOIN users AS u ON s.userID = u.id

The subquery filters the matches table on the specified user ID, joins it to locations , pulls the necessary columns from the two tables and prepares a single userID column (using either user1ID or user2ID , depending on which of the two is not the specified ID) to joining with users . The outer query joins the inner SELECT's result set to users and pulls the rest of the columns, obtained as a result of the join.

1) I see that you are matching users and you keep some information related to that match.

That's a little complicated to design. The easy approach is just make the data in matches redundant. By this way you will always get the match of user1ID=2. Means you need to store every match for 2 times, in one user1ID and user2ID and in the second with the opposite values of user1ID and user2ID. However as I said this is redundant and if you expect many records I don't recommend it.

2) Other approach is normalizing your design. Create another table matchUser(matchId, userId) (primary key is both attrs)

SELECT ... FROM matches AS m
LEFT JOIN locations AS l ON locationID=l.id 
LEFT JOIN users AS u ON (u.id=mu2.userId)
INNER JOIN matchUser mu1 ON mu1.userId=2
INNER JOIN matchUser mu2 ON mu2.matchId=mu1.matchId AND mu2.userId != 2

Something like this, the query maybe wrong I didn't test it but you'll get the idea.

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