2009-08-24 76 views
3

日安抓取設置默認翻譯,數據庫的問題:從表中

我有一個MySQL表描述,持有領域,如:LANG_ID,標籤,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 

但我不是很熟悉這種複雜的查詢,我不能使它工作。

我願意接受建議;)

謝謝!

回答

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

+0

你的第一個例子看起來不錯,但我真的不明白你的語法。另外,i.id,「我」是什麼?這是一個錯誤? 您介意以我在問題中使用的格式重寫您的第一個示例嗎?這真的會幫助我理解,這會讓我去嘗試。 謝謝! – doM 2009-08-24 17:51:49

+0

'@ doM':對不起,只是從我的博客複製它,並沒有修復所有的名字。等一下! – Quassnoi 2009-08-24 17:53:03

+0

說我的數據庫不存在函數COALESCE。我正在使用MySQL 5.0.51a – doM 2009-08-24 18:10:06

1

你可以加入描述表再次在不同的別名(例如,默認值)下,您只需從默認語言中提取結果。不確定這是否比您的IFNULL想法更具性能拖累。

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值之前排序。因此,如果有替代描述,則返回查詢的第一行,如果沒有替代描述,則只返回默認描述。

這段代碼的另一個顯而易見的好處是我們不需要每次都加入語言表。

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