简体   繁体   中英

I have 4 tables in MySQL - Join with 4th table without duplicates (possible null value)

Ok I am working with 4 tables and I need my query to return no duplicates and null value if needed. Unfortunately due to a restriction in the framework I am using I can not use UNION. Here are my tables:

users Table
------------------------------------------------------
id      name
------------------------------------------------------
1       jane
2       john
3       skip


songs Table
------------------------------------------------------
id      artist      title
------------------------------------------------------
1       devo        whip
2       snake       hiss
3       america     great
4       elvis       blues


song_history Table
------------------------------------------------------
singer_id   song_id
------------------------------------------------------
2       1
2       2
2       3
2       4


song_current Table
------------------------------------------------------
singer_id   song_id     event_id
------------------------------------------------------
2       3       20
2       4       22

I have written two queries that work for half of the results needed, here is the first one:

SELECT name, artist, title
FROM users AS user
LEFT JOIN song_history AS history ON user.id = history.singer_id
LEFT JOIN songs AS song ON history.song_id = song.id 
WHERE user.id = 2

The above query gives me a list of all the songs in song_history for user john:

name    artist      title   
-----------------------------
john  | devo      | whip    |   
john  | snake     | hiss    |   
john  | america   | great   |   

Here is the second query for the other half of the results needed:

SELECT name, artist, title, event_id
FROM users AS user
LEFT JOIN song_history AS history ON user.id = history.singer_id
LEFT JOIN songs AS song ON history.song_id = song.id
LEFT JOIN song_current AS csongs ON csongs.singer_id = user.id
AND csongs.song_id = history.song_id
WHERE user.id = 2
AND event_id = 20

The above query gives me a list of all the songs in song_history that are ALSO in the song_current table with event_id of 20

name    artist      title   event_id
--------------------------------------------
john  | america   | great   |   20

Now, I have a restriction due to the framework I am using that restricts me from using UNION so I am lost as to how or if there is a way to do this without UNION.

Here are the results I am looking for:

name    artist      title   event_id
-------------------------------------
john  | devo      | whip    |   null
john  | snake     | hiss    |   null
john  | america   | great   |   20
john  | elvis     | blues   |   null

Basically I need a list of all songs for a given user that are in the song_history table and if an event_id matches it needs to show the event_id, if it does not match then it needs to show null but still show the songs that are in the song_history table.

The song_history table will always contain what is in song_current (without the event_id) however, song_current will not always contain data that is found in song_history.

If I could use UNION, I would simple use the two successful queries above and my problem would be solved, however, since I can't use UNION then all my attempts at LEFT INNER, LEFT OUTER and other JOINS have eluded me.

Any help is greatly appreciated!

Edited:

Note that the song_current table will have other event_id's that will keep me from using a WHERE/OR like this:

AND (event_id = 20 OR event_id IS NULL);

The Joomla 3.3 Framework just recently included the UNION statement and it does not work on multiple columns at this time.

Here is an example of a somewhat working UNION query that works fine in phpMyAdmin:

NOTE: there is an additional column called users.ordering that always returns 0 that is not outlined above - i was using this to give a 0 value to songs that did not have an event_id.

SELECT name, artist, title, users.ordering AS event_id
FROM users, song_history, song_current
WHERE users.id = song_history.singer_id
AND song_history.song_id = songs.id
AND users.id = '2'
UNION
SELECT name, artist, title, song_current.event_id AS event_id
FROM users, song_current, songs
WHERE users.id = song_current.singer_id
AND song_current.song_id = songs.id
AND users.id = '2'
AND song_current.event_id = '20'

Keep in mind that this UNION query works but with one exception (albeit acceptable for my use) It lists all the songs in the song_history for the user with a 0 event_id then it lists all the songs again that are both in the song_history and in the song_current along with the matching event_id. This result would be just as acceptable as the results listed above.

All you probably need is to either remove the filter condition on event_id or include NULL event_id's as well, as below

SELECT name, artist, title, 
CASE
  WHEN event_id <> 20 THEN NULL
  ELSE event_id
END event_id
FROM users AS user
LEFT JOIN song_history AS history ON user.id = history.singer_id
LEFT JOIN songs AS song ON history.song_id = song.id
LEFT JOIN song_current AS csongs ON csongs.singer_id = user.id
AND csongs.song_id = history.song_id
WHERE user.id = 2

SQL Fiddle demo The third query includes the rows with NULL event_id.

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