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 BYORDER 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

Results:

|                                  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 BYDISTINCT 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

上测试