在PostgreSQL中通过另一个表的值选择一列

时间:2018-07-24 19:36:00

标签: postgresql

我有表个用户

user_id | lang_id
--------+---------
 12345  |    en 
 54321  |    ru
 77777  |    uz

和表格文本

text_id |   en   |   ru    |   uz
--------+--------+---------+-------
   hi   | Hello! | Привет! | Salom!
  bye   |  Bye!  |  Пока!  | Xayr!

我有两个信息:

  

user_id = 12345
  text_id ='hi'

并且我正在尝试查询,以获取用户所选语言的文本:

SELECT (SELECT lang_id FROM users WHERE user_id = 12345) FROM texts
WHERE text_id = 'hi'

并得到这个:

lang_id
------
  en
  

我应该收到文本“ Hello!”

如果您能帮助我解决这个问题,那么我是PostgreSQL的新手吧:)

3 个答案:

答案 0 :(得分:5)

虽然我100%建议将架构更改为适当的规范化,例如Jorge Campos在注释中提出的建议,但是您可以在CASE语句中使用一些硬编码来获取文本。

SELECT 
    CASE 
        WHEN users.lang_id = 'en' THEN texts.en
        WHEN users.lang_id = 'ru' THEN texts.ru
        WHEN users.lang_id = 'uz' THEN texts.uz
        END as user_language_text
FROM
    users, texts
WHERE
    user_id = 12345
    AND text_id = 'hi';

这里有一些主要的缺点:

  1. 从CPU角度来看,该CASE语句代价高昂
  2. 要确定从texts中检索数据的哪一列,必须对可能的语言值进行硬编码。这意味着每次添加新语言时,不仅需要向表中添加新列(本身就是主要的反模式),还必须调整所有SQL来适应。
  3. 您必须交叉联接(或不相关的子查询)以得出您的texts与用户的lang_id之间的关系。如果lang_id是文本表中的一列,则您可以在其中联接,然后在texts表中选择与用户的lang_id相对应的值。

再次。我强烈建议您重新考虑您的架构,因为这将使您陷入无法扩展的噩梦,将导致您不断编辑架构以及SQL中的硬代码值。

答案 1 :(得分:4)

最简单的方法是将行强制转换为json,然后动态访问字段。它与您的原始查询非常相似:

select row_to_json(t.*)->(select lang_id 
                            from users 
                           where user_id = 12345) 
  from texts t 
 where text_id = 'hi'

答案 2 :(得分:1)

我认为开发本地化方法不正确。您可以制作表texts 其参数为text_idlang_idtext。它可以帮助开发更灵活的

您可以的话

SELECT 
  case 
    when u.user_id = 'en' then t.en
    when u.user_id = 'ru' then t.ru
    when u.user_id = 'uz' then t.uz
    else t.en
  end as text
FROM texts as t
left join lateral (
  SELECT lang_id 
  FROM users 
  WHERE user_id = 12345
) as u on true 
WHERE text_id = 'hi'