2014-10-16 241 views
1

考慮mysql的模式是這樣的:Mysql的GROUP_CONCAT()重新排序結果集

CREATE TABLE `translations` (
    group_id INT(11), 
    lang VARCHAR(2), 
    text VARCHAR(9), 
    UNIQUE INDEX `group_id_lang` (`group_id`, `lang`) 
) 

這應該是很明顯的這是怎麼回事 - 我有很多的翻譯​​一個GROUP_ID。

現在,如果我運行以下查詢,爲了獲得所有使用首選語言'EN'的組,並回退到'RU',並且如果這兩個翻譯均不存在,則回退到任何可用的語言,

SELECT * 
FROM (
    SELECT * 
    FROM translations 
    ORDER BY lang = 'EN' DESC, lang = 'RU' DESC 
) translations 
GROUP BY group_id 

+----------+------+---------+ 
| group_id | lang | text | 
+----------+------+---------+ 
|  1 | EN | Estonia | 
|  2 | EN | England | 
|  3 | RU | Швеция | 
+----------+------+---------+ 

正如你看到的我會得到3行與最後一跌回到「RU」,因爲「EN」不存在於該組。到目前爲止,所有好的..

現在,如果我想也加入GROUP_CONCAT(lang) AS translations選擇所有可用的語言爲一列,然後事情就變得有點模糊:

SELECT *, GROUP_CONCAT(lang) AS available_translations 
FROM (
    SELECT * 
    FROM translations 
    ORDER BY lang = 'EN' DESC, lang = 'RU' DESC 
) translations 
GROUP BY group_id 

+----------+------+-----------+--------------+ 
| group_id | lang | text | translations | 
+----------+------+-----------+--------------+ 
|  1 | ET | Eesti  | ET,EN,RU  | 
|  2 | ET | Inglismaa | ET,EN,RU  | 
|  3 | RU | Швеция | RU,ET  | 
+----------+------+-----------+--------------+ 

現在MySQL不尊重我ORDER BY條款,並按照本機順序進行分組,因爲根本沒有排序。

爲什麼GROUP_CONCAT會導致此問題?

  • 我最好的猜測是MySQL是重新排序的結果更容易的文本分組..

我怎樣才能使它工作有首選語言,並列出了適用的翻譯按行?

另外,如果你想擺弄然後here you go

回答

3

結果的順序,不能保證到最外面的查詢,所以即使您已訂購的子查詢,這是不保證的順序記錄被讀取,並由外部查詢返回。但主要問題是,您正在通過擴展濫用MySQL組,允許您選擇不包含在group by子句或聚合函數中的列。

爲了簡化您的查詢您有:

SELECT group_id, text 
FROM translations 
GROUP BY group_id 
ORDER BY lang = 'EN' DESC, lang = 'RU' DESC 

除非text函數依賴於group_id這打破了SQL標準,但儘管如此,MySQL允許它,但是,作爲MySQL documents

聲明

服務器可以自由選擇每組中的任何值,因此除非它們相同,否則所選值是不確定的。此外,每個組的值的選擇不能通過添加ORDER BY子句來影響。

所以,即使你有一個順序,這不適用,直到每組選擇一行後,這一行是不確定的。您所做的只是訂購最終結果集。

爲了解決這一點,並得到determinsitic結果,可以使用GROUP_CONCAT一起串聯的所有文本,並明確說出你的要求的順序:

GROUP_CONCAT(text ORDER BY lang = 'EN' DESC, lang = 'RU' DESC) 

然後使用SUBSTRING_INDEX只提取第一項。因此,您的查詢就會變成:

SELECT Group_id, 
     SUBSTRING_INDEX(
        GROUP_CONCAT(lang 
           ORDER BY lang = 'EN' DESC, 
             lang = 'RU' DESC), 
        ',', 1) AS lang, 
     SUBSTRING_INDEX(
        GROUP_CONCAT(text 
           ORDER BY lang = 'EN' DESC, 
             lang = 'RU' DESC), 
        ',', 1) AS Text, 
     GROUP_CONCAT(lang ORDER BY lang = 'EN' DESC, 
            lang = 'RU' DESC) AS available_translations 
FROM translations 
GROUP BY Group_id; 

Example on SQL Fiddle

+0

很好解釋,你每天學習新的東西:)另外,分組之前不加入其他表發生的,對不對?所以,如果我想加入與另一個表分組的結果,那麼我應該在子查詢中使用當前查詢? – Kristian 2014-10-16 14:21:00

+0

是的,加入發生在分組之前。我猜你會需要一個基於你所說的子查詢,但在一定程度上取決於你加入的是什麼。 – GarethD 2014-10-16 14:26:16

+0

嗯,實際上我的結構是這樣的:'[articles](id,created,user_id)''和[articles_lang](article_id,lang,標題,內容,其他可翻譯字段)' 我想創建一個列表所有文章,無論他們有哪些translataions。所以編輯可以用他/她的語言儘可能多地看,但仍然能夠看到所有的行。 但是,我可以從這裏拿它,這給了一些關於GROUP BY的解釋,以及挖掘到mysql手冊的理由。乾杯! – Kristian 2014-10-16 14:45:17