我可以用Python(或任何其他语言)相当容易地做到这一点,但我试图看看使用纯T-sql是否可以实现
我有两个表:
表A的每一行都有一堆常规数据和时间戳记
+------+------+------+-----------+
| Col1 | Col2 | Col3 | Timestamp |
+------+------+------+-----------+
| A | B | C | 17:00 |
| D | E | F | 18:00 |
| G | H | I | 23:00 |
+------+------+------+-----------+
表B被视为元数据
+-------+-----------+
| RunNo | Timestamp |
+-------+-----------+
| 1 | 16:50 |
| 2 | 17:30 |
| 3 | 18:00 |
| 4 | 19:00 |
+-------+-----------+
因此,常规数据被引用为“ RunNo”。表B中的时间戳就是在数据库中创建“运行”时的时间戳。您可以通过比较时间戳将常规数据与其正确的运行号进行匹配。例如,表A中第一行的时间戳是17:00,该时间戳大于16:50且小于17:30,因此很显然,该行属于RunNo1。如何执行此查询,因此结果表为< / p>
+------+------+------+-----------+-------+
| Col1 | Col2 | Col3 | Timestamp | RunNo |
+------+------+------+-----------+-------+
| A | B | C | 17:00 | 1 |
| D | E | F | 18:00 | 2 |
| G | H | I | 23:00 | 4 |
+------+------+------+-----------+-------+
虽然我可能在这里使用CASE可能会有所帮助,但我不知道如何将其组合在一起
SELECT a.*,
CASE WHEN a.TIMESTAMP < b.TIMESAMP AND a.TIMESTAMP > b.TIMSTAMP then b.RunNo END AS RunNo
FROM A as a, B as b
任何帮助将不胜感激。
答案 0 :(得分:1)
CASE
允许您根据条件返回不同的值(即列或表达式)。这不是你在这里做什么。您要联接表并根据条件过滤匹配的行。
我用Timestamp
代替了名字ts
,即使逃脱了,我在SQL Fiddle上也遇到了困难。这是一个保留关键字。
SELECT A.Col1, A.Col2, A.Col3, A.ts, MAX(B.RunNo) AS RunNo
FROM
A
INNER JOIN B
ON A.ts > B.ts
GROUP BY A.Col1, A.Col2, A.Col3, A.ts
对于A.ts > B.ts
,它为第二项返回RunNo
2。使用A.ts >= B.ts
,第二个条目将返回RunNo
3。
答案 1 :(得分:0)
with TableA as (
Select [Col1] = 'A',[Col2] = 'B',[Col3] = 'C',[Timestamp] = '17:00'
Union all Select [Col1] = 'D',[Col2] = 'E',[Col3] = 'F',[Timestamp] = '18:00'
Union all Select [Col1] = 'G',[Col2] = 'H',[Col3] = 'I',[Timestamp] = '23:00'
)
, TableB as (
Select [RunNo] = '1',[Timestamp] = '16:50'
Union all Select [RunNo] = '2',[Timestamp] = '17:30'
Union all Select [RunNo] = '3',[Timestamp] = '18:00'
Union all Select [RunNo] = '4',[Timestamp] = '19:00'
)
, TableBWithRowNumber as (
select b.RunNo, ROW_NUMBER() over (order by b.timestamp asc) as number, cast(b.Timestamp as time) as timestamp
from TableB b
)
, TableBWithNextRun as (
select b1.RunNo, startTime = b1.timestamp , endTime = b2.timestamp
from TableBWithRowNumber b1
left join TableBWithRowNumber b2 on b1.number + 1= b2.number
)
select *
from TableA a
inner join TableBWithNextRun B
on a.Timestamp >= b.startTime and (a.Timestamp < b.endTime or b.endTime is null)
这会将您的时间戳转换为time
。我不确定您内部的数据类型是什么。
这将输出以下内容
Col1 Col2 Col3 Timestamp RunNo startTime endTime
A B C 17:00 1 16:50:00.0000000 17:30:00.0000000
D E F 18:00 3 18:00:00.0000000 19:00:00.0000000
G H I 23:00 4 19:00:00.0000000 NULL
答案 2 :(得分:0)
您可以使用lag函数来获取列的先验值,然后再进行联接。
WITH Runs AS
(
SELECT
RunNo,
COALESCE(LAG(TIMESTAMP),'00:00')) AS START_TS,
TIMESTAMP AS END_TS
FROM TableB
ORDER BY RunNo ASC
)
SELECT B.RunNo, A.*
FROM TableA A
JOIN Runs B ON A.Timestamp >= B.Start_TS AND A.Timestamp < B.End_Ts
这应该比大型数据集上的任何按组求解都要快。