数据库问题:从表中获取默认转换

时间:2009-08-24 17:36:36

标签: mysql database

美好的一天,

我有一个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

但我对这些复杂的查询并不是很熟悉,而且我无法使其发挥作用。

我愿意接受建议;)

谢谢!

4 个答案:

答案 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