SQL重复存在子查询

问题描述 投票:0回答:1

我正在尝试编写一个查询,该查询从两个表中提取多列,然后还要查看最近28天内是否还有另一个包含相同类型数据的实例。

我已经使查询正常工作,它看起来像这样:

SELECT
     a.col_a
    ,a.col_b
    ,a.col_c
    ,b.col_a
    ,b.col_b
    ,CASE WHEN EXSISTS (SELECT a_sub.col_a
                        FROM a_sub
                        INNER JOIN b_sub
                          ON a_sub.x = b_sub.x
                        WHERE
                          b.col_a = b_sub.col_a
                          AND b.col_b <> b_sub.col_b
                          AND a.date > a_sub.date
                          AND a.date <= DATEADD(d, 28, a_sub.date)
                          AND a.col_c = a_sub.col_c
                          AND (a.col_d IS NULL OR a.col_d <> 7)
                          AND (a_sub.col_d IS NULL OR a_sub.col_d <> 7)
                        ) THEN 'Yes'
                          ELSE 'No'
                          END AS IsRepeat28
FROM a
INNER JOIN b ON a.x = b.x

这不是特别快,但也不会太慢而不会成为问题。问题是我需要重复上述WHEN EXISTS子查询,但要重复21、14、7和1天,并重复5次-查询时间从大约15秒变为大约10分钟。

我还需要调整日期,并标记为“ IsRepeat”的行,还有一个基于“ HasRepeat”的版本,其基于

AND a_sub.date > a.date AND a_sub.date <= DATEADD(d, 28, a.date)

而不是原始的

AND a.date > a_sub.date AND a.date <= DATEADD(d, 28, a_sub.date)

然后这意味着拥有10个这些EXISTS子查询,将花费近45分钟。

我的问题确实是双重的;是否有一种更有效的方式编写此子查询,并且有更好的重复方式,而不是将几乎相同的代码写出10次?

sql-server tsql subquery exists
1个回答
0
投票

我将产生数据的任何查询称为问题。 SQL仅应用于查询数据。如果您了解自己的流程及其所做的工作,则无需执行计划。

首先,将主投影作为步骤1进行分隔,根据您有多少记录,将其分为临时表或表变量。在生产查询中缓存每个需要的集合,可以将负载大小作为选择计数(*)进行度量。

    insert into @mytablevariable values
    SELECT
       a.col_a,
       a.col_b,
       a.col_c,
       b.col_a,
       b.col_b
       -- build this column later
    FROM a
    INNER JOIN b ON a.x = b.x

接下来,缓存该嵌套查询的结果,这样就不会在每次迭代中进行内部联接。

    insert into @mysub values
    SELECT a_sub.col_a
    FROM a_sub
    INNER JOIN b_sub
       ON a_sub.x = b_sub.x
       AND b.col_b <> b_sub.col_b

我们故意制造废物,因此我们可以通过根据您的处理要求对@mysub进行重塑来进行管理。我们的目标是通过以正确的顺序获取正确的数据来消除工作。

在此过程中最突出的是WHERE子句,其中日期字段在日期范围内。

    AND a.date > a_sub.date AND a.date <= DATEADD(d, 28, a_sub.date)

自然地,表未按日期列值编制索引,因此,此WHERE比较必须进行全表扫描或我们称为提取器的提取。提取器从集合中提取一部分数据(子集)。我们始终希望将提取过程减少到一遍,这只有在完成对提取器的组织标准时才能完成。

首先,通过外部@mytablevariable查询中所需的日期值范围来最小化@mysub提取器结果的大小。

    insert into @mysub values
    SELECT a_sub.col_a
    FROM a_sub
    INNER JOIN b_sub
       ON a_sub.x = b_sub.x
       AND b.col_b <> b_sub.col_b
       and a_sub.date <= DATEADD(d, 28, select min(a.date) from @mytablevariable)
       and a_sub.date > (select max(a.date) from @mytablevariable)

然后,您可以将@mysub投影到您的21天子集中,将其他较小的子集再次投影。对于WHERE子句的其余部分,使用要比较的列扩展@mysub。要构建最终产品,请从第一个表中选择所有内容,并按以下方式对每个记录进行一次查找。

    select 
        *,
        case 
            when b.col_a in (select col_a from @mysub28) then 'Yes'
            else 'No'
        end as IsRepeat28,
        case 
            when b.col_a in (select col_a from @mysub21) then 'Yes'
            else 'No'
        end as IsRepeat21
        -- rinse, repeat
    from 
    @mytablevariable

[每当您有生产流程时,请分离出组件并按照提取器的选择标准进行操作,以使它们只通过一遍。

© www.soinside.com 2019 - 2024. All rights reserved.