Question

I'm stuck a little with a combine MySQL query. It's a part of a multi-language, multi-destination site, so I need to retrieve some text parts of the site from multiple table, with fallback. Order of possible hits:

corrected@local_tbl > english@local_tbl > corrected@global_tbl > english@global_tbl.

Because it'll be highly used, I'd like to keep it fast and with low number of connections, but returning only 1 row. I tried a few approaches as follows, but I'm sure there is a better solution.


Subquery in FROM clause: It dies if any of subquery gives 0 rows. Even if it works, needs some php interpret:

SELECT * FROM

(SELECT `sp_content` AS sp_local FROM `loc-ae_siteparts` WHERE `sp_name` = 'name_of_some_sitepart' AND `sp_lang` = 'de' AND `sp_corrected`='1' LIMIT 1) as local,
(SELECT `sp_content` AS sp_local_en FROM `loc-ae_siteparts` WHERE `sp_name` = 'name_of_some_sitepart' AND `sp_lang` = 'en' LIMIT 1) as local_en,
(SELECT `sp_content` AS sp_global, `sp_corrected` as sp_global_corrected FROM `loc-global_siteparts` WHERE `sp_name` = 'name_of_some_sitepart' AND `sp_lang` = 'de' LIMIT 1) as global,
(SELECT `sp_content` AS sp_global_en FROM `loc-global_siteparts` WHERE `sp_name` = 'name_of_some_sitepart' AND `sp_lang` = 'en' LIMIT 1) as global_en

TEMP Table: Here I am concerned about performance, can't use memory engine because it involves a text field. Wasted nuke for a birdie?

CREATE TEMPORARY TABLE IF NOT EXISTS `random_tbl_name` AS (SELECT `sp_content` FROM `loc-global_siteparts` LIMIT 0);

INSERT INTO `random_tbl_name` SELECT `sp_content` FROM `loc-ae_siteparts` WHERE `sp_name` = 'name_of_some_sitepart' AND `sp_lang` = 'de' AND `sp_corrected` = '1' LIMIT 1;
INSERT INTO `random_tbl_name` SELECT `sp_content` FROM `loc-ae_siteparts` WHERE `sp_name` = 'name_of_some_sitepart' AND `sp_lang` = 'en' LIMIT 1;
INSERT INTO `random_tbl_name` SELECT `sp_content` FROM `loc-global_siteparts` WHERE `sp_name` = 'name_of_some_sitepart' AND `sp_lang` = 'de' AND `sp_corrected` = '1' LIMIT 1;
INSERT INTO `random_tbl_name` SELECT `sp_content` FROM `loc-global_siteparts` WHERE `sp_name` = 'name_of_some_sitepart' AND `sp_lang` = 'en' LIMIT 1;

SELECT * FROM `random_tbl_name` LIMIT 1;

EDIT: Thanks for all answers, they were really helpful.

Was it helpful?

Solution

SELECT * FROM
    ((SELECT 1 precedence, `sp_content`
     FROM `loc-ae_siteparts` 
     WHERE `sp_name` = 'name_of_some_sitepart' AND `sp_lang` = 'de' AND `sp_corrected`='1'
     LIMIT 1)
     UNION
     (SELECT 2 precedence, `sp_content` 
     FROM `loc-ae_siteparts` 
     WHERE `sp_name` = 'name_of_some_sitepart' AND `sp_lang` = 'en' 
     LIMIT 1)
     UNION
     ...
    ) x
ORDER BY precedence
LIMIT 1

OTHER TIPS

The reason you get no result when one of the subqueries is empty is, with

select * from
s1, s2, s3, s4

you have an implicit join. And when one of the sub-results is empty, the resulting join is empty as well.

To solve this, you can use your subqueries as columns. This will give you the same result, but with NULL values, where the subselect returns no rows

SELECT (SELECT `sp_content` AS sp_local FROM `loc-ae_siteparts` WHERE `sp_name` = 'name_of_some_sitepart' AND `sp_lang` = 'de' AND `sp_corrected`='1' LIMIT 1) as local,
       (SELECT `sp_content` AS sp_local_en FROM `loc-ae_siteparts` WHERE `sp_name` = 'name_of_some_sitepart' AND `sp_lang` = 'en' LIMIT 1) as local_en,
       (SELECT `sp_content` AS sp_global, `sp_corrected` as sp_global_corrected FROM `loc-global_siteparts` WHERE `sp_name` = 'name_of_some_sitepart' AND `sp_lang` = 'de' LIMIT 1) as global,
       (SELECT `sp_content` AS sp_global_en FROM `loc-global_siteparts` WHERE `sp_name` = 'name_of_some_sitepart' AND `sp_lang` = 'en' LIMIT 1) as global_en

I've done similar things in the past like this:

SELECT COALESCE(ls1.sp_content, ls2.sp_content) AS sp_content
FROM (SELECT 1) a
LEFT JOIN loc-ae_siteparts ls1
  ON ls1.sp_name = 'name_of_some_sitepart' AND ls1.sp_lang = 'de' AND ls1.sp_corrected = '1'
LEFT JOIN loc-ae_siteparts ls2
  ON ls2.sp_name = 'name_of_some_sitepart' and ls2.sp_lang = 'en'
LIMIT 1
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top