Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2006.12.17;
Скачать: [xml.tar.bz2];

Вниз

Повторное использование результата 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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.5 MB
Время: 0.041 c
15-1164284577
alexsis
2006-11-23 15:22
2006.12.17
Игра Blood


2-1164519655
apic
2006-11-26 08:40
2006.12.17
исполняемый файл в чужой процесс


3-1160373460
jbond
2006-10-09 09:57
2006.12.17
Работа из Turbo Delphi Explorer с SQLite


15-1164723562
TUser
2006-11-28 17:19
2006.12.17
Чего только не бывает ...


5-1145440086
DVM
2006-04-19 13:48
2006.12.17
Переопределить OnClick у потомка TCustomControl?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский