Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2006.12.17;
Скачать: CL | DM;

Вниз

Повторное использование результата SQL-запроса   Найти похожие ветки 

 
Kostafey ©   (2006-11-28 22:43) [0]

Уважаемые мастера ! Прошу оказать содействие в очередном ламеском вопросе.
Посылаю запросы в SQL Server 20005.
И вот о чем начинаю задумываться.
Запрос формируется на основе нескольких вложенных коррелированных запросов.
Фрагмент подзапроса участвует в очередном подзапросе. Например:

select r.РТП,

      (select count(a.N_ZVK)
          from ZVK1 a, zvkrtp z
          where (a.N_ZVK = z.nzvk) and
    (z.rtp=r.Код) and
                (a.DATE_ZVK1 between @DateFrom and @DateTo)) as Kol1,

      round((select count(a.N_ZVK)
          from ZVK1 a, zvkrtp z
          where (a.N_ZVK = z.nzvk) and
    (z.rtp=r.Код) and
                (a.DATE_ZVK1 between @DateFrom and @DateTo))*100.0/500,2) as Acount1,

      (select count(a.N_ZVK)
          from ZVK1 a, zvkrtp z
          where (a.N_ZVK = z.nzvk) and
    (z.rtp=r.Код) and
                (a.DATE_ZVK1 between @DateFrom_s and @DateTo_s)) as Kol2,

      round((select count(a.N_ZVK)
          from ZVK1 a, zvkrtp z
          where (a.N_ZVK = z.nzvk) and
    (z.rtp=r.Код) and
                (a.DATE_ZVK1 between @DateFrom_s and @DateTo_s))*100.0/500,2) as Acount2,

      (select count(a.N_ZVK)
          from ZVK1 a, zvkrtp z
          where (a.N_ZVK = z.nzvk) and
    (z.rtp=r.Код) and
                (a.DATE_ZVK1 between @DateFrom and @DateTo))-
      (select count(a.N_ZVK)
          from ZVK1 a, zvkrtp z
          where (a.N_ZVK = z.nzvk) and
    (z.rtp=r.Код) and
                (a.DATE_ZVK1 between @DateFrom_s and @DateTo_s)) as Delfakt,

from RTP r


Хорошо бы в место этого писать что-то вроде:

select r.РТП,

      (select count(a.N_ZVK)
          from ZVK1 a, zvkrtp z
          where (a.N_ZVK = z.nzvk) and
    (z.rtp=r.Код) and
                (a.DATE_ZVK1 between @DateFrom and @DateTo)) as Kol1,

      round((Kol1)*100.0/500,2) as Acount1,

      (select count(a.N_ZVK)
          from ZVK1 a, zvkrtp z
          where (a.N_ZVK = z.nzvk) and
    (z.rtp=r.Код) and
                (a.DATE_ZVK1 between @DateFrom_s and @DateTo_s)) as Kol2,

      round((Kol2)*100.0/500,2) as Acount2,

      (Kol1)-(Kol2) as Delfakt,

from RTP r


 
Palladin ©   (2006-11-28 23:02) [1]

смотри в сторону User Defined Functions


 
Kostafey ©   (2006-11-28 23:15) [2]

> [1] Palladin ©   (28.11.06 23:02)
> смотри в сторону User Defined Functions


Спасибо, приму к сведению.

Да, к сожалению у меня довольно убогие знания по SQL.
Сложности по тому чтобы вбить любое количество кода нет.
Вопрос скорее в эффективности и, даже более всего, в красоте кода...

Не подскажете хорошие книги/статьи по тематике (кроме Google) ?


 
Palladin ©   (2006-11-28 23:38) [3]

www.sql.ru
Book online


 
Kostafey ©   (2006-11-29 03:07) [4]

