【问题标题】:MYSQL - Grab value from different row and return them on the same rowMYSQL - 从不同行获取值并将它们返回到同一行
【发布时间】:2014-07-08 11:26:51
【问题描述】:

我正在使用 Laravel 4 开发一个多语言网站,我正在使用一个名为 waavi 翻译的翻译包,简而言之,它会抓取 laravel 的语言文本文件并将它们保存到数据库中。

我在以连贯的方式检索数据以将它们与数据表一起显示以创建语言翻译界面时遇到问题。

表结构如下:

语言表:

id | locale | name
---------------------
1  | en     | english
2  | fr     | french

等等……

Language_entries 表:

id  | language_id | namespace | group       | item         | text
--------------------------------------------------------------------
.....
9   | 1           | *         | permissions | save.success | :name has successfully been saved.
....
102 | 2           | *         | permissions | save.success | :name a bien été sauvegardé.
.....

我要查找的查询结果是:

group       | item         | en                                 | fr 
----------------------------------------------------------------------------------------------
permissions | save.success | :name has successfully been saved. | :name a bien été sauvegardé.

任何帮助将不胜感激!

【问题讨论】:

  • 为什么需要这种方式的结果?如果你正在翻译,你不能只从 language_entries 内部连接语言中选择文本 language.id = language_entries.language_id where locale = "something" and group = 'something' and item = 'something'?当这取决于您在数据库中拥有多少语言环境时,您将如何知道查询中有多少列。该查询不会很灵活。
  • 这种呈现结果集的方式的通用名称是“pivoting”。
  • @BojanKovacevic 我不会是唯一翻译网站的人,该界面将由客户端使用,我认为这种显示数据的方式对用户来说是有意义的。不过,我肯定会使用您的查询的变体来更新数据库。谢谢。
  • @OllieJones 这正是我要找的,我不熟悉这个词,快速搜索给了我很多可以学习的结果。是时候玩它了,谢谢;)

标签: php mysql sql laravel-4 pivot


【解决方案1】:

接受用户的@Notulysses 回答。您可以像这样在 Laravel(在 4.0 上测试)中使用 SQL 查询:

DB::table(DB::raw('language_entries t2'))
  ->select(
    't2.group',
    't2.item',
    DB::raw('GROUP_CONCAT(IF(t1.locale = "en", t2.`text`, NULL)) AS en'),
    DB::raw('GROUP_CONCAT(IF(t1.locale = "fr", t2.`text`, NULL)) AS fr')
  )
  ->leftJoin(DB::raw('languages t1'), function($join)
  {
    $join->on('t1.id', '=', 't2.language_id');
  })
  ->groupBy('t2.group', 't2.item')
  ->get();

我之所以在DB::table() 中使用DB::raw('') 是因为Laravel 会将language_entries t2 转换为'language_entries t2',这会破坏查询。 select 和 left join 的原因相同。

如果您想使用变量而不是手动添加语言环境,请确保使用

DB::connection()->getPdo()->quote("Safe")

为了保证查询安全。

【讨论】:

    【解决方案2】:

    如果您有超过 2 个语言环境,您可以使用动态版本来解决您的原始问题。

    SET @sql = NULL;
    SELECT
    GROUP_CONCAT(DISTINCT
        CONCAT(
          'MAX(CASE WHEN locale= ''',
          locale,
          ''' THEN text END) AS ',
          locale
        )
       )INTO @sql
    FROM language_entries t
    JOIN languages l
    ON t.language_id=l.id
    GROUP BY `group`,item;
    
    
    
    SET @sql=CONCAT('SELECT `group`,item,',@sql,' FROM
    language_entries t
    JOIN languages l
    ON t.language_id=l.id
    GROUP BY `group`,item');
    
    
    PREPARE stmt FROM @sql;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;
    

    或者只是非动态版本

    SELECT `group`,
    item,
    MAX(CASE WHEN locale= 'en' THEN text END) AS en
    ,MAX(CASE WHEN locale= 'et' THEN text END) AS et
    FROM language_entries t 
    JOIN languages l 
    ON t.language_id=l.id 
    GROUP BY `group`,item
    

    FIDDLE

    【讨论】:

    • 是否可以修改此 SQL 以采用 2 或 3 个变量的语言环境?如果可以,怎么办?
    【解决方案3】:

    正如上面所说,这个问题称为枢轴,我可以建议您使用以下解决方案,使用多个 IF 条件(与第一个表中唯一 locale 条目的数量一样多):

    SELECT t2.`group`
         , t2.`item`
         , GROUP_CONCAT(IF(t1.locale = 'en', t2.`text`, NULL)) AS en
         ...
         , GROUP_CONCAT(IF(t1.locale = 'fr', t2.`text`, NULL)) AS fr
    FROM `language_entries` t2 
    LEFT JOIN `languages` t1 ON t1.`id` = t2.`language_id`
    GROUP BY t2.`group`,
             t2.`item`
    

    SQLFiddle

    【讨论】:

    • 将表 table2 重命名为 language_entries,然后将 table 重命名为 languages,它确实有效。如果没有其他人在 23 小时内提交更好的替代方案,我会将 150 个代表归功于您。谢谢!
    猜你喜欢
    • 2021-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多