如何将我的 N 个小查询转换为一个查询?
Posted
技术标签:
【中文标题】如何将我的 N 个小查询转换为一个查询?【英文标题】:How can I transform my N little queries into one query? 【发布时间】:2019-06-18 15:16:38 【问题描述】:我有一个查询,它为我提供给定日期和对的第一个可用值。
SELECT
TOP 1 value
FROM
my_table
WHERE
date >= 'myinputdate'
AND key = 'myinpukey'
ORDER BY date
我有 N 对键和日期,我试图找出如何不逐一查询每一对。表比较大,N也比较大,所以现在又重又慢。
如何在一个查询中查询所有对?
【问题讨论】:
样本数据最好使用DDL + DML。请edit您的问题包括它,您当前的尝试和您想要的结果。更多详情,read this. @DavidG :我期望每个键/日期对得到一个结果。 (date > 'date1' and key = 'key1') 的值,(date > 'date2' and key = 'key2') 的值。如果所有对都有对应的值,我想从 N 对中得到 N 个结果。 【参考方案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
如果您还希望显示NULL
结果值,可以使用OUTER APPLY
。这支持获取多列并使用ORDER BY
和TOP
来控制行数。
【讨论】:
您的输入需要保存在表格中,因为它们是多行。可以是变量表(以@开头)、临时表(以#开头)或物理表(持久)。我已经包含了一个带有变量表的示例。 太好了,谢谢你。据我了解,它将为每一对运行查询。与多个查询相比,您认为这意味着性能提升吗? 是的,关系数据库已经过优化,可以在集合中工作。尽可能避免一对一的查询或操作。 好的,我试试!非常感谢!【参考方案2】:此解决方案没有变量。您可以通过为 row_num
谓词设置正确的值来控制您的 N。
有很多方法可以让您随心所欲,这一切都取决于您的具体需求。正如它已经回答的那样,您可以使用临时/变量表来存储这些条件,然后在使用谓词的相同条件下加入它。您还可以创建用户定义的数据类型并将其用作函数/过程的参数。您可以使用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;
【讨论】:
【参考方案3】:如果所有键都使用相同的日期,则使用窗口函数:
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;
【讨论】:
所以你的意思是所有对的日期都相同?那么,就不是这样了。【参考方案4】: 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;
【讨论】:
它是否只适用于所有配对的唯一日期? 分区在键、日期字段和按日期字段排序...所以外部查询过滤每个键、日期对的 rownum=1 说实话我不太明白你的查询是什么。它是否给出了表中存在的任何键/日期对的结果?以上是关于如何将我的 N 个小查询转换为一个查询?的主要内容,如果未能解决你的问题,请参考以下文章
如何将我的 Bigquery 查询转换为 AWS Athena 查询?