首页 > 解决方案 > 获取组中的最新行

问题描述

我目前正在使用我的 TSQL 数据库中的一系列表,这些表允许我获取有关投保人(或客户)的信息。我需要按出生日期和邮政编码开始对每个投保人进行分组,因为其他匹配不够可靠。

我目前遇到的问题是这将显示该组中的最大值,而不是最新值。遗憾的是,由于 GDPR 的原因,我无法提供任何数据,希望有人可以通过我的查询引导我朝着正确的方向前进。

询问:

SELECT MAX([MSM_MarketPricing].[EnquiryKey]) AS EnquiryKey
      ,MAX([TotalNumberOfQuotes]) AS TotalNumberOfQuotes
      ,MAX([MarketPriceTop5Annual]) AS MarketPriceTop5Annual
      ,MAX([DirectInsPriceTop5Annual]) AS DirectInsPriceTop5Annual
      ,MAX([BrokerPriceTop5Annual]) AS BrokerPriceTop5Annual
      ,MAX([BigBrandsPriceTop5Annual]) AS BigBrandsPriceTop5Annual
      ,MAX([MediumBrandsTop5Annual]) AS MediumBrandsTop5Annual
      ,MAX([LittleBrandsPriceTop5Annual]) AS LittleBrandsPriceTop5Annual
      ,MAX([MSM_YourQuotes].[YourAnnualPrice]) AS YourAnnualPrice
      ,'   ' AS ' '

      -- Number Prediction Calculations --
      ,MAX([MarketPriceTop5Annual]) * ((100 +
      (CASE
      WHEN LEAST(MAX([MarketPriceTop5Annual]), MAX([DirectInsPriceTop5Annual]), MAX([BrokerPriceTop5Annual]), MAX([BigBrandsPriceTop5Annual]), MAX([MediumBrandsTop5Annual]), MAX([LittleBrandsPriceTop5Annual])) BETWEEN 0 AND 250 THEN -7.09
      WHEN LEAST(MAX([MarketPriceTop5Annual]), MAX([DirectInsPriceTop5Annual]), MAX([BrokerPriceTop5Annual]), MAX([BigBrandsPriceTop5Annual]), MAX([MediumBrandsTop5Annual]), MAX([LittleBrandsPriceTop5Annual])) BETWEEN 251 AND 500 THEN -8.52
      WHEN LEAST(MAX([MarketPriceTop5Annual]), MAX([DirectInsPriceTop5Annual]), MAX([BrokerPriceTop5Annual]), MAX([BigBrandsPriceTop5Annual]), MAX([MediumBrandsTop5Annual]), MAX([LittleBrandsPriceTop5Annual])) BETWEEN 501 AND 750 THEN -12.11
      WHEN LEAST(MAX([MarketPriceTop5Annual]), MAX([DirectInsPriceTop5Annual]), MAX([BrokerPriceTop5Annual]), MAX([BigBrandsPriceTop5Annual]), MAX([MediumBrandsTop5Annual]), MAX([LittleBrandsPriceTop5Annual])) BETWEEN 751 AND 1000 THEN -14.63
      WHEN LEAST(MAX([MarketPriceTop5Annual]), MAX([DirectInsPriceTop5Annual]), MAX([BrokerPriceTop5Annual]), MAX([BigBrandsPriceTop5Annual]), MAX([MediumBrandsTop5Annual]), MAX([LittleBrandsPriceTop5Annual])) BETWEEN 1001 AND 1500 THEN -16.88
      WHEN LEAST(MAX([MarketPriceTop5Annual]), MAX([DirectInsPriceTop5Annual]), MAX([BrokerPriceTop5Annual]), MAX([BigBrandsPriceTop5Annual]), MAX([MediumBrandsTop5Annual]), MAX([LittleBrandsPriceTop5Annual])) BETWEEN 1501 AND 2000 THEN -18.00
      WHEN LEAST(MAX([MarketPriceTop5Annual]), MAX([DirectInsPriceTop5Annual]), MAX([BrokerPriceTop5Annual]), MAX([BigBrandsPriceTop5Annual]), MAX([MediumBrandsTop5Annual]), MAX([LittleBrandsPriceTop5Annual])) BETWEEN 2001 AND 2500 THEN -19.42
      ELSE -27.48 END)) / 100) AS 'MarketPriceFromBucket'

      -- Number Prediction Calculations --
      ,MAX([DirectInsPriceTop5Annual]) * ((100 +
      (CASE
      WHEN LEAST(MAX([MarketPriceTop5Annual]), MAX([DirectInsPriceTop5Annual]), MAX([BrokerPriceTop5Annual]), MAX([BigBrandsPriceTop5Annual]), MAX([MediumBrandsTop5Annual]), MAX([LittleBrandsPriceTop5Annual])) BETWEEN 0 AND 250 THEN -7.09
      WHEN LEAST(MAX([MarketPriceTop5Annual]), MAX([DirectInsPriceTop5Annual]), MAX([BrokerPriceTop5Annual]), MAX([BigBrandsPriceTop5Annual]), MAX([MediumBrandsTop5Annual]), MAX([LittleBrandsPriceTop5Annual])) BETWEEN 251 AND 500 THEN -8.52
      WHEN LEAST(MAX([MarketPriceTop5Annual]), MAX([DirectInsPriceTop5Annual]), MAX([BrokerPriceTop5Annual]), MAX([BigBrandsPriceTop5Annual]), MAX([MediumBrandsTop5Annual]), MAX([LittleBrandsPriceTop5Annual])) BETWEEN 501 AND 750 THEN -12.11
      WHEN LEAST(MAX([MarketPriceTop5Annual]), MAX([DirectInsPriceTop5Annual]), MAX([BrokerPriceTop5Annual]), MAX([BigBrandsPriceTop5Annual]), MAX([MediumBrandsTop5Annual]), MAX([LittleBrandsPriceTop5Annual])) BETWEEN 751 AND 1000 THEN -14.63
      WHEN LEAST(MAX([MarketPriceTop5Annual]), MAX([DirectInsPriceTop5Annual]), MAX([BrokerPriceTop5Annual]), MAX([BigBrandsPriceTop5Annual]), MAX([MediumBrandsTop5Annual]), MAX([LittleBrandsPriceTop5Annual])) BETWEEN 1001 AND 1500 THEN -16.88
      WHEN LEAST(MAX([MarketPriceTop5Annual]), MAX([DirectInsPriceTop5Annual]), MAX([BrokerPriceTop5Annual]), MAX([BigBrandsPriceTop5Annual]), MAX([MediumBrandsTop5Annual]), MAX([LittleBrandsPriceTop5Annual])) BETWEEN 1501 AND 2000 THEN -18.00
      WHEN LEAST(MAX([MarketPriceTop5Annual]), MAX([DirectInsPriceTop5Annual]), MAX([BrokerPriceTop5Annual]), MAX([BigBrandsPriceTop5Annual]), MAX([MediumBrandsTop5Annual]), MAX([LittleBrandsPriceTop5Annual])) BETWEEN 2001 AND 2500 THEN -19.42
      ELSE -27.48 END)) / 100) AS 'DirectInsPriceFromBucket'

      -- Number Prediction Calculations --
      ,MAX([BrokerPriceTop5Annual]) * ((100 +
      (CASE
      WHEN LEAST(MAX([MarketPriceTop5Annual]), MAX([DirectInsPriceTop5Annual]), MAX([BrokerPriceTop5Annual]), MAX([BigBrandsPriceTop5Annual]), MAX([MediumBrandsTop5Annual]), MAX([LittleBrandsPriceTop5Annual])) BETWEEN 0 AND 250 THEN -7.09
      WHEN LEAST(MAX([MarketPriceTop5Annual]), MAX([DirectInsPriceTop5Annual]), MAX([BrokerPriceTop5Annual]), MAX([BigBrandsPriceTop5Annual]), MAX([MediumBrandsTop5Annual]), MAX([LittleBrandsPriceTop5Annual])) BETWEEN 251 AND 500 THEN -8.52
      WHEN LEAST(MAX([MarketPriceTop5Annual]), MAX([DirectInsPriceTop5Annual]), MAX([BrokerPriceTop5Annual]), MAX([BigBrandsPriceTop5Annual]), MAX([MediumBrandsTop5Annual]), MAX([LittleBrandsPriceTop5Annual])) BETWEEN 501 AND 750 THEN -12.11
      WHEN LEAST(MAX([MarketPriceTop5Annual]), MAX([DirectInsPriceTop5Annual]), MAX([BrokerPriceTop5Annual]), MAX([BigBrandsPriceTop5Annual]), MAX([MediumBrandsTop5Annual]), MAX([LittleBrandsPriceTop5Annual])) BETWEEN 751 AND 1000 THEN -14.63
      WHEN LEAST(MAX([MarketPriceTop5Annual]), MAX([DirectInsPriceTop5Annual]), MAX([BrokerPriceTop5Annual]), MAX([BigBrandsPriceTop5Annual]), MAX([MediumBrandsTop5Annual]), MAX([LittleBrandsPriceTop5Annual])) BETWEEN 1001 AND 1500 THEN -16.88
      WHEN LEAST(MAX([MarketPriceTop5Annual]), MAX([DirectInsPriceTop5Annual]), MAX([BrokerPriceTop5Annual]), MAX([BigBrandsPriceTop5Annual]), MAX([MediumBrandsTop5Annual]), MAX([LittleBrandsPriceTop5Annual])) BETWEEN 1501 AND 2000 THEN -18.00
      WHEN LEAST(MAX([MarketPriceTop5Annual]), MAX([DirectInsPriceTop5Annual]), MAX([BrokerPriceTop5Annual]), MAX([BigBrandsPriceTop5Annual]), MAX([MediumBrandsTop5Annual]), MAX([LittleBrandsPriceTop5Annual])) BETWEEN 2001 AND 2500 THEN -19.42
      ELSE -27.48 END)) / 100) AS 'BrokerPriceFromBucket'

      ,'   ' AS '  '
      ,CAST(MAX([MSM_YourQuotes].[YourAnnualPrice]) - MAX([MarketPriceTop5Annual]) * ((100 +
      (CASE
      WHEN LEAST(MAX([MarketPriceTop5Annual]), MAX([DirectInsPriceTop5Annual]), MAX([BrokerPriceTop5Annual]), MAX([BigBrandsPriceTop5Annual]), MAX([MediumBrandsTop5Annual]), MAX([LittleBrandsPriceTop5Annual])) BETWEEN 0 AND 250 THEN -7.09
      WHEN LEAST(MAX([MarketPriceTop5Annual]), MAX([DirectInsPriceTop5Annual]), MAX([BrokerPriceTop5Annual]), MAX([BigBrandsPriceTop5Annual]), MAX([MediumBrandsTop5Annual]), MAX([LittleBrandsPriceTop5Annual])) BETWEEN 251 AND 500 THEN -8.52
      WHEN LEAST(MAX([MarketPriceTop5Annual]), MAX([DirectInsPriceTop5Annual]), MAX([BrokerPriceTop5Annual]), MAX([BigBrandsPriceTop5Annual]), MAX([MediumBrandsTop5Annual]), MAX([LittleBrandsPriceTop5Annual])) BETWEEN 501 AND 750 THEN -12.11
      WHEN LEAST(MAX([MarketPriceTop5Annual]), MAX([DirectInsPriceTop5Annual]), MAX([BrokerPriceTop5Annual]), MAX([BigBrandsPriceTop5Annual]), MAX([MediumBrandsTop5Annual]), MAX([LittleBrandsPriceTop5Annual])) BETWEEN 751 AND 1000 THEN -14.63
      WHEN LEAST(MAX([MarketPriceTop5Annual]), MAX([DirectInsPriceTop5Annual]), MAX([BrokerPriceTop5Annual]), MAX([BigBrandsPriceTop5Annual]), MAX([MediumBrandsTop5Annual]), MAX([LittleBrandsPriceTop5Annual])) BETWEEN 1001 AND 1500 THEN -16.88
      WHEN LEAST(MAX([MarketPriceTop5Annual]), MAX([DirectInsPriceTop5Annual]), MAX([BrokerPriceTop5Annual]), MAX([BigBrandsPriceTop5Annual]), MAX([MediumBrandsTop5Annual]), MAX([LittleBrandsPriceTop5Annual])) BETWEEN 1501 AND 2000 THEN -18.00
      WHEN LEAST(MAX([MarketPriceTop5Annual]), MAX([DirectInsPriceTop5Annual]), MAX([BrokerPriceTop5Annual]), MAX([BigBrandsPriceTop5Annual]), MAX([MediumBrandsTop5Annual]), MAX([LittleBrandsPriceTop5Annual])) BETWEEN 2001 AND 2500 THEN -19.42
      ELSE -27.48 END)) / 100) AS INT) as 'CostDiffBucket'
      ,CAST(MAX([MSM_YourQuotes].[YourAnnualPrice]) - MAX([MarketPriceTop5Annual]) AS INT) as 'CostDiff'
      ,FLOOR(ROUND(100.0*(MAX([MSM_YourQuotes].[YourAnnualPrice]) - MAX([MarketPriceTop5Annual])) / MAX([MarketPriceTop5Annual]), 2)) AS PercentDiff
      ,CAST(CASE WHEN DATEADD(yy, DATEDIFF(yy, MAX([MSM_PolicyHolder].[DateOfBirth]), GETDATE()), MAX([MSM_PolicyHolder].[DateOfBirth])) < GETDATE() THEN DATEDIFF(yy, MAX([MSM_PolicyHolder].[DateOfBirth]), GETDATE()) ELSE DATEDIFF(yy, MAX([MSM_PolicyHolder].[DateOfBirth]), GETDATE()) - 1 END AS INT) AS 'Age'
      ,MAX([MSM_PolicyHolder].[DateOfBirth]) AS DateOfBirth
      ,MAX([MSM_PolicyHolder].[NoClaimsDiscountYears]) AS NoClaimsDiscountYears
      ,MAX([MSM_PolicyHolder].[LicenceHeldForMonths])/12 as 'LicenseLength'
      ,CAST(CASE WHEN DATEADD(yy, DATEDIFF(yy, MAX([MSM_Enquiry].[FirstStartedDrivingCar]), GETDATE()), MAX([MSM_Enquiry].[FirstStartedDrivingCar])) < GETDATE() THEN DATEDIFF(yy, MAX([MSM_Enquiry].[FirstStartedDrivingCar]), GETDATE()) ELSE DATEDIFF(yy, MAX([MSM_Enquiry].[FirstStartedDrivingCar]), GETDATE()) - 1 END AS INT) AS 'YearsOwned'
      ,MAX([MSM_Enquiry].[CarValue])
      -- Sub-Filters
      ,MAX([MSM_PolicyHolder].[Gender]) AS Gender
      ,MAX([MSM_PolicyHolder].[MaritalStatus]) AS MaritalStatus
      ,MAX([MSM_PolicyHolder].[MainBusinessType]) AS MainBusinessType
      ,CASE WHEN MAX([MIU_BusinessCats].[FTBusinessType]) IS NULL then 'Other' ELSE MAX([MIU_BusinessCats].[FTBusinessType]) END AS 'OccupationIndustry'
      ,MAX([MSM_PolicyHolder].[MainEmploymentStatus]) AS MainEmploymentStatus
      ,MAX([MSM_PolicyHolder].[LicenceType]) AS LicenceType
      ,CASE WHEN MAX(CAST([MSM_PolicyHolder].[NonMotoringConvictions] AS INT)) = 1 THEN 'Yes' ELSE 'No' END AS NonMotoringConvictions
      ,MAX([MSM_PolicyHolder].[AccessToOtherCars]) AS AccessToOtherCars
      ,MAX([MSM_PolicyHolder].[UKResidentSince]) AS UKResidentSince
      ,CAST(CASE WHEN DATEADD(yy, DATEDIFF(yy, MAX([MSM_PolicyHolder].[UKResidentSince]), GETDATE()), MAX([MSM_PolicyHolder].[UKResidentSince])) < GETDATE() THEN DATEDIFF(yy, MAX([MSM_PolicyHolder].[UKResidentSince]), GETDATE()) ELSE DATEDIFF(yy, MAX([MSM_PolicyHolder].[UKResidentSince]), GETDATE()) - 1 END AS INT) AS 'YearsInTheUK'
      ,CASE WHEN MAX(CAST([MSM_PolicyHolder].[MainDriver] AS INT)) = 1 THEN 'Yes' ELSE 'No' END AS MainDriver
      ,CASE WHEN MAX([MSM_Enquiry].[FuelType]) = 'P' THEN 'Petrol' WHEN MAX([MSM_Enquiry].[FuelType]) = 'D' THEN 'Diesel' ELSE 'Electric' END AS 'FuelType'
      ,MAX([MSM_Enquiry].[BodyShape]) AS BodyShape
      ,MAX([MSM_Enquiry].[AnnualPersonalMileage]) + MAX([MSM_Enquiry].[AnnualBusinessMileage]) AS 'Mileage'
      ,MAX([MSM_Enquiry].[CoverType]) AS CoverType
      ,MAX([MIU_MSMSales].[InsuranceCo]) AS InsuranceCo
      ,MAX([MIU_MSMSales].[AreaGroupBandID]) AS AreaGroupBandID
      ,MAX([MIU_AreaGroupBand].[Description]) AS 'AreaBand'
      ,MAX([MIU_MSMSales].[HostedRatingEngineName])
      ,MAX([MIU_MSMSales].[CreditScore]) AS CreditScore
      ,MAX([MIU_MSMSales].[EngineCC]) AS EngineCC
      ,MAX([MIU_MSMSales].[Garaging]) AS Garaging
      ,MAX([MSM_Enquiry].[EnquiryDateTime]) AS EnquiryDateTime
      ,MAX(CAST([MSM_YourQuotes].[UsedGoToSite] AS INT)) AS 'Clicks'
      ,(SELECT TOP 1 COUNT(*) FROM [MIU_MSMSales] MSMS WHERE MAX([MSM_Enquiry].[PolicyStartDate]) >= MSMS.[CoverDate] AND MAX([MIU_MSMSales].[InsuranceCo]) = MSMS.[InsuranceCo] AND CONCAT(MSMS.[DateOfBirth], MSMS.[PostcodeOutward]) = CONCAT(MAX([MSM_PolicyHolder].[DateOfBirth]), MAX([MSM_PolicyHolder].[PostcodeOutward]))) Sales
      ,CONCAT(CONVERT(VARCHAR(8), MAX([MSM_PolicyHolder].[DateOfBirth]), 3), MAX([MSM_PolicyHolder].[PostcodeOutward])) as 'UniqueCode'
  FROM [dbo].[MSM_MarketPricing]

  LEFT OUTER JOIN [MSM_PolicyHolder] ON [MSM_MarketPricing].[EnquiryKey] = [MSM_PolicyHolder].[EnquiryKey]
  LEFT OUTER JOIN [MSM_YourQuotes] ON [MSM_MarketPricing].[EnquiryKey] = [MSM_YourQuotes].[EnquiryKey]
  LEFT OUTER JOIN [MSM_Enquiry] ON [MSM_MarketPricing].[EnquiryKey] = [MSM_Enquiry].[EnquiryKey]
  LEFT OUTER JOIN [MSM_Sales] ON [MSM_MarketPricing].[EnquiryKey] = [MSM_Sales].[EnquiryKey]
  LEFT OUTER JOIN [MIU_BusinessCats] ON [MSM_PolicyHolder].[MainBusinessType] = [MIU_BusinessCats].[FTBusinessCategory]
  LEFT OUTER JOIN [MIU_MSMSales] ON [MSM_PolicyHolder].[DateOfBirth] = [MIU_MSMSales].[DateOfBirth] AND [MSM_PolicyHolder].[PostcodeOutward] = [MIU_MSMSales].[PostCodeOutward]
  LEFT OUTER JOIN [MIU_AreaGroupBand] ON [MIU_MSMSales].[AreaGroupBandID] = [MIU_AreaGroupBand].[Id]

  WHERE ([MSM_Sales].[PeergroupDirectOrBroker] = 'Broker' OR [MSM_Sales].[PeergroupDirectOrBroker] = 'Insurer')
  AND [MSM_YourQuotes].[ProductDescription] = 'insurance'
  AND FLOOR(ROUND(100.0*([MSM_YourQuotes].[YourAnnualPrice] - [MarketPriceTop5Annual]) / [MarketPriceTop5Annual], 2)) IS NOT NULL
  AND [MSM_Enquiry].[EnquiryDateTime] IS NOT NULL

  GROUP BY CONCAT(CONVERT(VARCHAR(8), [MSM_PolicyHolder].[DateOfBirth], 3), [MSM_PolicyHolder].[PostcodeOutward])

  ORDER BY MAX([MSM_Enquiry].[EnquiryDateTime]) DESC

