Postgres – 在值或自定义默认上进行筛选

huangapple go评论47阅读模式
英文:

Postgres - Where filter on value or custom default

问题

假设有一个存储给定“locale”下多个“items”的“locale_info”表

```sql
CREATE TABLE locale_info (
  locale TEXT,
  item_id TEXT
)

对于给定的“search_locale”,或者如果表中没有该“search_locale”的条目,则选择最干净的方法是什么?

我正在使用以下查询:

SELECT *
FROM locale_info
WHERE locale = COALESCE(
  (SELECT DISTINCT (locale) FROM locale_info WHERE locale = 'en_ZA'), 
  'en'
);

如果存在“en_ZA”项,它将返回这些项目,否则将返回默认的“en”语言环境。

我的问题是:如何以更干净的Postgres方式重写这个相当丑陋的查询?


<details>
<summary>英文:</summary>

Assuming a `locale_info` table that stores multiple `items` for a given `locale`

```sql
CREATE TABLE locale_info (
  locale TEXT,
  item_id TEXT
)

What is the cleanest way to select items for a given search_locale OR a default locale if table has no entries for the given search_locale?

I'm using the following:

SELECT *
FROM locale_info
WHERE locale = COALESCE(
  (SELECT DISTINCT (locale) FROM locale_info WHERE locale = &#39;en_ZA&#39;), 
  &#39;en&#39;
);

which will return en_ZA items if there are any, else the default en locale.

My question is: How do I rewrite that rather ugly query in a cleaner Postgres fashion?

答案1

得分: 1

以下是您要翻译的代码部分:

一种我可以想到的方法是使用 UNION ALL,只有在第一个返回了一行的情况下才运行第二个部分:

with requested as (
  SELECT *
  FROM locale_info
  WHERE locale = 'en_ZA'
)
select *
from requested
union all
SELECT *
FROM locale_info
where locale = 'en'
  and not exists (select * from requested);

另一种选择是始终选择两种区域设置,但按“重要性”对它们进行排序并丢弃第二个:

select *
from locale_info
where locale in ('en_ZA', 'en')
order by locale = 'en_ZA' desc
limit 1;

当对布尔值进行排序时,`false`  `true` 之前排序,所以通过按照 DESC 顺序排序,包含所需区域设置的行会首先出现。

无论如何,您应该在 `locale` 列上建立索引(或者在该列是第一列的索引)。
英文:

One way I can think of, is to use a UNION ALL, where the second part is only run if the first returned a row:

with requested as (
  SELECT *
  FROM locale_info
  WHERE locale = &#39;en_ZA&#39;
)
select *
from requested
union all
SELECT *
FROM locale_info
where locale = &#39;en&#39;
  and not exists (select * from requested);

Another option is to always select both locales but sort them by "importance" and discard the second one:

select *
from locale_info
where locale in (&#39;en_ZA&#39;, &#39;en&#39;)
order by locale = &#39;en_ZA&#39; desc
limit 1;

When sorting booleans, false is sorted before true, so by sorting DESCending, the row that contains the required locale comes first.

In any case, you should have an index on the locale column (or an index where that column is the first column)

huangapple
  • 本文由 发表于 2023年3月7日 00:54:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/75653641.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定