Discussion:
группировки и процедуры
(слишком старое сообщение для ответа)
Soloshenko Dmitriy
18 лет назад
Permalink
Кучу мануала просмотрел, но не могу понять как решить задачу :(

Задача:
1) В процедуре вызвать другую процедуру которая возвращает таблицу
(procTable).
2) В procTable сгруппировать записи по полю MyField, так же как это делал бы
запрос такого вида:
Select MyField
From MyTable
group by MyField.
3) Пройтись по группированным записям делаю вызов сгруппированного поля
MyField в новой таблице и вставить все это дело в конечную таблицу endTable.

В литературе описаны только частные случаи действий, но как только доходит
до конкретики ничего не работает :(
Программировал на IB/FB, а там все принципиально по иному. Как в MSSQL
005 - ума не приложу. В IB/FB все делается "на ура". даже без промежуточных
тамблиц.... Помогите, плиз....
Sergey Gerasin
18 лет назад
Permalink
Привет!
Post by Soloshenko Dmitriy
Кучу мануала просмотрел, но не могу понять как решить задачу :(
1) В процедуре вызвать другую процедуру которая возвращает таблицу
(procTable).
CREATE PROCEDURE PROC2
AS
BEGIN
... тра-ля-ля ...
SELECT поле1, поле2, поле3
FROM фиг его знает откуда
WHERE фиг его знает как
GROUP фиг его знает по чему
END

CREATE PROCEDURE PROC1
AS
BEGIN
CREATE TABLE #procTable (поле1 тип, поле2 тип, поле3 тип)
-- либо DECLARE @procTable TABLE (поле1 тип, поле2 тип, поле3 тип)
INSERT INTO #procTable EXEC PROC2
-- либо INSERT INTO @procTable EXEC PROC2
END
Post by Soloshenko Dmitriy
2) В procTable сгруппировать записи по полю MyField, так же как это делал
бы
Select MyField
From MyTable
group by MyField.
А что мешает это сделать сразу запросом в PROC2? И вернуть уже
сгруппированную таблицу? В любом случае, в PROC1 после получения данных в
#procTable можно сделать:

SELECT * INTO #groupedTable FROM #procTable GROUP BY ...

И дальше работать с #groupedTable. #procTable можно сразу после этого явно
кильнуть с помощью DROP TABLE. А можно и не килять, само убьется при
завершении процедуры или разрыве коннекта.

Если хочется "как в IB", то вместо PROC2 можно сделать табличную функцию.
Расписывать пример не буду, в Books Online все очень хорошо описано. Вызов в
процедуре будет выглядеть так:

CREATE PROCEDURE PROC1
AS
BEGIN
SELECT * INTO #procTable FROM <владелец>.FUNC1()
-- при этом создастся временная таблица с полями, определяемыми перечнем
под SELECT'ом, и с соответствующими типами полей
END

У функций есть ограничения, вытекающие в основном из требования
недопустимости "side effects". Например, невозможность вызывать хранимки и
выполнять изменение данных в БД, кроме локальных для функции табличных
переменных. Так что - процедура или функция, определяется исключительно
задачей и избранным методом ее решения.
Post by Soloshenko Dmitriy
3) Пройтись по группированным записям делаю вызов сгруппированного поля
MyField в новой таблице и вставить все это дело в конечную таблицу
endTable.
Вот это совсем непонятно... Что значит "пройтись"? Как правило, 95% вещей,
которые решаются в IB/FB (а зачастую и в Оракле) "обходом", в Transact SQL
элегантно делаются с помощью обычных запросов на изменение и временных
таблиц (либо табличных переменных). Использование курсоров требуется
чрезвычайно редко. Поставь задачу более четко :)
--
С уважением, Сергей.
***@energomash.ru
ICQ: 63474652



Отправлено через сервер Форумы@mail.ru - http://talk.mail.ru
Dmitry Novikov
18 лет назад
Permalink
Всем привет!
Post by Sergey Gerasin
CREATE TABLE #procTable (поле1 тип, поле2 тип, поле3 тип)
INSERT INTO #procTable EXEC PROC2
В 2005-м разрешили такую фенечку? В 2000-м нельзя в переменную
типа таблица рекордсет из хранимки пихать.

С наилучшими пожеланиями, Дмитрий.
dim_nУБРАТЬrnivcРУССКИЕkisБУКВЫru
Sergey Gerasin
18 лет назад
Permalink
Привет :)

??>> -- либо INSERT INTO @procTable EXEC PROC2

DN> В 2005-м разрешили такую фенечку? В 2000-м нельзя в переменную
DN> типа таблица рекордсет из хранимки пихать.

