Shagg |
Отправлено: 08.11.2006, 07:25 |
|
Дежурный стрелочник
Группа: Участник
Сообщений: 69
|
Всем привет! Появилась необходимость написать функцию на сервере, которая выполняла бы передаваемый ей запрос и возвращала бы это все одной строкой. Т.е. формат функции приблизительно такой:
CODE | GetRowSetAsString(@table, @col, @condition); |
где
@table = название таблицы из которой вытаскивать
@col = колонки
@condition = некоторое условие.
Функция строит запрос типа
CODE | 'select '+@col+' from '+@table+' where '+@condition |
собирает все в строку и возвращает.
Пробовал через курсоры, но на объявление типаCODE | declare cur cursor for 'select '+@col+' from '+@table+' where '+@condition | выдает "Incorrect syntax"
Как сделать? Подскажите или намекните.
Заранее прошу прощения если вопрос ламерский, но с БД я не очень близко дружу |
|
Shagg |
Отправлено: 08.11.2006, 07:26 |
|
Дежурный стрелочник
Группа: Участник
Сообщений: 69
|
Да забыл. Сервер — MSSQL 2000. |
|
olegenty |
Отправлено: 08.11.2006, 08:13 |
|
Ветеран
Группа: Модератор
Сообщений: 2412
|
1. помещаешь результат DSQL во временную таблицу.
2. пробегаешь курсором по временной таблице и генерируешь выходную строку.
|
|
Shagg |
Отправлено: 08.11.2006, 09:46 |
|
Дежурный стрелочник
Группа: Участник
Сообщений: 69
|
А как нить по другому? Так долго получается, мне эту функцию часто нужно будет вызывать. |
|
AVC |
Отправлено: 08.11.2006, 10:10 |
|
Ветеран
Группа: Модератор
Сообщений: 1583
|
QUOTE (Shagg @ 08.11.2006, 07:25) | Появилась необходимость написать функцию которая выполняла бы передаваемый ей запрос и возвращала бы это все одной строкой ... Функция строит запрос типа
'select '+@col+' from '+@table+' where '+@condition
собирает все в строку и возвращает.
|
Не понял, что за строку должна возвращать функция? Конкатенация (может с разделителями) всех значений одной колонки выборки ? |
|
olegenty |
Отправлено: 08.11.2006, 10:26 |
|
Ветеран
Группа: Модератор
Сообщений: 2412
|
по-другому никак, без перебора записей столбец в строку ты не поместишь. вопрос только в том, сделаешь ты это на стороне сервера, или на стороне клиента. а вот это как раз стоит обдумать.
|
|
Shagg |
Отправлено: 08.11.2006, 11:29 |
|
Дежурный стрелочник
Группа: Участник
Сообщений: 69
|
Извините.Наверно я не так описал проблему.
Результирующая строка формируется конкатенацией всех значений столбца @col через запятую (например). Выполняться естессно будет на сервере (USER DEFINED FUNCTION). А перебор на клиенте типаCODE | for (ADOQuery1->First(); !ADOQuery1->Eof; ADOQuery1->Next()) s += ADOQuery->FieldByName("ffield")->AsString+ ','; | не подходит, так как мне нужно обрабатывать запросы типа:CODE | select ('table2', 'col1', 'id in('+idlist+')') from table1 | А писать вложенные циклы с запросами так не охота.
В принципе, задача сводится к тому, чтобы открыть курсор для запроса, передаваемого строкой. Некое подобие функции EXEC. |
|
AVC |
Отправлено: 08.11.2006, 12:17 |
|
Ветеран
Группа: Модератор
Сообщений: 1583
|
Да, курсор правильное решение если, конечно, нет готовой функции (например у sybase asa она называется List). Осталось только разобраться с синтаксисом MS Sql, но тут не моя епархия а, напимер, olegenty. Если он говорит курсоров нет — значит нет.
На всяк случай привожу решение для Oracl'a (8). Может что полезное подчерпнете.
CODE |
CREATE OR REPLACE Function HHC.ToList
(pSqlText in varchar2
,pSep in varchar2 default Null
,pPref in varchar2 default Null
,pPost in varchar2 default Null
,pBaseText in varchar2 default Null
)
return varchar2
As
Type TAnyCursor Is REF CURSOR;
tcur TAnyCursor;
vSep varchar2( 100) := Trim(NVL(pSep,','));
vPref varchar2( 100) := Trim(pPref);
vPost varchar2( 100) := Trim(pPost);
vtext varchar2(32700) := pBaseText;
vVal varchar2( 4200);
vbylo boolean;
Begin
Open tcur For pSqlText;
vbylo := false;
Begin
Loop
Fetch tcur Into vVal;
Exit when not tcur%FOUND;
if (vbylo) then vtext := vtext || vSep; end if;
vbylo := true;
vtext := vtext || vPref || vval || vPost;
end Loop;
Exception when OTHERS then vtext := Null;
End;
Close tcur;
return vtext;
End;
/
| |
|
olegenty |
Отправлено: 08.11.2006, 12:29 |
|
Ветеран
Группа: Модератор
Сообщений: 2412
|
я как раз говорю — с курсором. но через временную таблицу.
например:
CODE |
create table #List(Line varchar(200));
declare @DSQL varchar(8000)
set @DSQL = 'insert into #List select ' + @column + ' from table ' + @table + ' where ' + @conditions
exec(@DSQL)
declare @Line varchar(200)
declure @Result varchar(8000)
set @Result = ''
declare C cursor local fast_forward for select Line from #List
open C
fetch next from C into @Line
while (@@fetch_status = 0) begin
@Result = @Result + ',' + @Line
fetch next from C into @Line
end
close C
deallocate ActionC
-- тут удали первую запятую
return @Result
|
|
|
olegenty |
Отправлено: 08.11.2006, 12:33 |
|
Ветеран
Группа: Модератор
Сообщений: 2412
|
только хрен там, временные таблицы нельзя использовать в теле функции, можно только табличные переменные. но табличная переменная не будет видна из DSQL. курсор для DSQL выражения не откроешь, скажет fuck you...
щас ещё подумаю...
|
|
olegenty |
Отправлено: 08.11.2006, 12:42 |
|
Ветеран
Группа: Модератор
Сообщений: 2412
|
Shagg, функция никак не получится. Всё, что ты можешь сделать — это обернуть результирующую выборку в хранимую процедуру. А вот в её теле переворачивать что угодно и как угодно... ответ окончательный, обжалованию не подлежит.
Теперь о самой постановке. если тебе это надо для in, то тебе вообще не нужна такая функция, ты можешь так и написать:
where some_field in (select some_other_field from some_other_table where conditions)
и последнее — динамическое in надо использовать так редко, как только это возможно, поскольку нарвёшься если не на table scan в плане выполнения, то на фетч всех записей по условию подзапроса в in, а реально нужна только одна запись — достаточно знать, есть ли ХОТЬ ОДНА удовлетворяющая условию запись. а для этого надо использовать where exists и where not exists... это азы...
|
|
Shagg |
Отправлено: 10.11.2006, 07:15 |
|
Дежурный стрелочник
Группа: Участник
Сообщений: 69
|
мда. Пробдема в том, что in вернет несколько строк. А мне то вся эта барахляндия нужна в одной ячейке... Ладно буду мутить на клиенте, благо возможности С++ неисчерпаемы. Спасибо всем за помощь. |
|