Если я не ошибаюсь, то > User Defined Functions пререгатива TSQL?
А то что-то я не могу найти в литературе по SQL про них ничего. :(


 
ЮЮ ©   (2006-11-29 04:34) [5]

А я бы посоветовал смотреть в сторону оптимизации.
Твой запрос - это 6 практически одинаковах подзапроса, пыполняемых для каждой записи из RTP. т.е. вложенный пгрегатный запрос выполняется 6 * RTP.RecordCount раз.

А при правильном написнии запроса хватило бы по одному разу  для пар @DateFrom,@DateTo и @DateFrom_s, @DateTo_s:

select
 РТП,
 s.Cnt as Kol1,
 case when s.Cnt  is null then null else round(s.Cnt/5, 2) end as Acount1,
 s_s.Cnt as Kol2,
 case when s_s.Cnt  is null then null else round(s_s.Cnt/5, 2) end as Acount2,
 isnull(s.Cnt, 0) - isnull(s_s.Cnt, 0) as Delfakt
from
 RTP r
 LEFT JOIN (
  // этот подзапрос даст count(a.N_ZVK) для каждого значения z.rtp
  select z.rtp, count(a.N_ZVK) cnt
  from
    ZVK1 a,
    JOIN zvkrtp ON (a.N_ZVK = z.nzvk) and
  where
   (a.DATE_ZVK1 between @DateFrom and @DateTo))
  group by
    z.rtp
 ) s ON r.Код = s.rtp
 LEFT JOIN (
  // этот подзапрос даст count(a.N_ZVK) для каждого значения z.rtp
  select z.rtp, count(a.N_ZVK) cnt
  from
    ZVK1 a,
    JOIN zvkrtp ON (a.N_ZVK = z.nzvk) and
  where
   (a.DATE_ZVK1 between @DateFrom_s and @DateTo_s))
  group by
    z.rtp
 ) s_s ON r.Код = s_s.rtp


 
Kostafey ©   (2006-11-29 09:45) [6]

> [5] ЮЮ ©   (29.11.06 04:34)

пишет:
Incorrect syntax near the keyword "JOIN".

Что нужно исправить ?


 
Anatoly Podgoretsky ©   (2006-11-29 10:10) [7]

> Kostafey  (29.11.2006 09:45:06)  [6]

> Что нужно исправить

Запрос


 
Kostafey ©   (2006-11-29 11:09) [8]

> [7] Anatoly Podgoretsky ©   (29.11.06 10:10)
> > Kostafey  (29.11.2006 09:45:06)  [6]
> > Что нужно исправить
> Запрос


Сейчас упаду со смеху.

Хорошо, не нужно приводить пример насилования моего SQL-запроса (хотя пример в [0] рабочий).
Я думаю, что > [5] ЮЮ ©   (29.11.06 04:34) в основном прав, но его я понимаю с трудом
(кроме того в нем есть ошибки синтаксита > [6] Kostafey ©   (29.11.06 09:45)).

Просто приведите пожалуйста стурктуру того запроса, кторый должен быть.


 
ЮЮ ©   (2006-11-29 12:36) [9]

Просто приведите пожалуйста стурктуру того запроса, кторый должен быть.

from
RTP r
LEFT JOIN ( <подзапрос> ) s ON r.Код = s.rtp
LEFT JOIN ( <подзапрос>  ) s_s ON r.Код = s_s.rtp

