【问题标题】:Select second max as max based on condition where max is used for condition根据条件选择第二个最大值作为最大值,其中最大值用于条件
【发布时间】:2015-11-04 05:56:29
【问题描述】:

尝试创建报告以查看存储单元在 1 个租约和另一个租约之间的空置时间。信息存储在客户表的列中:

PK (Customer Code) | Storage_Number (FK) | Status | startdate | enddate

我得到了基本代码来查找每单位的 MAX(最后一个)客户和之前的 1 个客户。我的问题是当前空置的存储单元。它将显示 New Customer Start Date 过去的客户,而我希望将此字段显示为空白,并且 Prior Customer End Date 应该来自最近的客户。

Select s.PK [Storage Number], 
ca.enddate [Prior Customer End Date],
cb.startdate [New Customer Start Date],
Datediff(DAY, ca.enddate, cb.startdate)-1 [Days Vacant]
From Storage s
Left Outer Join (
    Select Storage_Number, 
    MAX(PK) Customer_Code
    FROM Customer
    WHERE Status in (‘Future’, ‘Active’, ’Past’)
    Group By Storage_Number
)maxa On maxa.Storage_Number = s.PK
Left Outer Join(
    Select Storage_Number,
    MAX(PK) Customer_Code
    FROM Customer b
    Full Outer Join (
        Select Storage_Number sn, 
        MAX(PK) cc
        FROM Customer
        WHERE Status in (‘Future’, ‘Active’, ’Past’)
        Group By Storage_Number
    )a on a.sn = b.Storage_Number
    WHERE Status in (‘Future’, ‘Active’, ’Past’)
    And b.PK != a.cc
    Group by Storage_Number
)maxb
ON maxb.Storage_Number = s.PK
Left Outer Join Customer ca on ca.Storage_Number = s.PK and ca.PK = maxb.PK
Left Outer Join Customer cb on cb.Storage_Number = s.PK and cb.PK = maxa.PK
WHERE ca.enddate !> cb.startdate
Order By ca.enddate

我可以添加多个CASE 语句

Select s.PK [Storage Number], 
CASE
    WHEN    cb.status = ‘Past’
    THEN cb.enddate
    Else ca.enddate
END [Prior Customer End Date],
CASE
    WHEN cb.status = ‘Past’
    THEN null
    ELSE cb.startdate
END [New Customer Start Date],
CASE
    WHEN cb.status = ‘Past’
    THEN null 
    ELSE Datediff(DAY, ca.enddate, cb.startdate)-1
END [Days Vacant]
FROM ………..

但是我想看看是否有更好的方法来做到这一点。

【问题讨论】:

  • 看看我对这个问题的解决方案:我怀疑它会对你的问题有所帮助:stackoverflow.com/questions/31735333/…
  • 你能展示一些实际数据和预期结果吗,最好的情况是小提琴?这似乎是像 ROW_NUMBER 这样的窗口聚合函数的任务。您的 SQL Server 版本是什么?
  • @JohnLBevan 我没有 2014 年。不确定我有什么版本。我正在开发 RDP 到 3'rd 方数据库,我在哪里检查版本?
  • 试试Select @@version
  • 发行版:SQL Server 2000 RTM。版本:8.00.194

标签: sql sql-server tsql sql-server-2000


【解决方案1】:

更新

SQL 2000 版本(使用下面的设置代码/我没有测试,因为没有 SQL 2000 实例;希望一切都与该版本兼容,因为我尽量不使用任何太现代的东西)。

declare @firstAvailableDate datetime = '2014-12-20' --allows us to see how many days the units were available before their first booking
, @lastAvailableDate datetime = getutcdate() --allows us to say up to which date we're interested for the last booking

declare @BookingSequence table
(
    OrderByStorageId bigint identity(1,1)
    , StorageId bigint
    , StartDate datetime
    , EndDate datetime
    , CustomerId bigint 
)

insert @BookingSequence  
select StorageId, StartDate, EndDate, CustomerId
from @CustomerBookings
order by StorageId, StartDate

declare @BookingPrevAndCurrent table
(
    StorageId bigint
    , StartDate datetime
    , EndDate datetime
    , PreviousBookingEndDate datetime
    , CustomerId bigint
    , OrderByStorageId bigint
)

insert @BookingPrevAndCurrent 
select c.StorageId, c.StartDate, c.EndDate, coalesce(p.EndDate,@firstAvailableDate), c.CustomerId, c.OrderByStorageId
from @BookingSequence c
left outer join @BookingSequence p
on p.StorageId = c.StorageId 
and p.OrderByStorageId = c.OrderByStorageId - 1

