Postgresql 在根据条件检索过程中从 table 中删除重复项
Postgresql remove duplicates from table in process of retrieval based on criteria
我有一个业务逻辑,我想从数据库中检索翻译,可以覆盖翻译,因此应在可用时检索覆盖的翻译。
Schema:
i18n
-----
id
slug // unique
i18nTranslations
--------------
id
i18nId // referencing i18n.id
langId
text
overriddenType // pageOverride / instanceOverride
i18nPageOverrides
-----------------
id
translationId // referencing i18nTranslations.id
instanceId
pageId
Example:
i18nTranslations
------------------------------------------------------
id i18nId langId text type overrideType
------------------------------------------------------
1 | ABC | En | AAX | static |
2 | ABC | En | AAX Ovd | static | pageOverride
3 | ABC | Tr | TDF | static |
i18nPageOverride
--------------------------
transId pageId instanceId
--------------------------
2 login admin
Expected Output:
------------------------------------------------------
id i18nId langId text type overrideType
------------------------------------------------------
2 | ABC | En | AAX Ovd | static | pageOverride // overridden data
3 | ABC | Tr | TDF | static |
在上面的预期输出中,带有“AAX”文本的行已被删除,因为它已覆盖语言的行。
是否有任何方法可以仅通过使用查询来实现此行为?
您可以使用ROW_NUMBER
window函数PARTITION BY
和ORDER BY
为重复的数字创建行号然后过滤rn = 1
行。
查询 1:
SELECT "iId",
"itI18nId",
"itLangId",
"itText",
"itType",
"itOverrideType"
FROM (
SELECT *,
ROW_NUMBER() OVER(PARTITION BY "itI18nId","itLangId" ORDER BY "itOverrideType","iCreatedAt") rn
FROM i18n i
INNER JOIN i18n_translations t
ON i."iId" = t."itI18nId"
LEFT JOIN i18n_page_override o
ON o."ipoTranslationId" = t."itId"
) t1
WHERE rn = 1
| iId | itI18nId | itLangId | itText | itType | itOverrideType |
|--------------------------------------|--------------------------------------|--------------------------------------|--------|--------------|----------------|
| b76481bc-1171-4fb3-8433-31302ae39a81 | b76481bc-1171-4fb3-8433-31302ae39a81 | 175376f6-9dc8-4bea-bbc0-bf93744999c9 | Adi | staticNormal | (null) |
| b76481bc-1171-4fb3-8433-31302ae39a81 | b76481bc-1171-4fb3-8433-31302ae39a81 | 875dbdbb-9cb2-4f1b-a8ca-096321a0cd36 | Fn Ovd | staticNormal | stPageOverride |
带有 ORDER BY
的 DISTINCT ON 表达式可能是完美的选择。
排序可以降序 i18nPageOverrides.id,空值排在最后。
DISTINCT ON ( expression [, ...] ) keeps only the first row of each
set of rows where the given expressions evaluate to equal. The
DISTINCT ON expressions are interpreted using the same rules as for
ORDER BY (see above).
SELECT DISTINCT ON (tr.i18nId, tr.langId)
tr.id, tr.i18nId, tr.langId, tr.itText, tr.itType, tr.overrideType
FROM i18nTranslations tr
LEFT JOIN i18nPageOverrides po ON po.translationId = tr.id
ORDER BY tr.i18nId, tr.langId, po.id DESC NULLS LAST, tr.id;
id
i18nid
langid
ittext
ittype
overridetype
2
ABC
En
AAX Ovd
static
pageOverride
3
ABC
Tr
TDF
static
null
在 db<>fiddle here
上测试
我有一个业务逻辑,我想从数据库中检索翻译,可以覆盖翻译,因此应在可用时检索覆盖的翻译。
Schema:
i18n
-----
id
slug // unique
i18nTranslations
--------------
id
i18nId // referencing i18n.id
langId
text
overriddenType // pageOverride / instanceOverride
i18nPageOverrides
-----------------
id
translationId // referencing i18nTranslations.id
instanceId
pageId
Example:
i18nTranslations
------------------------------------------------------
id i18nId langId text type overrideType
------------------------------------------------------
1 | ABC | En | AAX | static |
2 | ABC | En | AAX Ovd | static | pageOverride
3 | ABC | Tr | TDF | static |
i18nPageOverride
--------------------------
transId pageId instanceId
--------------------------
2 login admin
Expected Output:
------------------------------------------------------
id i18nId langId text type overrideType
------------------------------------------------------
2 | ABC | En | AAX Ovd | static | pageOverride // overridden data
3 | ABC | Tr | TDF | static |
在上面的预期输出中,带有“AAX”文本的行已被删除,因为它已覆盖语言的行。
是否有任何方法可以仅通过使用查询来实现此行为?
您可以使用ROW_NUMBER
window函数PARTITION BY
和ORDER BY
为重复的数字创建行号然后过滤rn = 1
行。
查询 1:
SELECT "iId",
"itI18nId",
"itLangId",
"itText",
"itType",
"itOverrideType"
FROM (
SELECT *,
ROW_NUMBER() OVER(PARTITION BY "itI18nId","itLangId" ORDER BY "itOverrideType","iCreatedAt") rn
FROM i18n i
INNER JOIN i18n_translations t
ON i."iId" = t."itI18nId"
LEFT JOIN i18n_page_override o
ON o."ipoTranslationId" = t."itId"
) t1
WHERE rn = 1
| iId | itI18nId | itLangId | itText | itType | itOverrideType |
|--------------------------------------|--------------------------------------|--------------------------------------|--------|--------------|----------------|
| b76481bc-1171-4fb3-8433-31302ae39a81 | b76481bc-1171-4fb3-8433-31302ae39a81 | 175376f6-9dc8-4bea-bbc0-bf93744999c9 | Adi | staticNormal | (null) |
| b76481bc-1171-4fb3-8433-31302ae39a81 | b76481bc-1171-4fb3-8433-31302ae39a81 | 875dbdbb-9cb2-4f1b-a8ca-096321a0cd36 | Fn Ovd | staticNormal | stPageOverride |
带有 ORDER BY
的 DISTINCT ON 表达式可能是完美的选择。
排序可以降序 i18nPageOverrides.id,空值排在最后。
DISTINCT ON ( expression [, ...] ) keeps only the first row of each set of rows where the given expressions evaluate to equal. The DISTINCT ON expressions are interpreted using the same rules as for ORDER BY (see above).
SELECT DISTINCT ON (tr.i18nId, tr.langId) tr.id, tr.i18nId, tr.langId, tr.itText, tr.itType, tr.overrideType FROM i18nTranslations tr LEFT JOIN i18nPageOverrides po ON po.translationId = tr.id ORDER BY tr.i18nId, tr.langId, po.id DESC NULLS LAST, tr.id;
id i18nid langid ittext ittype overridetype 2 ABC En AAX Ovd static pageOverride 3 ABC Tr TDF static null
在 db<>fiddle here
上测试