简体   繁体   English

Postgres中的优先选择语句

[英]Priority select statement in Postgres

I have rails application. 我有Rails应用程序。 in this application I use module globalize3 for i18n. 在此应用程序中,我将模块globalize3用于i18n。 I have table news and news_translations with this rows locale , description and title . 我有带有此行的localedescriptiontitle表格newsnews_translations I using join statement get all news checking current locale. 我使用join语句获取所有新闻检查当前区域设置。 It's correct work for current locale. 对于当前语言环境,这是正确的工作。 For example: 例如:

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

But I want make another logic. 但我想提出另一种逻辑。 If user from 'de' for example, I show him all news with locale 'de' and all news which haven't 'de' translation but have 'en' . 例如,如果来自'de'用户,我向他显示所有带有语言环境'de'新闻,以及所有没有'de'翻译但带有'en' When I try do it with OR statement I get one news in two translation 'de' and 'en' . 当我尝试使用OR语句执行此操作时,我得到两个翻译为'de''en' Have I can do correct using something like priorities. 我是否可以使用优先级之类的东西来纠正问题。

It's an awkward query. 这是一个尴尬的查询。 In a word, you need to OR the potential rows, and then compute the top row of the sub-result sets ordered by case when locale = 'it' then 1 when ... end . 简而言之,您需要对可能的行进行“或”运算,然后计算case when locale = 'it' then 1 when ... endcase when locale = 'it' then 1 when ... end排序的子结果集的顶行, case when locale = 'it' then 1 when ... end排序。 There are many ways to end up with the correct result (window functions in particular) but, frankly, you really don't want to go there for performace reasons. 有很多方法可以得出正确的结果(尤其是窗口函数),但是坦率地说,出于性能方面的考虑,您真的不想去那里。

Methinks revisit your assumptions, or alter your schema. Methinks重新审视您的假设,或更改您的架构。

One way to make it reasonably fast is to add an array column to news items, eg languages , that is maintained by a trigger. 使它相当快的一种方法是将数组列添加到由触发器维护的新闻项(例如languages )中。 Filter the top news (which I assume is what you're fetching) using that instead of joins against translations. 使用该新闻过滤热门新闻(我认为这是您要获取的新闻),而不是针对翻译进行联接。 (Note: depending on your Postgres version, avoid adding a GIST index on that column, because the selectivity of the && operator was hard-coded and would beat that of an order by/limit/offset using a btree beyond a certain row.) (注意:根据您的Postgres版本,请避免在该列上添加GIST索引,因为&&运算符的选择性是硬编码的,并且会使用超出特定行的btree超过/ by / limit / offset的顺序。)

Another way to make it reasonably fast is to track a separate feed table per language -- basically a materialized view that yields the ids of the query you're trying to build. 使其变得相当快的另一种方法是跟踪每种语言的单独的供稿表-基本上是一个物化视图,该视图产生您要构建的查询的ID。

Either option, as you see, amounts to partially or completely pre-computing the rows that will show for each language. 如您所见,这两种选择都等于部分或完全预先计算了每种语言所显示的行。 The first approach with an array column works fine in my own experience -- I like to use it for tags, to speed up and/or filters. 根据我自己的经验,使用数组列的第一种方法可以很好地工作-我喜欢将其用于标签,加快和/或过滤。

Consider seriously Denis' comments about performance and altering your schema. 认真考虑Denis关于性能和更改架构的评论。 However, the following does solve your problem and may be applicable if you don't let weighted_tables get too large. 但是,以下内容确实可以解决您的问题,并且如果您不让weighted_tables变得太大,则可能适用。 Note in particular that Common Table Expressions (the tables WITH generates,) have no indices on them. 请特别注意,公用表表达式(表WITH生成的表)上没有索引。

SQL Fiddle SQL小提琴

You can use DISTINCT and ORDER BY to trick it. 您可以使用DISTINCT和ORDER BY来欺骗它。

I do not know what are your primary and foreign keys for the news, but assuming it is 'news_id' you can do it that way: 我不知道您的新闻主键和外键是什么,但是假设它是“ 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;

That query will always return you the news articles once (no duplicates and multiple translations) and will preferably give you the 'de' translation (if it exists), if not it will fall into the 'en', and finally if both do not exist, it will give you the first translation found ordered by the 'locale'. 该查询将始终向您返回新闻文章一次(没有重复和多次翻译),并且最好为您提供“ de”翻译(如果存在),如果不存在,它将归为“ en”,如果两者均不包含存在,它将为您提供按“语言环境”排序的第一个翻译。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM