我有一张表存储合同中的行。每个合同都有自己的唯一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的合同的ID为100的合同行已在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 |
+-------------+---------+-------+
答案 0 :(得分:3)
对contract_history和maxdate的额外加入将起作用
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
<强>输出强>
答案 1 :(得分: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;
答案 2 :(得分: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 NULL
子句中的WHERE
。
很高兴你明白了!
答案 3 :(得分: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
答案 4 :(得分:-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 ....