sql-server-2005 - 连接最近的日期(无子查询)

标签 sql-server-2005 join

我有这个不太标准化的表格:

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'

如您所见,其想法是分别对 INOUT 行进行排名,然后将前者与后者进行匹配(使用外连接,因为最后一个 IN 项可以没有匹配项)。

引用文献:

关于sql-server-2005 - 连接最近的日期(无子查询),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8875617/

相关文章:

MySQL:如何加速连接?

php - 如何在mysql和php中连接两个具有共同属性的表?

MySQL 使用带有 2 个查询、子查询或连接的 select?

javascript - Javascript 对象类似于 SQL 'JOIN'?

sql-server - SQL Server (2005) - "Deleted On"DATETIME 和索引

sql-server - 更新二进制字段从文件系统获取文件而不使用动态 SQL

SQL - 获取月份/季度的数字日

join - pig : Outer join on more than 2 relations

SQL测试最佳实践

sql-server-2005 - 在SQL Server中截断和删除有什么区别?