问题
Environment: MS SQL Server 2016.
I have a table which contains (Jasper Reports) layout representations like this (only relevant fields shown for brevity):
ID Name Key Version
1 CoverLetter <guid1> 1.00.00
2 Contract <guid2> 1.00.00
3 CoverLetter <guid1> 1.00.01
Goal:
I need an additional calculated field which is set to true or false according to whether the record is the highest version of any given Layout or not (Same layout but different versions have same key, different layouts have different key).
Like this:
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
The SQL query which shows only the highest versions of each Layout is like this:
( 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
)
But I need all records - the ones with highest version number per same key flagged with true and the rest flagged with false.
What I already did: Searched google and SO but didn't find anything similar which I could transform into what I need.
回答1:
Just change your INNER JOIN To a LEFT OUTER JOIN
and use a case in your Select EG
CASE WHEN latest_TACMasterLayouts.TACMasterLayoutKey IS NOT NULL THEN 1 ELSE 0 END as isHighestVersion
回答2:
Thanks John, this has pointed me into the right direction.
It has to be a RIGHT OUTER JOIN - otherwise only the records with highest version are shown.
As reference here the fully working code:
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:
You need to do some parsing in order to get desired result.
First, you split your version numbers into separate ints, then assign row_number
based on them, and then based on row number, you put 1-true or 0-false in a extra column, which I called IsLatest
.
In SQL Server there is no true
or false
, you can use BIT
datatype, which has two values (just like boolean): 1 and 0.
Try this query:
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
来源:https://stackoverflow.com/questions/52553410/flag-records-with-highest-version-number-within-calculated-field-calculated-colu