我有这个不太标准化的表格:
ItemName Type DateTransferred
Hand Drill IN 2012-01-16 11:06:10.077
Hand Drill OUT 2012-01-16 11:06:16.563
Hand Drill IN 2012-01-16 11:06:26.780
Grinder IN 2012-01-16 11:06:33.917
Hand Drill OUT 2012-01-16 11:06:45.443
创建查询:
CREATE TABLE [dbo].[TransferLog](
[ItemName] [nvarchar](50) NOT NULL,
[Type] [nvarchar](3) NOT NULL,
[DateTransferred] [datetime] NOT NULL
) ON [PRIMARY]
ALTER TABLE [dbo].[TransferLog]
ADD CONSTRAINT [DF_TransferLog_DateTransferred]
DEFAULT (getdate()) FOR [DateTransferred]
基本上,上表记录了项目团队从仓库借出的元素(类型:IN)和归还的元素(类型:OUT)。
我想要实现的是获取所有借用的设备,何时借用(IN)以及何时归还(OUT)。当尝试将“借用交易”与其相应的“返回交易”匹配时会出现问题,因为它们唯一的关系是 ItemName:
选择所有“借用交易”:
select tIn.ItemName, tIn.DateTransferred as DateBorrowed
from transferLog as tIn
where tIn.[type] = 'IN'
结果:
ItemName DateBorrowed
Hand Drill 2012-01-16 11:06:10.077
Hand Drill 2012-01-16 11:06:26.780
Grinder 2012-01-16 11:06:33.917
尝试选择所有“借用交易”及其对应的“归还交易”:
select tIn.ItemName, tIn.DateTransferred as DateBorrowed,
tOut.DateTransferred as DateReturned
from transferLog as tIn
left join transferLog as tOut
on tIn.ItemName = tOut.ItemName
and tOut.[type] = 'OUT'
where tIn.[type] = 'IN'
结果:
ItemName DateBorrowed DateReturned
Hand Drill 2012-01-16 11:06:10.077 2012-01-16 11:06:16.563
Hand Drill 2012-01-16 11:06:10.077 2012-01-16 11:06:45.443
Hand Drill 2012-01-16 11:06:26.780 2012-01-16 11:06:16.563
Hand Drill 2012-01-16 11:06:26.780 2012-01-16 11:06:45.443
Grinder 2012-01-16 11:06:33.917 NULL
注意,每个“借入交易”只能有一个或没有对应的“归还交易”,以上结果将每个“借入交易”与每个“归还交易”匹配,只要它们具有相同的 ItemName
。结果应该是:
ItemName DateBorrowed DateReturned
Hand Drill 2012-01-16 11:06:10.077 2012-01-16 11:06:16.563
Hand Drill 2012-01-16 11:06:26.780 2012-01-16 11:06:45.443
Grinder 2012-01-16 11:06:33.917 NULL
现在,我正在考虑如何将“归还交易”与大于且最接近“借用交易”的 DateTransferred 的 DateTransferred
进行匹配。像这样的东西:
select tIn.ItemName, tIn.DateTransferred as DateBorrowed,
tOut.DateTransferred as DateReturned
from transferLog as tIn
left join transferLog as tOut
on tIn.ItemName = tOut.ItemName
and tOut.[type] = 'OUT'
and
tOut.DateTransferred > tIn.DateTransferred
-- AND NEAREST tOut.DateTransferred TO tIn.DateTransferred
where tIn.[type] = 'IN'
我读了这个( SQL Join on Nearest less than date )和这个( Join tables on nearest date in the past, in MySQL ),但是子查询对我来说是一个困难的选择,因为我需要的查询结果只是另一个查询的一部分,我担心它会影响性能。
最佳答案
下面确实使用了子查询(更准确地说,是一个公共(public)表表达式),但它应该足够有效:
;
WITH ranked AS (
SELECT
*,
rnk = ROW_NUMBER() OVER (PARTITION BY ItemName, Type ORDER BY DateTransferred)
FROM TransferLog
)
SELECT
r_in.ItemName,
r_in.DateTransferred AS DateBorrowed,
r_out.DateTransferred AS DateReturned
FROM ranked r_in
LEFT JOIN ranked r_out ON r_out.Type = 'OUT'
AND r_in.ItemName = r_out.ItemName
AND r_in.rnk = r_out.rnk
WHERE r_in.Type = 'IN'
如您所见,其想法是分别对 IN
和 OUT
行进行排名,然后将前者与后者进行匹配(使用外连接,因为最后一个 IN
项可以没有匹配项)。
引用文献:
关于sql-server-2005 - 连接最近的日期(无子查询),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8875617/