对一个表使用CASE语句的SQL Multiple WHERE子句

时间:2018-07-23 17:40:13

标签: sql odbc where ibm-midrange

我写了这个查询,它似乎正在收集正确的结果,但是,这也需要很长时间。我只是想知道是否有办法提高效率? (我知道它的效率很低,因为它正在创建数据表并将它们重新连接在一起-我只是不知道如何解决它,特别是在包含CASE问题的情况下。)

我正在使用与AS400进行ODBC连接的Excel。问号允许用户在Excel单元格中输入参数。

with W as
(
  select yr as YEAR, pd as PERIOD, sum(amt1 + amt2 + amt3 + amt4) as SALES
    from TABLE
    group by yr, pd
    order by yr desc, pd desc
), X as
(
  select yr as YEAR, pd as PERIOD, sum(amt1 + amt2 + amt3 + amt4) as BSALES
    from TABLE
    where type = 'B'
    group by yr, pd
    order by yr desc, pd desc
), Y as
(
  select
    CASE WHEN pd = 1 THEN yr - 1 ELSE yr END as YEAR, 
    CASE WHEN pd = 1 THEN 12 ELSE pd - 1 END as PERIOD, 
    SUM(OM) as MODOM
    from TABLE
    group by yr, pd
    order by yr desc, pd desc
), Z as
(
  select
    CASE WHEN pd = 1 THEN yr - 1 ELSE yr END as YEAR, 
    CASE WHEN pd = 1 THEN 12 ELSE pd - 1 END as PERIOD, 
    SUM(BOM) as BMODOM
    from TABLE
    where type = 'B'
    group by yr, pd
    order by yr desc, pd desc
)
select w.YEAR, w.PERIOD, w.SALES, x.BSales, y.MODOM, z.BMODOM
from w inner join x
on w.YEAR = x.YEAR and w.PERIOD = x.PERIOD
inner join y
on w.YEAR = y.YEAR and w.PERIOD = y.PERIOD
inner join z
on w.YEAR = z.YEAR and w.PERIOD = z.PERIOD
where w.YEAR between ? and ? and w.PERIOD between ? and ?
order by YEAR desc, PERIOD desc

出于隐私目的,我不得不稍微更改代码,但我相信所有这些都可以正确传达。

示例数据:

Yr  Pd  Type    Amt OM
18  2   A       45  181
18  2   B       33  163
18  2   A       40  153
18  1   B       39  136
18  1   B       24  142
18  1   B       53  143
18  1   A       41  186
18  1   A       78  197
17  12  A       98  139
17  12  A       54  159
17  12  B       78  181
17  12  B       45  101
17  11  A       28  134
17  11  A       77  192
17  11  A       75  110
17  11  B       60  135
17  11  B       83  170
17  10  B       72  114
17  10  A       26  118
17  10  A       95  111
17  9   A       12  112
17  9   B       14  171

示例结果

Yr  Pd  Sales   Bsales  MODOM   BMODOM
18  2   118     33      804     421
18  1   235     116     580     282
17  12  275     123     741     305
17  11  323     143     343     114
17  10  193     72      283     171

请注意,我需要在TOTAL级别然后在TYPE B级别进行销售。我还需要在TOTAL级别的OM,然后在B型级别-但是-我需要抵消一个期间。因此,MODOM是针对17-10的,反映了表中时段17-9的OM总数。 (我希望这是有道理的。)

EDIT (我很落后)。 17-10的MODOM实际上会反映17-11的OM值,而不是其他方式。更正了预期结果。

Yr  Pd  Sales   Bsales  MODOM   BMODOM
18  2   118     33      0       0
18  1   235     116     497     163
17  12  275     123     804     421
17  11  323     143     580     282
17  10  193     72      741     305

1 个答案:

答案 0 :(得分:2)

因此,使用条件聚合,您至少可以摆脱2个公用表表达式,这将有所帮助。直到您的最终表示查询(而不是在每个公用表表达式中)才进行排序也将有所帮助。使用实际日期,例如一个月的第一个月中的第一个月可以帮助消除在定义前一个期间时潜在的代价高昂的案例表达方式。

有几种写方法,但这将为您提供条件聚集的示例。

请注意使用LEFT JOIN而不是INNER,因为如果您使用INNER,您的第一个期间将始终退出查询

WITH PeriodSales AS(
    SELECT
       yr as YEAR
       ,pd AS PERIOD
       ,SUM(amt) as SALES
       ,SUM(CASE WHEN type = 'B' THEN amt END) as BSALES
    FROM
       Table
    GROUP BY
       yr
       ,pd
)
, PreviousPeriod AS 
(
    SELECT
       CASE WHEN pd = 12 THEN yr + 1 ELSE yr END as YEAR
       ,CASE WHEN pd = 12 THEN 1 ELSE pd + 1 END as PERIOD
       ,SUM(OM) as MODOM
       ,SUM(CASE WHEN type = 'B' THEN OM END) as BMODOM
    FROM
       Table
    GROUP BY
       CASE WHEN pd = 12 THEN yr + 1 ELSE yr END
       ,CASE WHEN pd = 12 THEN 1 ELSE pd + 1 END
)

SELECT
    ps.YEAR
    ,ps.PERIOD
    ,ps.SALES
    ,ps.BSALES
    ,pp.MODOM
    ,pp.BMODOM
FROM
    PeriodSales ps
    LEFT JOIN PreviousPeriod pp
    ON ps.YEAR = pp.YEAR
    AND ps.PERIOD = pp.PERIOD
ORDER BY
    ps.YEAR DESC
    ,ps.PERIOD DESC

根据您的修改,要与“上一个期间”对齐以获得所需的OM金额,您实际上将要添加一个期间而不是在我使用的示例中减去一个期间。我已经对此进行了测试,并且可以正常工作。如果不了解更多有关表和执行计划等信息,我们可能会发现许多其他性能因素。