开发者

UNION SELECT with multiple distinct criteria where there is no real FK

开发者 https://www.devze.com 2023-03-29 19:20 出处:网络
I need to select a handfull of items from several tables with one problematic criterium. There is a meta_data table that contains information about a referred table. Simplified structure:

I need to select a handfull of items from several tables with one problematic criterium. There is a meta_data table that contains information about a referred table. Simplified structure:

table quest
id   INT AI PK
id_questtype   INT  FK -> questtype.id
id_creator   INT  FK -> user.id
creationdate   DATETIME
...

Each id refers to respective table

table user
id   INT AI PK
id_group   INT
username   VARCHAR(255)
...

table questtype
id   INT AI PK
name   VARCHAR(100)
...

Now comes tricky part:

table  quest_meta
id   INT AI PK
id_quest   INT  FK -> quest.id
id_user   INT  FK -> user.id
id_meta   INT NN
key   VARCHAR(20)
value   LONGTEXT

This table "quest_meta" is used to store all sorts of additional information for each quest item. For example question 1, question 2 etc.

table participation
id_user   INT  FK -> user.id
id_quest   INT  FK -> quest.id
id_quest_meta   INT NN

The id_quest_meta refers to quest_meta.id_meta but its not a real FK because there can be multiple rows with the same id_meta in the quest_meta table.

Works all nice and fine until i want to query information join all of those tables and having to fulfill !2! criteria in the participation table.

My current query looks something like this:

SELECT up.time, qm.value as title, u.username, u.id as id_user, q.id as id_quest
FROM participation p INNER JOIN quests q 
ON p.id_quest = q.id INNER JOIN user u
ON p.id_user = u.id INNER JOIN quest_meta qm
ON q.id = qm.id_quest
WHERE up.time > '2011-08-19 00:00:00' AND qm.key = 'quest_title' AND qm.id_meta = -1
GROUP BY p.id_user
UNION
SELECT p.time, qm.value as title, u.username, u.id as id_user, q.id as id_quest
FROM participation p INNER JOIN quests q 
ON p.id_quest = uq.id INNER JOIN users u
ON p.id_user = u.id INNER JOIN quests_meta qm
ON q.id = qm.id_quest
WHERE p.time > '2011-08-19 00:00:00' AND q.id = 2 AND p.vote = '1' AND p.id_quest_meta = -7
GROUP BY id_user 
ORDER BY time DESC;

The reason for the UNION is, that i need the additional criterium p.vote = '1' together with p.id_quest_meta = -7 (this is the quest_meta i know means it should be shown). So this is what i have...

MY PROBLEM NOW IS: How can i additionally make sure, that FROM 2nd SELECT only rows are selected WHERE qm.key = 'quest_title' AND qm.id_quest_meta = -1

Currently i receive a random qm.value from all the rows that are in the participation table.

All t开发者_JAVA技巧ables are InnoDB. If anything is unclear, ill love to explain whatever details are missing. Thanks a lot in advance.


I found the solution over a good night of sleep and dreaming about it :)

The solution is, to put the second SELECT in a subselect without the GROUP BY which allows me to SELECT "WHERE criterium 2" from the rows that fulfill criterium 1 and then GROUP the result and making UNION with first SELECT.

Here is the query:

SELECT up.time, qm.value as title, u.username, u.id as id_user, q.id as id_quest, qm.key as tit
FROM participation p INNER JOIN quests q 
ON p.id_quest = q.id INNER JOIN user u
ON p.id_user = u.id INNER JOIN quest_meta qm
ON q.id = qm.id_quest
WHERE p.time > '2011-08-19 00:00:00' AND qm.key = 'quest_title' AND qm.id_meta = -1
GROUP BY p.id_user
UNION
SELECT a.time, a.type, a.title, a.username, a.id_user, a.id_quest, a.tit
FROM (
SELECT p.time, qm.value as title, u.username, u.id as id_user, q.id as id_quest, qm.tit
FROM participation p INNER JOIN quests q 
ON p.id_quest = uq.id INNER JOIN users u
ON p.id_user = u.id INNER JOIN quests_meta qm
ON q.id = qm.id_quest
WHERE p.time > '2011-08-19 00:00:00' AND q.id = 2 AND p.vote = '1' AND p.id_quest_meta = -7
) AS a
WHERE a.tit = 'quest_title'
GROUP BY id_user 
ORDER BY time DESC;

The only downside is, that i had to add one more column (qm.tit) to the result table because i needed to query for it in the "select from subselect" (WHERE a.tit = 'quest_title').

0

精彩评论

暂无评论...
验证码 换一张
取 消