这是根据问题中的新细节更新的回复。可以在执行以下操作之前将基于应用程序的表插入到数据库中,或者如果需要,可以通过 CTE 术语注入数据。
测试用例:
Working test case for sqlite
感兴趣的 SQL,首先是 SELECT 以生成应用程序可以用来更新本地数据的结果,然后是更新在数据库中创建的目标表的示例,其中包含要填充的应用程序数据新的打开/评分数据。
文字3000000000 只是我们从提供的应用程序时间戳中搜索Open 详细信息的时间戳增量/范围,对于应用程序提供的每一行。基本上,我们从EURUSD 表中找到最近的先前时间戳。
-- Just calculate the result, without touching target
WITH RECURSIVE ts (ts, n) AS (
SELECT TimestampUnix, ROW_NUMBER() OVER (ORDER BY TimestampUnix)
FROM target WHERE currency = 'EUR'
)
, xrows (ts, n, TimestampUnix, Open, rn) AS (
SELECT ts, n, EURUSD.TimestampUnix, EURUSD.Open
, ROW_NUMBER() OVER (PARTITION BY n ORDER BY TimestampUnix DESC)
FROM ts
JOIN EURUSD
ON EURUSD.TimestampUnix <= ts.ts
AND EURUSD.TimestampUnix > ts.ts - 3000000000
)
SELECT *
FROM xrows WHERE rn = 1
;
-- Now use the above to UPDATE the target table.
-- sqlite might not support a JOIN here.
-- So we use correlated behavior in the SET clause
UPDATE target
SET rate = (
WITH ts (ts, n, currency) AS (
SELECT TimestampUnix, ROW_NUMBER() OVER (ORDER BY TimestampUnix)
, currency
FROM target WHERE currency = 'EUR'
)
, xrows (ts, n, currency, TimestampUnix, Open, rn) AS (
SELECT ts, n, currency, EURUSD.TimestampUnix, EURUSD.Open
, ROW_NUMBER() OVER (PARTITION BY n ORDER BY TimestampUnix DESC)
FROM ts
JOIN EURUSD
ON EURUSD.TimestampUnix <= ts.ts
AND EURUSD.TimestampUnix > ts.ts - 3000000000
)
SELECT Open
FROM xrows
WHERE rn = 1
AND ts = target.TimestampUnix
AND currency = target.currency
)
WHERE currency = 'EUR'
;
eurusd 表和一些生成的示例数据:
CREATE TABLE eurusd (
TimestampUnix timestamp, Open int
);
-- Add some sample data for testing...
INSERT INTO eurusd
WITH RECURSIVE cte (ts, Open, n) AS (
SELECT 1630942385000, 1101, 1 UNION ALL
SELECT ts-1000000000, Open-1, n+1 FROM cte
WHERE n < 15
)
SELECT ts, Open FROM cte
;
生成的数据如下所示:
目标/应用表:
-- Let this table represent the data in the application to be updated.
CREATE TABLE target (
TimestampUnix timestamp
, currency varchar(10)
, rate int
);
-- The application could insert these rows before processing, or just provide this
-- data via a CTE term.
INSERT INTO target VALUES
(1630942385000, 'TST', 0)
, (1630942377000, 'EUR', NULL)
, (1630942162000, 'BTC', NULL)
, (1625942399000, 'EUR', NULL)
;
这张桌子看起来像这样。我们希望更新突出显示的行:
第一个查询的结果,只显示生成的与找到的最接近的rate 的行:
UPDATE 之后的target 表的结果,更新后的rates 突出显示:
原始回复:
这是计算感兴趣的时间戳的一种方法(从 current_timestamp 开始每 -12 小时),然后根据问题中的逻辑返回每个时间戳 1 行。
我们从 current_timestamp - 12 小时开始,并迭代(通过递归)产生连续的时间戳值,从中计算下一个结果,直到某个停止条件。我添加了一个条件,将迭代次数限制在 10 次左右,但只有几天的数据,即 4 x 12 小时范围。
ROW_NUMBER 用于计算每个时间戳范围内每个 EURUSD 行的位置(降序),因此 rn = 1 表示该范围内最近的行,类似于您的ORDER BY ts DESC LIMIT 1。
我还调整了您的逻辑以避免搜索给定时间戳之前的所有数据。如果其中包含数月或数年的数据,您可能只需要查看最后一天左右,即可获得每个时间戳的最新 Open 值。如果这是可以接受的,这也可以帮助您当前的 SQL。
通过不迭代 SQL 100 次,您也可能会获得更显着的改进。
更新为更好的形式:
WITH RECURSIVE ts (ts, n) AS (
SELECT datetime(current_timestamp, '-12 hour'), 1
UNION ALL
SELECT datetime(ts, '-12 hour'), n+1
FROM ts
WHERE n < 10
)
, xrows (ts, n, TimestampUnix, Open, rn) AS (
SELECT ts, n, EURUSD.TimestampUnix, EURUSD.Open
, ROW_NUMBER() OVER (PARTITION BY n ORDER BY TimestampUnix DESC)
FROM ts
JOIN EURUSD
ON EURUSD.TimestampUnix < datetime(ts.ts, '+12 hour')
AND EURUSD.TimestampUnix >= ts.ts
)
SELECT *
FROM xrows WHERE rn = 1
;
这只是一个例子。以下小提琴包含一些用于测试的数据:
Working Test Case with data
使用的数据:
基于该数据的结果: