我正在嘗試使用左連接連接兩個表。并且結果集必須僅包含來自“正確”連接表的第一條記錄。
假設我有兩個表 products 和 product_translations 如下;
表“產品”
| ID | 價錢 |
|---|---|
| 1 | 100 |
| 2 | 150 |
表 'product_translations'
| ID | 產品編號 | 朗 | 柱子 | 價值 |
|---|---|---|---|---|
| 1 | 1 | 恩 | 標題 | 產品 1 標題 |
| 2 | 2 | 恩 | 標題 | 產品 2 標題 |
| 3 | 1 | 恩 | 描述 | 產品 1 描述 |
| 4 | 2 | 恩 | 描述 | 產品 2 說明 |
| 5 | 1 | 德 | 標題 | 產品 1 標題 |
| 6 | 2 | 德 | 標題 | 產品 2 標題 |
| 7 | 1 | 德 | 描述 | 產品 1 Beschreibung |
| 8 | 2 | 德 | 描述 | 產品 2 Beschreibung |
預期輸出
| ID | 價錢 | 標題 | 描述 |
|---|---|---|---|
| 1 | 100 | 產品 1 標題 | 產品 1 描述 |
| 2 | 150 | 產品 2 標題 | 產品 2 說明 |
uj5u.com熱心網友回復:
似乎您不想要“第一”行,而只是基于語言的兩個不同的行。所以你需要加入翻譯表:一個用于“標題”,一個用于“描述”
select p.*, t.description as title, d.description
from product p
left join product_translations t
on t.product_id = p.id
and t.language = 'en'
and t.column = 'title'
left join product_translations d
on d.product_id = p.id
and d.language = 'en'
and d.column = 'description'
如果您想使用“主要”和“后備”語言檢索它,您可以執行以下操作:
with product_texts as (
select t.product_id, t.value as title, d.value as description, t.lang
from product_translations t
join product_translations d
on d.product_id = t.product_id
and d.lang = t.lang
and d."column" = 'description'
where t."column" = 'title'
and t.product_id = 3
and t.lang in ('de', 'en')
)
select t.*
from product_texts t
order by case
when t.lang = 'de' then 1
else 2
end
limit 1
由于始終連接它有點復雜,因此您可以創建一個執行此操作的函式:
create function get_translations(p_product_id int, p_lang text, p_fallback_lang text default 'en')
returns table (product_id int, title text, description text, lang text)
as
$$
with product_texts as (
select t.product_id, t.value as title, d.value as description, t.lang
from product_translations t
join product_translations d
on d.product_id = t.product_id
and d.lang = t.lang
and d."column" = 'description'
where t."column" = 'title'
and t.product_id = 3
and t.lang in (p_lang, p_fallback_lang)
)
select t.*
from product_texts t
order by case
when t.lang = p_lang then 1
else 2
end
limit 1
$$
language sql
rows 1
stable;
然后你可以這樣做:
select *
from products p
left join lateral get_translations(p.id, 'de', 'en') on true
呼叫該函式幾乎沒有任何開銷,因為這將被行內 - 就像您已將函式的查詢寫入主查詢一樣。
為了獲得良好的性能,您需要一個索引(product_id, lang, "column")或什至兩個過濾索引:
create index product_lang_title
on product_translations (product_id, lang)
where "column" = 'title';
create index product_lang_descr
on product_translations (product_id, lang)
where "column" = 'description';
在線示例
uj5u.com熱心網友回復:
使用 row_number 定義第一行。我假設您的意思是“第一條記錄”是具有最低“id”值的記錄。
with prod_t as
(
select t1.*, row_number() over (partition by product_id, t1.column order by id) as rn
from product_translations t1
)
select p1.*, t2.value as title, t3.value as desctiption
from products p1
left join prod_t t2
on t2.product_id = p1.id
and t2.column = 'title'
and rn =1
left join prod_t t3
on t3.product_id = p1.id
and t3.column = 'description'
and rn =1
另外,最好避免使用“column”作為列名
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/366791.html
標籤:sql PostgreSQL的 左连接
