我花了一段时间,我认为这不是最有效的方法(转换太多),但我有一个 XML 解决方案可以工作,有人可能会对其进行改进。请注意,由于您正在处理时间,因此我使用了 Date 函数 - 但请确保您阅读了最后的警告。基本上,在您的 CTE 中,您可以将数据转换为简单的 XML 格式,例如
<Note>
<T1>00:00</T1>
<T2>00:00</T2>
</Note>
这消除了执行字符串拆分功能的需要。现在您可以通过使用DATEDIFF、DATEADD、CAST 和LEFT 的组合来获得结果
WITH CTE1 AS
(
SELECT CAST('<Note><T1>' + REPLACE((LTRIM(RTRIM(REPLACE(CAST(Note AS NVARCHAR(4000)),
':tt:','')))), ',', '</T1><T2>') + '</T2></Note>' AS XML) AS Note
FROM UD_Notes
WHERE Note like ':t%'
)
SELECT LEFT(CAST(DATEADD(mi, DATEDIFF(mi, CAST(y.T1 AS TIME), CAST(y.T2 AS TIME)), CAST('00:00' AS TIME)) AS VARCHAR(20)), 5)
FROM (
SELECT c.value('(T1/text())[1]', 'varchar(50)') AS T1,
c.value('(T2/text())[1]', 'varchar(50)') AS T2
FROM (SELECT Note FROM CTE1) x
CROSS APPLY Note.nodes('/Note') AS T(c)) y
发生的情况是,首先我们让 CTE 给我们一个 XML 数据类型,然后我们可以查询它给我们两个“列”(T1 和 T2)。 SELECT 正在同时做很多工作,所以我会分解它。让我们假设您给出的示例是12:35 - 12:32 = 00:03。
DATEDIFF(mi, CAST(y.T1 AS TIME), CAST(y.T2 AS TIME))
这里我们得到T1 和T2 两列,我们CAST 那些TIME 类型并得到差异(即T2 - T1)。这给了我们一个 INT 与 3 的差异,所以在接下来的部分中,我将简单地将 3 替换为相关部分。
所以,现在我们得到
DATEADD(mi, 3, CAST('00:00' AS TIME))
我们在这里所做的是创建一个名义上的 TIME 和 00:00 并在几分钟内添加我们的差异 (mi) 所以这给了我们 00:03。再一次,我们将其替换。
CAST(00:03 AS VARCHAR(20))
这里很简单,我们只是得到一个VARCHAR 表示我们的时间。因为TIME 的准确度非常好,所以我们得到秒和纳秒,看起来像00:03:00.0000000。我们想去掉秒和纳秒,因为我们在这里处理小时和分钟。
LEFT('00:03:00.0000000', 5)
这给我们留下了'00:03' 作为字符串。
我不会费心浏览查询的主体,因为虽然我可以编写它,但我认为我不能足够清楚地解释它,但是有很多页面可以比我更好地解释 XML 查询,例如this blog post 来自 MSDN,this blog post 着眼于在 t-sql 中查询 XML 字段。
我毫不怀疑有更好的方法可以做到这一点,这里的人也可以很好地解释查询 - 请随时添加到这里并解释我的努力。
警告
如果T1 是01:00 并且T2 是12:57 那么你会得到11:57 的答案,因为它们在前进方向上确实相隔11 小时57 分钟。老实说,我现在还没有时间研究如何让这两次得到 3 的结果,但我希望其他人可能知道如何做。