Ой, по инерции написал... Точно, не было в 2000. В 2005 - ща проверю :)
Сорри за дезу. Остальное все правильно - проверял :)
--
С уважением, Сергей.
***@energomash.ru
ICQ: 63474652



Отправлено через сервер Форумы@mail.ru - http://talk.mail.ru
Soloshenko Dmitriy
18 лет назад
Permalink
Спасибо. п. 1. пройден успешно...
Post by Sergey Gerasin
Post by Soloshenko Dmitriy
2) В procTable сгруппировать записи по полю MyField, так же как это делал
А что мешает это сделать сразу запросом в PROC2? И вернуть уже
сгруппированную таблицу?
Ну, в Proc1 запрос строится с учетом параметров. в вот в прок 2, хотелось
осузествлять группировку.
DECLARE @groupedTable TABLE (MyFiled varchar(250))

SELECT MyFiled INTO #groupedTable FROM #procTable GROUP BY MyFiled
Вот здесь не получается... при созхранении пишет, что некорректный синтаксис
около #groupedTable
...
в FB я бы сделал примерно так:

FOR
SELECT MyField FROM groupedTable
INTO :MyField
DO
BEGIN
FOR
SELECT ID, F1, F2, F3 FROM MyTable2
INTO :ID, :F1, :F2, :F3
WHERE F1 = :MyField
DO
suspend;

END

К сожалению, как реализовать такой простой код на MSSQL не понимаю....
Post by Sergey Gerasin
--
С уважением, Сергей.
ICQ: 63474652
Sergey Gerasin
18 лет назад
Permalink
Привет :)

??>> А что мешает это сделать сразу запросом в PROC2? И вернуть уже
??>> сгруппированную таблицу?
SD> Ну, в Proc1 запрос строится с учетом параметров. в вот в прок 2,
SD> хотелось осузествлять группировку.

Ну и пусть строится с учетом параметров... Какая разница? Сразу и
сгруппировать при выдаче результата. Хотя это уже хозяйское дело :) Кста,
функции тоже можно делать с параметрами (это я на всякий случай напоминаю
:))

??>> В любом случае, в PROC1 после получения данных в #procTable можно
??>> сделать:

SD> DECLARE @groupedTable TABLE (MyFiled varchar(250))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Это здесь не нужно. Данная конструкция создает не временную таблицу, а
табличную переменную. Количество отличий между ними небольшое, но они
существенны. Если интересно, могу отдельно рассказать, хотя в BOL это
подробно расписано.
SELECT INTO же с табличными переменными не работает, как уже заметил Дмитрий
Новиков.

SD> SELECT MyFiled INTO #groupedTable FROM #procTable GROUP BY MyFiled
SD> Вот здесь не получается... при созхранении пишет, что некорректный
SD> синтаксис около #groupedTable

Странно... Все верно написано. У меня сейчас отработало. Можешь полностью
код привести?
При использовании SELECT INTO конечная таблица создается автоматически, в
соответствии с перечнем полей в SELECT и их типами. Потому явно создавать
таблицу не надо. Более того, на момент выполнения SELECT INTO такой таблицы
не должно еще существовать.

Можно заполнить временную таблицу данными и таким образом:

CREATE TABLE #groupedTable (MyField VARCHAR(250))

INSERT INTO #groupedTable
SELECT SELECT MyFiled FROM #procTable GROUP BY MyFiled

Но такая запись длиннее, и, кроме того, требует явного указания перечня
полей искомой таблицы при ее создании. SELECT INTO упрощает эту задачу.
Цитата из BOL:

"The SELECT INTO statement creates a new table and populates it with the
result set of the SELECT statement. SELECT INTO can be used to combine data
from several tables or views into one table. It can also be used to create a
new table that contains data selected from a linked server.
The structure of the new table is defined by the attributes of the
expressions in the select list."

SD> в FB я бы сделал примерно так:

SD> FOR
SD> SELECT MyField FROM groupedTable
SD> INTO :MyField
SD> DO
SD> BEGIN
SD> FOR
SD> SELECT ID, F1, F2, F3 FROM MyTable2
SD> INTO :ID, :F1, :F2, :F3
SD> WHERE F1 = :MyField
SD> DO
SD> suspend;

SD> END

Гм...

Последним оператором процедуры в MS SQL в этом случае будет нечто вроде:

SELECT t1.ID, t1.F1, t1.F2, t1.F3
FROM
MyTable2 t1
INNER JOIN
#groupedTable t2
ON t2.MyField = t1.F1
ORDER BY
t2.F1

