美好的一天,
我有一个MySQL表说明,其中包含以下字段:lang_id,label,short_description,long_description和is_default。
在我的应用程序中,根据当前语言从数据库中提取产品描述。现在一切正常,但是我想为每个产品添加一个默认描述,以便找不到所需语言的描述,而是取代默认描述。
现在,我的请求看起来像这样:
SELECT
description.id AS record_id
description.label,
description.short_description,
description.long_description
FROM
products,
description,
languages
WHERE
products.id = '.$someProductID.' AND
products.id = description.product_id AND
languages.id = description.lang_id AND
languages.code = "'.$someLang.'"
当所需的翻译不存在时,是否有人有解决方案来获取产品的默认描述?
我想在我的请求中添加一些IFNULL语句,如下所示:
IFNULL(description.label, (SELECT label FROM description WHERE product_id = '.$someProductID.' AND is_default = 1) ) AS label
但我对这些复杂的查询并不是很熟悉,而且我无法使其发挥作用。
我愿意接受建议;)
谢谢!
答案 0 :(得分:2)
这一个:
SELECT p.*, COALESCE (dn.name, den.name) AS cname
FROM products p
LEFT JOIN
description dn
ON dn.product_id = p.id
AND dn.language =
(
SELECT id
FROM language
WHERE code = 'your_language'
)
LEFT JOIN
description den
ON den.product_id = p.id
AND den.is_default
)
WHERE p.id = @my_product
,或者这一个:
SELECT p.*,
COALESCE (dn.name,
(
SELECT den.name
FROM description den
WHERE den.product_id = p.id
AND den.is_default
)
) AS cname
FROM products p
LEFT JOIN
description dn
ON dn.product_id = p.id
AND dn.language =
(
SELECT id
FROM language
WHERE code = 'your_language'
)
WHERE p.id = @my_product
在除MySQL
之外的所有数据库中,当您的语言翻译较少时,第一个数据库效率更高,第二个数据库在您有大量翻译时效率更高。
在MySQL
中,第二个查询(COALESCE
)总是更有效率。
有关性能详情,请参阅我的博客中关于此问题的这一系列文章:
,并进一步导航其他RDBMS
的
答案 1 :(得分:1)
您可以在不同的别名(例如,默认值)下再次加入说明表,其中您只从默认语言中提取结果。不确定这是否比你的IFNULL想法更具表现力。
答案 2 :(得分:0)
您可以预先获取语言ID并使用它们来正确构建查询:
// this code is performed once and the results are stored for use in all description lookups
SELECT id INTO :def_lang_id FROM languages WHERE code = :default_lang_code;
SELECT id INTO :usr_lang_id FROM languages WHERE code = :user_lang_code;
// this is an example of using the above results to speed your search for the "correct" descriptions
if ($def_lang_id == $usr_lang_id) {
$sql = "SELECT d.id, d.label, d.short_desc, d.long_desc
FROM products p, description d
WHERE p.id = :some_prod_id
AND p.id = d.product_id
AND d.lang_id = :usr_lang_id";
} else {
$orderdirection = $def_lang_id < $usr_lang_id ? "DESC" : "ASC";
$sql = "SELECT d.id, d.label, d.short_desc, d.long_desc
FROM products p, description d
WHERE p.id = :some_prod_id
AND p.id = d.product_id
AND d.lang_id in (:def_lang_id, :usr_lang_id)
ORDER BY d.lang_id $langdirection";
}
现在,如果用户使用默认语言,则只获取一个描述。如果他们使用的是其他语言,则备用语言的lang_id将在查询中的default_id值之前排序。因此,如果存在备用描述,则在查询的第一行中返回,如果没有备用描述,则仅返回默认描述。
此代码的另一个明显好处是我们不需要每次都加入语言表。
答案 3 :(得分:0)
感谢您的帮助,我正在接近解决方案!
@jmucchiello:我不是在寻找PHP方面的验证。我希望MySQL完成所有工作,因为我将在许多其他SQL查询中使用它。
换句话说,我想提出该请求,将其存储在视图中,以便以简化的方式获取我的产品的翻译描述。类似于:descriptionView。
然后我会这样使用它:
SELECT * FROM descriptionView WHERE lang_code = "en" AND product_id = 80007
现在这就是我所拥有的:
SELECT
descriptions.code,
IFNULL(t1.label, t2.label) AS label,
IFNULL(t1.short_description, t2.short_description) AS short_description,
IFNULL(t1.long_description, t2.long_description) AS long_description
FROM
descriptions
LEFT JOIN
translations t1
ON
t1.description_id = descriptions.id AND t1.lang_id =
(
SELECT
id
FROM
languages
WHERE
code = "fr"
)
LEFT JOIN
translations t2
ON
t2.description_id = descriptions.id AND t2.is_default = 1
WHERE
descriptions.id = 1
它运行正常,但我需要删除硬编码的“1”和“fr”,因为我想在一个视图中对其进行转换,该视图将收集所有条目,然后对该视图执行选择。
问题是,出于某种原因,我无法将第一个左连接更改为:
LEFT JOIN
translations t1
ON
t1.description_id = descriptions.id AND t1.lang_id = languages.id
并在FROM子句中添加语言。
最后,我将删除WHERE子句,因为我想要所有结果。
因此,我的最终查询将如下所示:
CREATE VIEW descriptionView AS
SELECT
languages.code as lang,
descriptions.code,
IFNULL(t1.label, t2.label) AS label,
IFNULL(t1.short_description, t2.short_description) AS short_description,
IFNULL(t1.long_description, t2.long_description) AS long_description
FROM
descriptions,
languages
LEFT JOIN
translations t1
ON
t1.description_id = descriptions.id AND t1.lang_id = languages.id
LEFT JOIN
translations t2
ON
t2.description_id = descriptions.id AND t2.is_default = 1
然后我可以使用以下方式查询该视图:
SELECT * FROM descriptionView WHERE lang_code = "en" AND product_id = 80007