如何将我的 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 BYTOP 来控制行数。

【讨论】:

您的输入需要保存在表格中,因为它们是多行。可以是变量表(以@开头)、临时表(以#开头)或物理表(持久)。我已经包含了一个带有变量表的示例。 太好了,谢谢你。据我了解,它将为每一对运行查询。与多个查询相比,您认为这意味着性能提升吗? 是的,关系数据库已经过优化,可以在集合中工作。尽可能避免一对一的查询或操作。 好的,我试试!非常感谢!【参考方案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 查询?

如何将 presto 查询输出转换为 python 数据框

为啥 `fetch` 将我的 JSON 字符串转换为查询字符串?副作用? [复制]

如何在 SQL 查询中将行转换为固定列

将我的 mssql 查询变成结构化的 xml 结果集

如何执行选择查询,而不锁定更新查询