Имхо, даже в IB такая конструкция будет проще и красноречивее :) Заодно -
эффективнее. Ибо позволяет серверу построить наиболее эффективный план
запроса. Т.е.:

FOR
SELECT t1.ID, t1.F1, t1.F2, t1.F3
FROM
MyTable2 t1
INNER JOIN
groupedTable t2
ON t2.MyField = t1.F1
INTO :ID, :F1, :F2, :F3
ORDER BY
t2.F1
DO
suspend;

При работе с данными в любой реляционной БД от процедурного подхода надо
отвыкать ;)
--
С уважением, Сергей.
***@energomash.ru
ICQ: 63474652



Отправлено через сервер Форумы@mail.ru - http://talk.mail.ru
Dmitry Novikov
18 лет назад
Permalink
Всем привет!
Post by Sergey Gerasin
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Это здесь не нужно. Данная конструкция создает не временную таблицу, а
табличную переменную. Количество отличий между ними небольшое, но они
существенны. Если интересно, могу отдельно рассказать, хотя в BOL это
подробно расписано.
SELECT INTO же с табличными переменными не работает, как уже заметил Дмитрий
Новиков.
Hеправда :о) Я говорил, что с ними не работает insert into. А select into вообще
не умеет с хранимками работать, независимо от типа таблицы :о) Это в 2000.


С наилучшими пожеланиями, Дмитрий.
dim_nУБРАТЬrnivcРУССКИЕkisБУКВЫru
Sergey Gerasin
18 лет назад
Permalink
Привет :)

DN> Hеправда :о) Я говорил, что с ними не работает insert into. А select
DN> into вообще не умеет с хранимками работать, независимо от типа таблицы
DN> :о) Это в 2000.

Чего ж я так гоню... Вроде тока из отпуска... :(

Короче, обобщая: :D

INSERT INTO @table_var EXEC proc1 - работает в 2005

SELECT <чего-нить> INTO @table_var ... - не работает, поскольку само собой
есть нонсенс. Нельзя объявить переменную таким образом.

SELECT INTO не работает с процедурами, потому что в принципе EXEC proc не
может служить источником данных для SELECT, согласно документации. Хотя,
конечно, было бы заманчиво иметь возможность

SELECT * FROM
table1 t1
INNER JOIN
(EXEC proc1) t2
ON ...

Но увы ;)

Вроде все :)
--
С уважением, Сергей.
***@energomash.ru
ICQ: 63474652



Отправлено через сервер Форумы@mail.ru - http://talk.mail.ru
Soloshenko Dmitriy
18 лет назад
Permalink
Такс, приступаю к изучению и экспериментам. После ваших выяснений у меня
сплошная каша в голове :) Так что, в наказание, если у меня ничего не
получится, буду стучаться в аську :))))
Sergey Gerasin
18 лет назад
Permalink
Привет :)

SD> Такс, приступаю к изучению и экспериментам. После ваших выяснений у
SD> меня сплошная каша в голове :) Так что, в наказание, если у меня ничего
SD> не получится, буду стучаться в аську :))))

Ну для начала было бы неплохо изучить матчасть :) Конкретно - разделы BOL
касательно временных таблиц (temporary tables), табличных переменных (table
variables), процедур, функций (user-defined functions), а также
использования операторов SELECT и INSERT применительно к оным :) Потому что
бОльшая часть того, что я писал - перевод BOL на русский язык :)
--
С уважением, Сергей.
***@energomash.ru
ICQ: 63474652



Отправлено через сервер Форумы@mail.ru - http://talk.mail.ru
Soloshenko Dmitriy
18 лет назад
Permalink
...
Могу пересислить список книг, которые я прочел перед тем как задать вопрос
:) и в которых этого всего нету :)))
Кстати, все здорово получилось. Хоть. правда, без SELECT MyFiled INTO
#groupedTable FROM #procTable GROUP BY MyFiled

Отлажусь, потом еще поспрашиваю :)))
Sergey Gerasin
18 лет назад
Permalink
Привет :)


SD> Могу пересислить список книг, которые я прочел перед тем как задать
SD> вопрос :) и в которых этого всего нету :)))

Ну дык читать надо не "список" книг, а лишь одну, вечную, на все времена,
аминь :D - SQL Server Books Online ;) Там все (почти) есть. Предмет
разговора - точно :)

SD> Кстати, все здорово получилось. Хоть. правда, без SELECT MyFiled INTO
SD> #groupedTable FROM #procTable GROUP BY MyFiled

Иначе и быть не могло :)
--
С уважением, Сергей.
***@energomash.ru
ICQ: 63474652



Отправлено через сервер Форумы@mail.ru - http://talk.mail.ru
Loading...