Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Повторное использование результата SQL-запроса


Kostafey ©   (2006-11-28 22:43:00) 

Уважаемые мастера ! Прошу оказать содействие в очередном ламеском вопросе.
Посылаю запросы в 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


ЮЮ   (2006-11-30 03:26:00) [1]

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


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


ЮЮ   (2006-11-30 03:20:00) [2]


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


Речь идет о соединения вообще, не важно вутренниие они или внешние. Кстати, 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? :)


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

> [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... я не понимаю.
Скажите речь идет о внешних соединениях так?


Kostafey   (2006-11-29 18:43:00) [4]

> [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 */


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


ЮЮ   (2006-11-29 12:36:00) [5]

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

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 11:09:00) [6]

> [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)).

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


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

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

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

Запрос


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

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

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

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


ЮЮ   (2006-11-29 04:34:00) [9]

А я бы посоветовал смотреть в сторону оптимизации.
Твой запрос - это 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 03:07:00) [10]

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


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

www.sql.ru
Book online


Kostafey   (2006-11-28 23:15:00) [12]

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


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

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

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


Palladin   (2006-11-28 23:02:00) [13]

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


Наверх

Титульная страница Поиск, карта сайта Написать письмо