【问题标题】:Flag Records with highest version number within calculated field/calculated column as "true", rest as false将计算字段/计算列中版本号最高的记录标记为“真”,其余为假
【发布时间】:2018-09-28 10:29:50
【问题描述】:

环境:MS SQL Server 2016。

我有一个表格,其中包含(Jasper 报告)这样的布局表示(为简洁起见,仅显示相关字段):

ID        Name                          Key                           Version
  1       CoverLetter                   <guid1>                       1.00.00
  2       Contract                      <guid2>                       1.00.00
  3       CoverLetter                   <guid1>                       1.00.01

目标:

我需要一个额外的计算字段,根据该字段设置为 true 或 false 记录是否是任何给定 Layout 的最高版本(相同的布局但不同的版本有相同的 key,不同的布局有不同的 key)。

像这样:

ID:       Name:                 Key:          Version:      isHighestVersion: (calculated field)
  1       CoverLetter           <guid1>       1.00.00       false
  2       Contract              <guid2>       1.00.00       true
  3       CoverLetter           <guid1>       1.00.01       true

只显示每个 Layout 的最高版本的 SQL 查询是这样的:

( SELECT TACMasterlayouts.*
FROM
  (SELECT
     TACMasterLayoutKey, MAX(TACMasterLayoutVersion) as TACMasterLayoutVersion
   FROM
     TACMasterlayouts
   GROUP BY
     TACMasterLayoutKey) AS latest_TACMasterLayouts
INNER JOIN
  TACMasterlayouts
ON
  TACMasterlayouts.TACMasterLayoutKey = latest_TACMasterLayouts.TACMasterLayoutKey AND
  TACMasterlayouts.TACMasterLayoutVersion = latest_TACMasterLayouts.TACMasterLayoutVersion
) 

但我需要所有记录 - 每个相同键的版本号最高的记录标记为 true,其余记录标记为 false。

我已经做过的事情: 搜索了谷歌和 SO,但没有找到任何类似的东西我可以转换成我需要的东西。

【问题讨论】:

  • CASE WHEN ROW_NUMBER() OVER (PARTITION BY Key ORDER BY Version DESC) = 1 THEN 1 ELSE 0 END。需要一些程序集(ROW_NUMBER() 可能不允许直接在 CASE 中,并且需要子查询/CTE)。使用MAX 的解决方案也是可能的,并且可能会或可能不会更有效。

标签: sql-server sql-server-2016 calculated-columns


【解决方案1】:

只需将您的 INNER JOIN 更改为 LEFT OUTER JOIN

并在您的 选择 EG

CASE WHEN latest_TACMasterLayouts.TACMasterLayoutKey IS NOT NULL THEN 1  ELSE 0 END as isHighestVersion

【讨论】:

  • 这为我指明了正确的方向。谢谢。它必须是 RIGHT OUTER JOIN(我通过反复试验发现)- 否则只显示最高版本记录。
【解决方案2】:

谢谢约翰, 这为我指明了正确的方向。

它必须是 RIGHT OUTER JOIN - 否则只会显示最高版本的记录。

作为参考这里完整的工作代码:

SELECT TACMasterlayouts.*, CASE WHEN latest_TACMasterLayouts.TACMasterLayoutKey IS NOT NULL THEN 1  ELSE 0 END as isHighestVersion
FROM
  (SELECT TACMasterLayoutKey, MAX(TACMasterLayoutVersion) as TACMasterLayoutVersion
   FROM
     TACMasterlayouts
   GROUP BY
 TACMasterLayoutKey) AS latest_TACMasterLayouts
RIGHT OUTER JOIN
  TACMasterlayouts
ON
  TACMasterlayouts.TACMasterLayoutKey = latest_TACMasterLayouts.TACMasterLayoutKey AND
  TACMasterlayouts.TACMasterLayoutVersion = latest_TACMasterLayouts.TACMasterLayoutVersion
  ) 

【讨论】:

    【解决方案3】:

    你需要做一些解析才能得到想要的结果。

    首先,您将版本号拆分为单独的 int,然后根据它们分配 row_number,然后根据行号,您将 1-true 或 0-false 放在额外的列中,我称之为 IsLatest .

    在 SQL Server 中没有truefalse,您可以使用BIT 数据类型,它有两个值(就像布尔值一样):1 和 0。

    试试这个查询:

    declare @tbl table(ID int,Name varchar(20),[Key] varchar(10),Version varchar(10));
    insert into @tbl values 
    (1,'CoverLetter','<guid1>','1.00.00'),
    (2,'Contract','<guid2>','1.00.00'),
    (3,'CoverLetter','<guid1>','1.00.01');
    
    select ID, [Key], [version],
           case when rn = 1 then 1 else 0 end IsLatest
    from (
        select *,
               row_number() over (order by
                 cast(substring([version], 1, FirstDot - 1) as int) desc,
                 cast(substring([version], FirstDot + 1, SecondDot - FirstDot - 1) as int) desc,
                 cast(substring([version], SecondDot + 1, 100) as int) desc) rn
        from (
            select ID, [Key], [version],
                   charindex('.', [version]) FirstDot,
                   charindex('.', [version], charindex('.', [version]) + 1) SecondDot
            from @tbl
        ) a
    ) a
    

    【讨论】:

    • 在这里拆分版本号是多余的(因为这些部分恰好已经被填充了),但如果有必要,可以方便地重新调整PARSENAME 的用途。
    • @JeroenMostert 感谢您的评论。你的建议确实很方便,但我认为我的方法并不过分。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多