2016-07-20 124 views
0

我有一张表,用于存储合同上的行。每份合同都有他自己的唯一ID,它也有其父母合同的ID。例如:如何连接到另一个表并仅返回最近的匹配行?

+-------------+---------+ 
| contract_id | line_id | 
+-------------+---------+ 
|  1111 |  100 | 
|  1111 |  101 | 
|  1111 |  102 | 
+-------------+---------+ 

我有另一个表,它存储了合约行的历史变化。例如,每当合同行上的单位数量发生变化时,新的行就会被添加到表格中。示例:

+-------------+---------+--------------+-------+ 
| contract_id | line_id | date_changed | units | 
+-------------+---------+--------------+-------+ 
|  1111 |  100 | 2016-01-01 |  1 | 
|  1111 |  100 | 2016-02-01 |  2 | 
|  1111 |  100 | 2016-03-01 |  3 | 
+-------------+---------+--------------+-------+ 

正如您所见,ID为1111的合同的合同行已在3个月内编辑了3次。当前值是3个单位。

我正在对合同行表进行查询以选择所有数据。我想加入历史数据表,并为每个合约行选择最近的行,并在结果中显示单位。我该怎么做呢?

预期结果(将有用于101和102单结果为好):

+-------------+---------+-------+ 
| contract_id | line_id | units | 
+-------------+---------+-------+ 
|  1111 |  100 |  3 | 
+-------------+---------+-------+ 

我尝试查询下面左连接但它返回3行而不是1

查询:

SELECT *, T1.units 
FROM contract_lines 
LEFT JOIN (
    SELECT contract_id, line_id, units, MAX(date_changed) AS maxdate 
    FROM contract_history 
    GROUP BY contract_id, line_id, units) AS T1 
    ON contract_lines.contract_id = T1.contract_id 
    AND contract_lines.line_id = T1.line_id 

实际结果:

+-------------+---------+-------+ 
| contract_id | line_id | units | 
+-------------+---------+-------+ 
|  1111 |  100 |  1 | 
|  1111 |  100 |  2 | 
|  1111 |  100 |  3 | 
+-------------+---------+-------+ 

回答

3

额外加入与的maxDate到contract_history一起将工作

SELECT contract_lines.*,T2.units 
FROM contract_lines 
LEFT JOIN (
    SELECT contract_id, line_id, MAX(date_changed) AS maxdate 
    FROM contract_history 
    GROUP BY contract_id, line_id) AS T1 
    JOIN contract_history T2 ON 
     T1.contract_id=T2.contract_id and 
     T1.line_id= T2.line_id and 
     T1.maxdate=T2.date_changed 
ON contract_lines.contract_id = T1.contract_id 
AND contract_lines.line_id = T1.line_id 

输出

enter image description here

+0

区别在这里没有'单位'字段。你从原始表格中获得 –

+0

这对我不起作用。在最后两行中,我收到一条错误消息:“多部分标识符'contract_lines.contract_id'无法绑定”,分别与'line_id'相同。这不是我熟悉的错误。有任何想法吗? – Equalsk

-1

一如往常似乎是花了一个小时看着它,并在StackOverflow大声呼喊,因为有一个难得的维护期,我在发布问题后不久就解决了自己的问题。

为了帮助任何被困住的人,我会展示我发现的东西。这可能不是一个有效的方法来实现这一点,所以如果有人有更好的建议,我全神贯注。

我适应了答案从这里:T-SQL Subquery Max(Date) and Joins

SELECT *, 
     Units = (SELECT TOP 1 units 
       FROM contract_history 
       WHERE contract_lines.contract_id = contract_history.contract_id 
       AND contract_lines.line_id = contract_history.line_id 
       ORDER BY date_changed DESC 
       ) 
FROM .... 
+0

尝试'inquisitive_mind'的形式给出,是更好地履行一个子查询(单表扫描),而不是一个选择的每一行。 –

+0

恩,是的,但不需要downvote,我的回答没有错,只是效率低下。我甚至在答案中陈述了很多。但是,无论如何感谢... – Equalsk

+0

我试图成为有用的。我没有downvote。忽略巨魔;) –

0

另一个可能的解决了这一点。这使用RANK对此进行排序/过滤。与你所做的一样,只是一个不同的机智。

SELECT contract_lines.*, T1.units 
FROM contract_lines 
LEFT JOIN (
    SELECT contract_id, line_id, units, 
    RANK() OVER (PARTITION BY contract_id, line_id ORDER BY date_changed DESC) AS [rank] 
    FROM contract_history) AS T1 
ON contract_lines.contract_id = T1.contract_id 
AND contract_lines.line_id = T1.line_id 
AND T1.rank = 1 
WHERE T1.units IS NOT NULL 

你可以改变这一个INNER JOIN,如果你期望的数据出现的所有时间删除IS NOT NULLWHERE子句。

很高兴你知道了!

1

这是我喜欢的风格,因为它不需要自我加入和干净的表达意图。此外,它在性能方面与ROW_NUMBER()方法竞争非常好。

select a.* 
    , b.units 
from contract_lines as a 
join (
    select a.contract_id 
     , a.line_id 
     , a.units 
     , Max(a.date_changed) over(partition by a.contract_id, a.line_id) as max_date_changed 
    from contract_history as a 
) as b 
    on a.contract_id = b.contract_id 
    and a.line_id = b.line_id 
    and b.date_changed = b.max_date_changed; 
0

试试这个简单的查询:

SELECT TOP 1 T1.* 
FROM contract_lines T0 
    INNER JOIN contract_history T1 
     ON T0.contract_id = T1.contract_id and 
      T0.line_id = T1.line_id 
ORDER BY date_changed DESC 
相关问题