获得明确的最高修订号

时间:2016-07-14 10:54:53

标签: sql postgresql

背景

我正在努力编写一个查询来为3个表中的每个id选择具有最高版本号的记录。 worksite id在所有3个表中共享,因此查询worksitedraft.id = 103和worksitesubmission.id = 103将分别返回不同状态的同一工作站。

所有3个表 worksite,worksiteDraft,worksiteSubmission 都有以下列:

id,name,reference,majorrevisionnumber,minorrevisionnumber

基本上我需要将所有三个表合并在一起,然后区分结果,但要确保每个结果都是3个表中具有最高版本号的记录。

当前解决方案

到目前为止,我有以下(工作)解决方案,但它非常讨厌,感觉必须有更好的方法。

创建一个联合在一起的3个表中所有工作场所的视图:

CREATE VIEW allworksites AS
SELECT * FROM 
(
    SELECT id, name, reference, 'worksiteDraft' as type, CONCAT(majorrevisionnumber, '.', minorrevisionnumber) as revisionnumber
    FROM worksitedraft
    UNION
    SELECT id, name, reference, 'worksiteSubmission' as type, CONCAT(majorrevisionnumber, '.', minorrevisionnumber) as revisionnumber
    FROM worksitesubmission
    UNION
    SELECT id, name, reference, 'worksite' as type, CONCAT(majorrevisionnumber, '.', minorrevisionnumber) as revisionnumber
    FROM worksite
) as allworksites;

然后使用嵌套选择通过按主要/次要修订号排序并限制为1

来计算类型
SELECT * FROM allworksites
WHERE id = 106
AND type = 

(
    SELECT type FROM
    (
        SELECT
            id,
            type,
            revisionnumber
        FROM 
        (
            SELECT 'worksiteDraft' as type, CONCAT(majorrevisionnumber, '.', minorrevisionnumber) as revisionnumber
            FROM worksitedraft
            WHERE id = allworksites.id
            UNION ALL
            SELECT 'worksiteSubmission' as type, CONCAT(majorrevisionnumber, '.', minorrevisionnumber) as revisionnumber
            FROM worksitesubmission
            WHERE id = allworksites.id
            UNION ALL
            SELECT 'worksite' as type, CONCAT(majorrevisionnumber, '.', minorrevisionnumber) as revisionnumber
            FROM worksite
            WHERE id = allworksites.id
        ) as latestrevision
        ORDER BY revisionnumber DESC
        limit 1
    ) as latestrevisiontype
)

问题

是否有另一种(可能是完全不同的)更好的方法来查询这些数据?

编辑。根据要求添加了样本数据和所需结果

样本数据

worksitedraft

| "id"| "name"          | "reference"| "majorrevisionnumber" | "minorrevisionnumber"
| 101 | "Worksite One"  | "ref-1"    | 1                     | 0
| 102 | "Worksite Two"  | "ref-2"    | 1                     | 0
| 103 | "Worksite Three"| "ref-3"    | 1                     | 0
| 104 | "Worksite Four" | "ref-4"    | 2                     | 0
| 105 | "Worksite Five" | "ref-5"    | 2                     | 0
| 106 | "Worksite Six"  | "ref-6"    | 3                     | 0

worksitesubmission

| "id"| "name"          | "reference"| "majorrevisionnumber" | "minorrevisionnumber"
| 101 | "Worksite One"  | "ref-1"    | 1                     | 1
| 102 | "Worksite Two"  | "ref-2"    | 1                     | 2
| 103 | "Worksite Three"| "ref-3"    | 1                     | 2
| 104 | "Worksite Four" | "ref-4"    | 1                     | 2
| 105 | "Worksite Five" | "ref-5"    | 2                     | 1
| 106 | "Worksite Six"  | "ref-6"    | 2                     | 2

工地

| "id"| "name"          | "reference"| "majorrevisionnumber" | "minorrevisionnumber"
| 101 | "Worksite One"  | "ref-1"    | 1                     | 2
| 102 | "Worksite Two"  | "ref-2"    | 1                     | 3
| 103 | "Worksite Three"| "ref-3"    | 1                     | 3
| 104 | "Worksite Four" | "ref-4"    | 1                     | 2
| 105 | "Worksite Five" | "ref-5"    | 2                     | 2
| 106 | "Worksite Six"  | "ref-6"    | 2                     | 3

期望的结果

| "id"| "name"          | "reference"| "majorrevisionnumber" | "minorrevisionnumber"
| 101 | "Worksite One"  | "ref-1"    | 1                     | 2
| 102 | "Worksite Two"  | "ref-2"    | 1                     | 3
| 103 | "Worksite Three"| "ref-3"    | 1                     | 3
| 104 | "Worksite Four" | "ref-4"    | 2                     | 0
| 105 | "Worksite Five" | "ref-5"    | 2                     | 2
| 106 | "Worksite Six"  | "ref-6"    | 3                     | 0

注意:我正在使用postgresql 9.4

编辑: @Gordon_Linoff和@a_horse_with_no_name

的建议后的最终解决方案
SELECT DISTINCT ON (id) * 
FROM (SELECT id, name, reference, 'worksiteDraft' as type, majorrevisionnumber, minorrevisionnumber
      FROM worksitedraft
      UNION ALL
      SELECT id, name, reference, 'worksiteSubmission' as type, majorrevisionnumber, minorrevisionnumber
      FROM worksitesubmission
      UNION ALL
      SELECT id, name, reference, 'worksite' as type, majorrevisionnumber, minorrevisionnumber
      FROM worksite
     ) allworksites
ORDER BY id, ARRAY[majorrevisionnumber, minorrevisionnumber]::int[] DESC;

1 个答案:

答案 0 :(得分:2)

您可以使用单个查询执行此操作。我认为最简单的方法是DISTINCT ON

SELECT DISTINCT ON (id) * 
FROM (SELECT id, name, reference, 'worksiteDraft' as type,
             CONCAT(majorrevisionnumber, '.', minorrevisionnumber) as revisionnumber
      FROM worksitedraft
      UNION ALL
      SELECT id, name, reference, 'worksiteSubmission' as type,      
             CONCAT(majorrevisionnumber, '.', minorrevisionnumber) as revisionnumber
      FROM worksitesubmission
      UNION ALL
      SELECT id, name, reference, 'worksite' as type, 
             CONCAT(majorrevisionnumber, '.', minorrevisionnumber) as revisionnumber
      FROM worksite
     ) allworksites
ORDER BY id, revisionnumber DESC;

注意:

  • 使用UNION ALL代替UNIONUNION会导致删除重复值的开销,这是不必要的开销。
  • 除非您的修订版本格式正确,否则连接它们可能不会返回最新值。 (即排序顺序为1.12之后的1.9)。但是,这是问题中使用的逻辑。
  • DISTINCT ONid返回一行,第一行根据ORDER BY子句遇到。
  • 视图不是必需的。

编辑:要修复订单号,请不要连接它们:

SELECT DISTINCT ON (id) * 
FROM (SELECT id, name, reference, 'worksiteDraft' as type,
             majorrevisionnumber, minorrevisionnumber
      FROM worksitedraft
      UNION ALL
      SELECT id, name, reference, 'worksiteSubmission' as type,      
             majorrevisionnumber, minorrevisionnumber
      FROM worksitesubmission
      UNION ALL
      SELECT id, name, reference, 'worksite' as type, 
             majorrevisionnumber, minorrevisionnumber
      FROM worksite
     ) allworksites
ORDER BY id, majorrevisionnumber DESC, minorrevisionnumber DESC;