select s.Name StorageUnit
, c.Name Customer
, x.PreviousBookingEndDate 
, coalesce(x.StartDate, @lastAvailableDate) CurrentBookingStartDate
, DateDiff(Day,x.PreviousBookingEndDate, coalesce(x.StartDate, @lastAvailableDate)) DaysBetweenBookings
from @Storage s
left outer join @BookingPrevAndCurrent  x
    on x.StorageId = s.id
left outer join @Customer c
    on c.id = x.CustomerId
order by StorageUnit, PreviousBookingEndDate

SQL 2008 版本

试试这样的:

SQL Fiddle

--setup code / sample data

declare @CustomerBookings table
(
    Id bigint identity(1,1)
    , CustomerId bigint
    , StorageId bigint 
    , StatusId int
    , StartDate datetime
    , EndDate datetime
)
declare @Storage table
(
    id bigint identity(1,1)
    , Name nvarchar(32) not null
)
declare @Customer table
(
    id bigint identity(1,1)
    , Name nvarchar(32) not null
)
insert @Storage values('A'),('B'),('C')
insert @Customer values('Jane'),('Paul'),('Keith')
insert @CustomerBookings 
select c.id, s.id, 1, x.b, x.e
from 
(
    select 'Jane' c, 'A' s, '2015-01-01' b, '2015-01-03' e 
    union all
    select 'Jane' c, 'A' s, '2015-01-05' b, '2015-01-06' e 
    union all
    select 'Jane' c, 'B' s, '2015-01-05' b, '2015-01-06' e 
    union all
    select 'Paul' c, 'C' s, '2015-01-02' b, '2015-01-06' e 
    union all
    select 'Paul' c, 'A' s, '2015-01-07' b, '2015-01-10' e 
    union all
    select 'Paul' c, 'A' s, '2015-01-012' b, '2015-01-18' e 
    union all
    select 'Keith' c, 'B' s, '2015-01-01' b, '2015-01-04' e 
    union all
    select 'Keith' c, 'A' s, '2015-01-20' b, '2015-01-23' e 
    union all
    select 'Keith' c, 'B' s, '2015-01-08' b, '2015-01-10' e 
    union all
    select 'Keith' c, 'B' s, '2015-01-20' b, '2015-01-23' e 
) x
inner join @Storage s on s.Name = x.s
inner join @Customer c on c.Name = x.c

--the actual solution

declare @firstAvailableDate datetime = '2014-12-20' --allows us to see how many days the units were available before their first booking
, @lastAvailableDate datetime = getutcdate() --allows us to say up to which date we're interested for the last booking

;with BookingSequence as 
(
    select StorageId, StartDate, EndDate, CustomerId, ROW_NUMBER() over (partition by StorageId order by StartDate) OrderByStorageId
    from @CustomerBookings
)
, BookingPrevAndCurrent as
(
    select StorageId, StartDate, EndDate, @firstAvailableDate PreviousBookingEndDate, CustomerId, OrderByStorageId
    from BookingSequence c
    where c.OrderByStorageId = 1

    union all

    select c.StorageId, c.StartDate, c.EndDate, p.EndDate, c.CustomerId, c.OrderByStorageId
    from BookingPrevAndCurrent  p
    inner join BookingSequence c
    on c.StorageId = p.StorageId
    and c.OrderByStorageId = p.OrderByStorageId + 1
)
select s.Name StorageUnit
, c.Name Customer
, x.PreviousBookingEndDate 
, coalesce(x.StartDate, @lastAvailableDate) CurrentBookingStartDate
, DateDiff(Day,x.PreviousBookingEndDate, coalesce(x.StartDate, @lastAvailableDate)) DaysBetweenBookings
from @Storage s
left outer join BookingPrevAndCurrent  x
    on x.StorageId = s.id
left outer join @Customer c
    on c.id = x.CustomerId
order by StorageUnit, PreviousBookingEndDate

【讨论】:

  • 不用担心/更新了,尝试使用 SQL2000 兼容的解决方案;遗憾的是没有什么可测试的,在 2000 年我不知道 SQL,所以不能确定我使用的所有东西都是兼容的......但希望一切都可以工作。
猜你喜欢
  • 1970-01-01
  • 2015-10-31
  • 1970-01-01
  • 2021-03-26
  • 1970-01-01
  • 2012-09-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多