我有这个不那么正常化的表:
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)但是子查询对我来说是一个困难的因为我需要的查询结果只是另一个查询的一部分,我害怕它会影响表现。
答案 0 :(得分:4)
以下使用子查询(更准确地说,是一个常见的表表达式),但它应该足够有效:
;
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
项可以没有比赛)。
参考文献:
答案 1 :(得分:0)
回答这个问题似乎很晚,但我想我应该回答它,因为我已经看到了。 答案中出现了问题。 如果插入表中有以下新记录: 手钻2012-01-16 11:06:10.077 2010-01-16 00:00:00.563 这将导致错误的后果。 这是我的答案。
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=
(
select
top 1 DateTransferred
from TransferLog as temp
where temp.DateTransferred>tIn.DateTransferred
and temp.ItemName=tIn.ItemName
and tIn.[Type]='in'
and temp.[Type]='out'
order by temp.DateTransferred asc
)
where tIn.[Type]='in'
原谅我可怜的英语并给我你的意见