希望这能解释我正在努力实现的目标与我目前拥有的目标。

谢谢。

标签: sql-servertsql

解决方案


样本数据

只是发明了一些数据。寻找一个最小的,可重现的例子

create table client
(
  clientid int,
  clientname nvarchar(20),
  clientdob date
);
insert into client (clientid, clientname, clientdob) values
(1, 'Clark Kent',  '1938-04-18'),
(2, 'Bruce Wayne', '1939-03-30');

create table quote
(
  clientid int,
  quotedate date,
  quoteprice money
);
insert into quote (clientid, quotedate, quoteprice) values
(1, '2021-01-01', 1000.0),
(1, '2021-02-01',  995.0),
(2, '2021-01-05', 2000.0),
(2, '2021-01-31', 1900.0);

问题再现

select c.clientid,
       c.clientname,
       c.clientdob,
       max(q.quotedate) as quotedate,  --> gives latest date :)
       max(q.quoteprice) as quoteprice --> does not give latest price :(
from quote q
join client c
  on c.clientId = q.clientid
group by c.clientid,
         c.clientname,
         c.clientdob;

这给出了:

clientid  clientname   clientdob   quotedate   quoteprice
--------  -----------  ----------  ----------  ----------
1         Clark Kent   1938-04-18  2021-02-01  1000.0000   --> not latest quote price
2         Bruce Wayne  1939-03-30  2021-01-31  2000.0000   --> not latest quote price

解决方案 1

charlieface在问题评论中建议。在公用表表达式 ( ) 中按报价日期降序对
所有行 ( ) 编号,并为每个客户获取第一行 ( )。row_number()ctecte.num = 1

with cte as
(
  select c.clientid,
         c.clientname,
         c.clientdob,
         q.quotedate,
         q.quoteprice,
         row_number() over(partition by c.clientid, c.clientname, c.clientdob order by q.quotedate desc) as num
  from quote q
  join client c
    on c.clientId = q.clientid
)
select cte.clientid,
       cte.clientname,
       cte.clientdob,
       cte.quotedate,
       cte.quoteprice
from cte
where cte.num = 1;

解决方案 2

选择所有单独的客户信息(并构造客户的唯一密钥)并为每个客户获取最后一个报价信息 ( outer apply)。

select c.clientid,
       c.clientname,
       c.clientdob,
       q1.quotedate,
       q1.quoteprice
from client c
outer apply ( select top 1
                     q.quotedate,
                     q.quoteprice
              from quote q
              where q.clientid = c.clientid
              order by q.quotedate desc ) q1;

结果

clientid  clientname   clientdob   quotedate   quoteprice
--------  -----------  ----------  ----------  ----------
1         Clark Kent   1938-04-18  2021-02-01   995.0000  --> latest quote date AND price
2         Bruce Wayne  1939-03-30  2021-01-31  1900.0000  --> latest quote date AND price

小提琴以查看实际情况。


推荐阅读