(кроме того в нем есть ошибки синтаксита >
дельфийские комменарии
// этот подзапрос даст count(a.N_ZVK) для каждого значения z.rtp
замени на SQL-кие
-- этот подзапрос даст count(a.N_ZVK) для каждого значения z.rtp
/* этот подзапрос даст count(a.N_ZVK) для каждого значения z.rtp */


 
Kostafey ©   (2006-11-29 18:43) [10]

> [9] ЮЮ ©   (29.11.06 12:36)
> (кроме того в нем есть ошибки синтаксита >
> дельфийские комменарии
> // этот подзапрос даст count(a.N_ZVK) для каждого значения
> z.rtp
> замени на SQL-кие
> -- этот подзапрос даст count(a.N_ZVK) для каждого значения
> z.rtp
> /* этот подзапрос даст count(a.N_ZVK) для каждого значения
> z.rtp */


Да, но я это, конечно, знаю.
Ошибка вовсе не в комментарии.


 
Kostafey ©   (2006-11-29 23:27) [11]

> [5] ЮЮ ©   (29.11.06 04:34)

О! Понял что надо исправить !
Запрос прекрасно работает:

select
РТП,
case when s.Cnt  is null then 0 else  s.Cnt end as Kol1,
case when s.Cnt  is null then 0 else round(s.Cnt/5, 2) end as Acount1,
case when s_s.Cnt  is null then 0 else  s_s.Cnt end as Kol2,
case when s_s.Cnt  is null then 0 else round(s_s.Cnt/5, 2) end as Acount2,
isnull(s.Cnt, 0) - isnull(s_s.Cnt, 0) as Delfakt,
1 as Dummy
from
RTP r
LEFT JOIN (
 -- этот подзапрос даст count(a.N_ZVK) для каждого значения z.rtp
 select z.rtp, count(a.N_ZVK) cnt
 from
   ZVK1 a
   JOIN zvkrtp z ON (a.N_ZVK = z.nzvk)
 where
  (a.DATE_ZVK1 between @DateFrom and @DateTo)
 group by
   z.rtp
) s ON r.Код = s.rtp
LEFT JOIN (
 -- этот подзапрос даст count(a.N_ZVK) для каждого значения z.rtp
 select z.rtp, count(a.N_ZVK) cnt
 from
   ZVK1 a
   JOIN zvkrtp z ON (a.N_ZVK = z.nzvk)
 where
  (a.DATE_ZVK1 between @DateFrom_s and @DateTo_s)
 group by
   z.rtp
) s_s ON r.Код = s_s.rtp

Были пара синтаксических ошибок, но я вообще не представляю как можно ТАКОЕ написать не имея возможности просмотреть результат !

Спасибо огромное! Гораздо более красивый и изящный код !

Правда я с таким SQL я не владею и все что идет ниже from RTP r... я не понимаю.
Скажите речь идет о внешних соединениях так?


 
ЮЮ ©   (2006-11-30 03:20) [12]


> Скажите речь идет о внешних соединениях так?


Речь идет о соединения вообще, не важно вутренниие они или внешние. Кстати, INNER и OUTER я никогда не пишу, поэтому для себя рассматриваю только левое (LEFT) и обычное соединение.

При выборе из двух и более табли всегд есть соединение, только неявное.
SELECT FROM a, b WHERE a.b = b.a  
эквивалентно
SELECT FROM a JOIN b ON a.b = b.a  

Во-первых, когда таблиц в запросе десяток достаточно пропустить одно из услвий связи в  WHERE части и вместо связанных таблиц получим их произведение.

Во вторых ON гораздо шире по возможностям, чем WHERE:
SELECT FROM
 a
 LEFT JOIN b ON
   (a.b = b.a) AND (a.type = :Type) AND (b.[Date] BETWEEN :D1 AND :D2 )


т.е. можно связывать не все записи из a, в на записи в b наложить ограничения.
более того, можно для разных записей использовать разные ограничения:

Во вторых ON гораздо шире по возможностям, чем WHERE:
SELECT FROM
 a
JOIN b ON
   (a.b = b.a) AND (
     (a.type = :Type) AND (b.[Date] BETWEEN :D1 AND :D2 )
     OR
     (a.type <> :Type) AND (b.[Date] <:D1)                            

соединив же их просто а, b получить такой результат сразу, без case в списке выбираемых полей. Но это хорошо на MS SQL, где case есть,  а такое работает и в Local SQL.

LEFT JOIN  и  просто  JOIN отличаются же тем, что LEFT JOIN  ставим тогда, когда нас интересуют все записи из a, независимо от того, есть ли соответствующие записи в b.
Т.е. если в твоем примере не нужны был записи, если count по любому из агрегирующих подзапросов = 0, то вместо  LEFT JOIN можно было бы использовать JOIN.  

Ну и, наконец, MS SQL позволяет вместо таблиц использовать в запросах именнованные подзапросы, т.е. не просто a, а (<подзапрос>) a
     

З.Ы. Ну что ещё остальсь непонятки по части того , что идет ниже from RTP r? :)


 
ЮЮ ©   (2006-11-30 03:26) [13]

Во-первых, ...
Во вторых, ...


Наконец, при такой записи условие связи и пропустить труднее  и сами связи становятся нагляднее, так как прописаны отдельно для каждой присоединяемой таблицы, а не савлены в огромную кучу в общем для всех WHERE



Страницы: 1 вся ветка

Текущий архив: 2006.12.17;
Скачать: CL | DM;

Наверх




Память: 0.51 MB
Время: 0.051 c
15-1164391910
Колдун
2006-11-24 21:11
2006.12.17
К555РУ2


15-1164275079
Ганна Юхимівна
2006-11-23 12:44
2006.12.17
Turbo Delphi - собственный Object Inspector


2-1164688018
Syrym
2006-11-28 07:26
2006.12.17
что то связано с распечатко вложенной таблицы


2-1164634654
webpauk
2006-11-27 16:37
2006.12.17
Определить позицию в типе


8-1142757370
Kano
2006-03-19 11:36
2006.12.17
Вставка анимированных gif