как оптимизировать и объединить два SQL-запроса

#sql

#sql

Вопрос:

У меня есть два SQL-запроса. Во-первых, для этих pl — ‘IQ’, ‘SM’, ‘T2’, а во-вторых, для pl = ‘AT’, ‘VV’,’CM’. Я получаю следующую информацию —

введите описание изображения здесь

Есть ли какая-либо возможность оптимизировать эти два запроса и объединить их в один? Информация в операторе CASE повторяется, отличается только pl.

Первый запрос:

 /* Formatted on 10.7.2016 1:23:06  (QP5 v5.163.1008.3004) */
SELECT DISTINCT
       pl,
       SUM (
          CASE
             WHEN pl IN ('IQ', 'SM', 'T2')
             THEN
                CASE
                   WHEN time LIKE '201601%'
                   THEN
                      ( (charge / POWER (10, decimals)) * 1.27131)
                   WHEN time LIKE '201602%'
                   THEN
                      ( (charge / POWER (10, decimals)) * 1.27609)
                   WHEN time LIKE '201603%'
                   THEN
                      ( (charge / POWER (10, decimals)) * 1.263019)
                   WHEN time LIKE '201604%'
                   THEN
                      ( (charge / POWER (10, decimals)) * 1.251591)
                   WHEN time LIKE '201605%'
                   THEN
                      ( (charge / POWER (10, decimals)) * 1.248002)
                   WHEN time LIKE '201606%'
                   THEN
                      ( (charge / POWER (10, decimals)) * 1.252972)
                   WHEN time LIKE '201607%'
                   THEN
                      ( (charge / POWER (10, decimals)) * 1.248432)
                   WHEN time LIKE '201608%'
                   THEN
                      ( (charge / POWER (10, decimals)) * 1.25790)
                   WHEN time LIKE '201609%'
                   THEN
                      ( (charge / POWER (10, decimals)) * 1.240378)
                   ELSE
                      0
                END
             ELSE
                0
          END)
       OVER ()
          AS charge
  FROM ch
 WHERE     TYPE = 'MO'
       AND pl IN ('IQ', 'SM', 'T2')
       AND time BETWEEN '20160101000000' AND '20160930235959'
  

Второй запрос:

 /* Formatted on 10.7.2016 1:36:11  (QP5 v5.163.1008.3004) */
SELECT DISTINCT
   pl,
   SUM (
      CASE
         WHEN pl IN ('AT', 'VV', 'CM')
         THEN
            CASE
               WHEN time LIKE '201601%'
               THEN
                  ( (charge / POWER (10, decimals)) * 1.27131)
               WHEN time LIKE '201602%'
               THEN
                  ( (charge / POWER (10, decimals)) * 1.27609)
               WHEN time LIKE '201603%'
               THEN
                  ( (charge / POWER (10, decimals)) * 1.263019)
               WHEN time LIKE '201604%'
               THEN
                  ( (charge / POWER (10, decimals)) * 1.251591)
               WHEN time LIKE '201605%'
               THEN
                  ( (charge / POWER (10, decimals)) * 1.248002)
               WHEN time LIKE '201606%'
               THEN
                  ( (charge / POWER (10, decimals)) * 1.252972)
               WHEN time LIKE '201607%'
               THEN
                  ( (charge / POWER (10, decimals)) * 1.248432)
               WHEN time LIKE '201608%'
               THEN
                  ( (charge / POWER (10, decimals)) * 1.25790)
               WHEN time LIKE '201609%'
               THEN
                  ( (charge / POWER (10, decimals)) * 1.240378)
               ELSE
                  0
            END
         ELSE
            0
      END)
   OVER ()
      AS charge
FROM ch
WHERE     TYPE = 'MO'
   AND pl IN ('AT', 'VV', 'CM')
   AND time BETWEEN '20160101000000' AND '20160930235959'
  

Заранее спасибо за помощь

Комментарии:

1. Я удалил несовместимые теги базы данных. Пожалуйста, пометьте свой вопрос базой данных, которую вы фактически используете.

2. Есть ли какая-то особая причина использовать текстовый столбец для хранения данных {дата, время, временная метка} и их вызова time ?

Ответ №1:

Кажется, вы хотите union all :

 with q1 as (
      <first query here>
     ),
     q2 as (
      <second query here>
     )
select q1.*
from q1
union all
select q2.*
from q2;
  

Комментарии:

1. Необходим ли CTE? Табличные значения могут быть встроены в виде подзапросов.

2. @Dai . , , CTE не требуется. Вместо этого можно использовать подзапросы.

Ответ №2:

Вы и вставляете UNION между 2 запросами, чтобы объединить их. Чтобы помочь вам с оптимизацией, мне нужно больше информации, например, структура таблицы, индексы … и т.д.

Ответ №3:

если ваш запрос имеет одинаковые имена полей в инструкции select, вы можете использовать «ОБЪЕДИНЕНИЕ». простой, например, является,

 select id,name from table1 where condition
Union
select id,name from table2 where condition
  

это даст вам результат объединения обоих запросов.

Ответ №4:

Как уже упоминалось, странно, что вы, похоже, храните свои datetimes в виде строк. Но в любом случае:

Ваши запросы выбирают один и тот же тип и временной диапазон из таблицы, только один рассматривает один набор PLS, а другой — другой. Они даже используют одни и те же формулы в вашем предложении select . Так что это можно легко объединить

 with factors as
(
  select '201601%' as pattern, 1.27131 as factor
  union all
  select '201602%' as pattern, 1.27609 as factor
  union all
  select '201603%' as pattern, 1.263019 as factor
  union all
  select '201604%' as pattern, 1.251591 as factor
  union all
  select '201605%' as pattern, 1.248002 as factor
  union all
  select '201606%' as pattern, 1.252972 as factor
  union all
  select '201607%' as pattern, 1.248432 as factor
  union all
  select '201608%' as pattern, 1.25790 as factor
  union all
  select '201609%' as pattern, 1.240378 as factor
)
select pl, sum(charge) over 
            (partition by case when pl in ('IQ', 'SM', 'T2') then 1 else 2 end) as charge
from
(
  select
    pl,
    sum(case when f.factor is null then 0 
             else ch.charge / power(10, ch.decimals) * f.factor end) as charge
  from ch
  left join factors f on ch.time like f.pattern
  where type = 'MO'
  and time BETWEEN '20160101000000' AND '20160930235959'
  and pl in ('IQ', 'SM', 'T2', 'AT', 'VV', 'CM')
  group by pl
) pls;
  

Вы даже можете сделать это без подзапроса. Выберите то, что вы считаете более удобным для чтения.

 select
  pl,
  sum
  (
    sum(case when f.factor is null then 0 
             else ch.charge / power(10, ch.decimals) * f.factor end)
  ) over (partition by case when pl in ('IQ', 'SM', 'T2') then 1 else 2 end) as charge
from ch
left join factors f on ch.time like f.pattern
where type = 'MO'
and time BETWEEN '20160101000000' AND '20160930235959'
and pl in ('IQ', 'SM', 'T2', 'AT', 'VV', 'CM')
group by pl;
  

Возможно, вы захотите создать таблицу для факторов, чтобы избавиться от предложения with .