SQL 在您只获取 first/oldest 结果的时间戳上加入
SQL Join on timestamps where you only take the first/oldest result
假设我有两个表:
Table #1
t1
ID | Col1 | MeasureTime | Parameter_ID
----------------------------------------------
1 | abc | 2020-11-11 07:00:00 | 1
2 | abc | 2020-11-11 08:00:00 | 1
Table #2
t2
ID | Parameter_ID | Col2 | ValidFrom
----------------------------------------------
1 | 1 | xyz | 2020-11-11 06:30:00
2 | 1 | def | 2020-11-11 07:30:00
我想使用 Parameter_ID
连接两个表并且我想建立 1:1 关系。 t2
中的ValidFrom
就是这个参数生效的时间。但不幸的是,没有 ValidTo
,而是我必须检查我是否加入了来自 t2
的第一个 Parameter_ID
,其中 ValidFrom
是有效的。
所以我想要这样的结果:
Table #3
t3
ID | Col1 | MeasureTime | Parameter_ID | ValidFrom | Col2
-----------------------------------------------------------------
1 | abc | 2020-11-11 07:00:00 | 1 | 06:30:00 | xyz
2 | abc | 2020-11-11 08:00:00 | 1 | 07:30:00 | def
但如果我做一个简单的:
SELECT *
FROM t1
JOIN t2 ON t1.PARAMETER_ID = t2.PARAMETER_ID AND t1.Measuretime >= t2.ValidFrom
我会得到:
Table #3
t3
ID | Col1 | MeasureTime | Parameter_ID | ValidFrom | Col2
-----------------------------------------------------------------
1 | abc | 2020-11-11 07:00:00 | 1 | 06:30:00 | xyz
2 | abc | 2020-11-11 08:00:00 | 1 | 06:30:00 | xyz
3 | abc | 2020-11-11 08:00:00 | 1 | 07:30:00 | def
我其实不想ID
2
.
希望我的问题变得清楚。我可以想到类似“如果 t2 有多个结果,则按 ValidFrom ASC 排序并只取第一个”。但不幸的是,我不太确定如何使用 SQL 执行此操作。也许这个问题还有更优雅的解决方案?
你可以使用 row_number()
select a.* from
(SELECT *, row_number()over(partition by Col1,MeasureTime order by MeasureTime) rn
FROM t1
JOIN t2 ON t1.PARAMETER_ID = t2.PARAMETER_ID AND t1.Measuretime >= t2.ValidFrom
) a were a.rn=1
您可以使用 ROW_NUMBER
分析函数扩展原始查询,如下所示:
SELECT * FROM
(SELECT T1.*, T2.VALID_FROM, T2.COL2,
ROW_NUMBER()
OVER (PARTITION BY T1.ID ORDER BY T2.VALID_FROM DESC NULLS LAST) AS RN
FROM T1 JOIN T2 ON T1.PARAMETER_ID = T2.PARAMETER_ID
AND T1.MEASURETIME >= T2.VALIDFROM)
WHERE RN = 1
我建议使用 lead()
生成 valid_to
。然后使用 join
:
select t1.*, t2.valid_from, t2.col2
from table1 t1 join
(select t2.*,
lead(valid_from) over (partition by parameter_id order by valid_from) as valid_to
from t2
) t2
on t1.parameter_id = t2.parameter_id and
t1.MeasureTime >= t2.valid_from and
(t1.MeasureTime < t2.valid_to or t2.valid_to is null);
虽然您愿意将两个表中的值排列起来,但听起来正确的解决方案是从 table2
中获取日期范围包括 table1
的行日期。
假设我有两个表:
Table #1
t1
ID | Col1 | MeasureTime | Parameter_ID
----------------------------------------------
1 | abc | 2020-11-11 07:00:00 | 1
2 | abc | 2020-11-11 08:00:00 | 1
Table #2
t2
ID | Parameter_ID | Col2 | ValidFrom
----------------------------------------------
1 | 1 | xyz | 2020-11-11 06:30:00
2 | 1 | def | 2020-11-11 07:30:00
我想使用 Parameter_ID
连接两个表并且我想建立 1:1 关系。 t2
中的ValidFrom
就是这个参数生效的时间。但不幸的是,没有 ValidTo
,而是我必须检查我是否加入了来自 t2
的第一个 Parameter_ID
,其中 ValidFrom
是有效的。
所以我想要这样的结果:
Table #3
t3
ID | Col1 | MeasureTime | Parameter_ID | ValidFrom | Col2
-----------------------------------------------------------------
1 | abc | 2020-11-11 07:00:00 | 1 | 06:30:00 | xyz
2 | abc | 2020-11-11 08:00:00 | 1 | 07:30:00 | def
但如果我做一个简单的:
SELECT *
FROM t1
JOIN t2 ON t1.PARAMETER_ID = t2.PARAMETER_ID AND t1.Measuretime >= t2.ValidFrom
我会得到:
Table #3
t3
ID | Col1 | MeasureTime | Parameter_ID | ValidFrom | Col2
-----------------------------------------------------------------
1 | abc | 2020-11-11 07:00:00 | 1 | 06:30:00 | xyz
2 | abc | 2020-11-11 08:00:00 | 1 | 06:30:00 | xyz
3 | abc | 2020-11-11 08:00:00 | 1 | 07:30:00 | def
我其实不想ID
2
.
希望我的问题变得清楚。我可以想到类似“如果 t2 有多个结果,则按 ValidFrom ASC 排序并只取第一个”。但不幸的是,我不太确定如何使用 SQL 执行此操作。也许这个问题还有更优雅的解决方案?
你可以使用 row_number()
select a.* from
(SELECT *, row_number()over(partition by Col1,MeasureTime order by MeasureTime) rn
FROM t1
JOIN t2 ON t1.PARAMETER_ID = t2.PARAMETER_ID AND t1.Measuretime >= t2.ValidFrom
) a were a.rn=1
您可以使用 ROW_NUMBER
分析函数扩展原始查询,如下所示:
SELECT * FROM
(SELECT T1.*, T2.VALID_FROM, T2.COL2,
ROW_NUMBER()
OVER (PARTITION BY T1.ID ORDER BY T2.VALID_FROM DESC NULLS LAST) AS RN
FROM T1 JOIN T2 ON T1.PARAMETER_ID = T2.PARAMETER_ID
AND T1.MEASURETIME >= T2.VALIDFROM)
WHERE RN = 1
我建议使用 lead()
生成 valid_to
。然后使用 join
:
select t1.*, t2.valid_from, t2.col2
from table1 t1 join
(select t2.*,
lead(valid_from) over (partition by parameter_id order by valid_from) as valid_to
from t2
) t2
on t1.parameter_id = t2.parameter_id and
t1.MeasureTime >= t2.valid_from and
(t1.MeasureTime < t2.valid_to or t2.valid_to is null);
虽然您愿意将两个表中的值排列起来,但听起来正确的解决方案是从 table2
中获取日期范围包括 table1
的行日期。