Postgres中的优先选择声明

时间:2013-12-14 17:14:38

标签: ruby-on-rails postgresql multilingual

我有rails应用程序。在这个应用程序中,我使用模块globalize3 for i18n。我的表格newsnews_translations包含localedescriptiontitle行。我使用join语句获取检查当前语言环境的所有新闻。这是当前语言环境的正确工作。例如:

WHERE "news_tranlations"."locale" = 'it'

但我想做另一个逻辑。例如,如果来自'de'的用户,我会向他显示包含区域设置'de'的所有新闻以及所有没有'de'翻译但拥有'en'的新闻。当我尝试使用OR语句时,我会在两个翻译'de''en'中收到一条新闻。我能用正确的优先事项做正确的事。

3 个答案:

答案 0 :(得分:1)

这是一个尴尬的问题。总之,您需要对潜在的行进行OR,然后计算由case when locale = 'it' then 1 when ... end排序的子结果集的顶行。有很多方法可以得到正确的结果(特别是窗口函数),但是,坦率地说,你真的不想因为性能原因去那里。

Methinks重新审视您的假设,或改变您的架构。

使其合理快速的一种方法是向新闻项添加数组列,例如languages,由触发器维护。使用它来过滤最新消息(我假设是你正在提取的消息),而不是对翻译进行连接。 (注意:根据你的Postgres版本,避免在该列上添加GIST索引,因为&&运算符的选择性是硬编码的,并且使用超出a的btree将超过/ limit / offset的顺序某一行。)

另一种使其速度相当快的方法是每种语言跟踪一个单独的Feed表 - 基本上是一个物化视图,它会产生您尝试构建的查询的ID。

如您所见,任何一个选项都等于部分或完全预先计算将为每种语言显示的行。使用数组列的第一种方法在我自己的经验中运行良好 - 我喜欢将它用于标记,加速和/或过滤。

答案 1 :(得分:1)

认真考虑Denis关于性能和改变架构的评论。但是,以下内容确实可以解决您的问题,如果您不让weighted_tables变得太大,则可能适用。请特别注意,公用表表达式(表格WITH生成)没有索引。

SQL Fiddle

答案 2 :(得分:1)

您可以使用DISTINCT和ORDER BY来欺骗它。

我不知道这个新闻的主键和外键是什么,但假设它是'news_id'你可以这样做:

SELECT
  DISTINCT ON (n.news_id),
  n.news_id,
  nt.title,
  nt.description
FROM
  news n INNER JOIN news_translation nt
ON
  n.news_id = nt.news_id
ORDER BY
  n.news_id,
  nt.locale != 'de',
  nt.locale != 'en',
  nt.locale;

该查询将始终返回新闻文章一次(没有重复和多次翻译),并且最好会给你'de'翻译(如果存在),如果不存在,它将落入'en',最后如果两者都不存在,它将为您提供第一个按“语言环境”排序的翻译。