我有一个查询,该查询为我提供了给定日期和货币对的第一个可用值。
SELECT
TOP 1 value
FROM
my_table
WHERE
date >= 'myinputdate'
AND key = 'myinpukey'
ORDER BY date
我有N对键和日期,并且我尝试找出如何不一一查询每个对。桌子很大,N也很大,所以它又重又慢。
如何在一次查询中查询所有对?
答案 0 :(得分:1)
一种解决方案是使用APPLY
就像动态创建的“函数”,其中包含来自另一组的一个或多个列:
DECLARE @inputs TABLE (
myinputdate DATE,
myinputkey INT)
INSERT INTO @inputs(
myinputdate,
myinputkey)
VALUES
('2019-06-05', 1),
('2019-06-01', 2)
SELECT
I.myinputdate,
I.myinputkey,
R.value
FROM
@inputs AS I
CROSS APPLY (
SELECT TOP 1
T.value
FROM
my_table AS T
WHERE
T.date >= I.myinputdate AND
T.key = I.myinputkey
ORDER BY
T.date ) AS R
如果希望也显示OUTER APPLY
结果值,则可以使用NULL
。这支持获取多个列,并将ORDER BY
与TOP
一起使用以控制行数。
答案 1 :(得分:1)
此解决方案没有变量。您可以通过为row_num
谓词设置正确的值来控制 N 。
有很多方法可以满足您的需求,这取决于您的特定需求。正如它已经回答的那样,您可以使用temp / variable表存储这些条件,然后在使用谓词的相同条件下将其联接。您还可以创建用户定义的数据类型,并将其用作函数/过程的参数。您可以使用CROSS APPLY
+ VALUES
子句来获取该列表,然后将其加入。
DROP TABLE IF EXISTS #temp;
CREATE TABLE #temp ( d DATE, k VARCHAR(100) );
GO
INSERT INTO #temp
VALUES ( '20180101', 'a' ),
( '20180102', 'b' ),
( '20180103', 'c' ),
( '20180104', 'd' ),
( '20190101', 'a' ),
( '20190102', 'b' ),
( '20180402', 'c' ),
( '20190103', 'c' ),
( '20190104', 'd' );
SELECT a.d ,
a.k
FROM ( SELECT d ,
k ,
ROW_NUMBER() OVER ( PARTITION BY k ORDER BY d DESC ) row_num
FROM #temp
WHERE (d >= '20180401'
AND k = 'a')
OR (d > '20180401'
AND k = 'b')
OR (d > '20180401'
AND k = 'c')
) a
WHERE a.row_num <= 1;
-- VALUES way
SELECT a.d ,
a.k
FROM ( SELECT t.d ,
t.k ,
ROW_NUMBER() OVER ( PARTITION BY t.k ORDER BY t.d DESC ) row_num
FROM #temp t
CROSS APPLY (VALUES('20180401','a'), ('20180401', 'b'), ('20180401', 'c')) f(d,k)
WHERE t.d >= f.d AND f.k = t.k
) a
WHERE a.row_num <= 1;
答案 2 :(得分:0)
如果所有键都使用相同的日期,则使用窗口功能:
SELECT key, value
FROM (SELECT t.*, ROW_NUMBER() OVER (PARTITION BY key ORDER BY date) as seqnum
FROM my_table t
WHERE date >= @input_date AND
key IN ( . . . )
) t
WHERE seqnum = 1;
答案 3 :(得分:0)
SELECT key, date,value
FROM (SELECT ROW_NUMBER() OVER (PARTITION BY key,date ORDER BY date) as rownum,key,date,value
FROM my_table
WHERE
date >= 'myinputdate'
) as d
WHERE d.rownum = 1;