-
Здравствуйте!
Есть такая задача: нужно сохранить rtf файл в базу данных, затем из базы данных получить и загрузить в редактор.
rtf передается в поток TMymoryStream.
Для записи в базу данных используется хранимая процедура типа:
@code image
AS
INSERT INTO temp_table(code) VALUES(@code)
-----------------------------------------------------
var mystream:Tmemorystream; // сюда передаю rtf
Пользуюсь компонентом ADOCommand
ADOCommand1.CommandType:=cmdStoredProc;
ADOCommand1.CommandText:='p_inferno_temp2;1';
ADOCommand1.Parameters.Clear;
ADOCommand1.Parameters.Add;
ADOCommand1.Parameters[0].Direction:=pdInput;
ADOCommand1.Parameters[0].Name:='@code'; ADOCommand1.Parameters[0].LoadFromStream(mystream,ftBlob);
Параметру не передается значение из потока.
такой вариант записи в базу вобще возможен?
-
with ADOCommand1 do
begin
Connection := ....;
CommandText := 'exec s_MyProc @code=:code';
Parameters.ParamByName('code').DataType := ftBlob;
Parameters.ParamByName('code').LoadFromStream(mystream,ftBlob);
try
Execute;
except
......
end;
end;
-
Это осилил, спасибо, а как теперь из базы выгрузить в stream?
-
with TADODataSet.Create(nil) do
begin
try
Connection := .....;
CommandText := 'Select code from temp_table';
try
Open;
if IsEmpty then Exit;
ms := TMemoryStream.Create;
try
TBLOBField(FieldByName('code')).SaveToStream(ms, ftBLOB);
ms.Position := 0;
... Работаем с ms
finally
ms.Free;
end;
except
.....
end;
finally
Free;
end;
end;
-
спасибо за оперативность :)
пойду пробовать
-
Все работает.
Теперь пытаюсь сделать вывод с помощью хранимой процедуры
если просто то:
CREATE PROCEDURE temp_out
AS
select code from temp_table
GO
В принципе я вызываю процедуру, она мне возвращает набор, и я его обрабатываю как описано выше... Так будет работать?
-
> Так будет работать?
>
Да.
Только я бы сделал такую процедуру:
CREATE PROCEDURE s_temp_table
@ActNam varchar(32)='NONE',
@Code image =NULL
AS
Declare @result int;
Set NoCount On;
Set @ActNam=LTrim(RTrim(Upper(@ActNam)));
Set @result=0;
if @ActNam='SEL'
begin
Select code from temp_table;
Goto Fin;
end;
if @ActNam='ADD'
begin
Insert into temp_table (code) Values (@code);
Goto Fin;
end;
FIN:
return(@result);
GO
Ну и вызов в случае добавления - exec s_temp_table @ActNam='ADD', @code=:code
выборки - exec s_temp_table @ActNam='SEL'
-
Круто, сейчас у меня глаза на место встанут (они на стол выпали), и я разберусь..
Пока все временное, просто пробую - потом конечно все это обрастет кодом ;)
Спасибо за точный и быстрый ответ
-
А еще такой вопросик, не стал новую тему создавать...
Слышал, что в новых версиях msSQL не будет типа данных image. На сколько эти слуи - правда?
-
> Viod (14.07.2008 6:17:08) [8]
Тип будет, имени не будет.
А зачем слухами пользуешься?
-
Да не то чтобы пользуюсь - услышал и спросил по быстрому.
Имени не будет... Так процедуры хранимые переписывать придется при переводе на новую версию сервера?
-
> if @ActNam='SEL'
> begin
> Select code from temp_table;
> Goto Fin;
> end;
Хм... а почему goto, а не else?
-
> Имени не будет... Так процедуры хранимые переписывать придется
> при переводе на новую версию сервера?
Возможно и придется, имя типа будет другое.
-
> Хм... а почему goto, а не else?
Это лишь шаблон, там этих @AcNam до чёртиков может быть.
Короче, привык так... :)
-
А вот такой вопрос: для того чтобы вытащить из базы blob поле в Stream мы используем ADODataSet. По методу Open он как я понимаю должен вернуть набор записей. А если записи не вернулись, тоесть хранимая процедура не вернула набор записей - дебаггер оворит, что все плохо :)
Хранимая процедура выглядит так:
IF EXISTS(select .......)
BEGIN
SELECT ...........
RETURN 0
END
ELSE RETURN -1
Так вот когда RETURN -1, тогда Open сделать не выходит...
Как обработать этот случай. Или как получить blob с помощью AdoCommand.
Пробовал
AdoCommand.Execute.Fields[номер поля].value
вроде возвращает обычные типы данных а вот blob не хочет
-
> Хранимая процедура выглядит так:
А не надо так делать. Возвращай Select в любом случае. т.е. вместо
IF EXISTS(select .......)
BEGIN
SELECT ...........
RETURN 0
END
ELSE RETURN -1
делай
SELECT .....
RETURN 0
А вот на клиенте уже проверяй:
with DataSet do
begin
try
Open;
if IsEmpty then ....
else ....
except
....
end;
end;
-
Ясно... Ну а чисто теоретически с AdoCommand реально?
-
> Ну а чисто теоретически с AdoCommand реально?
Реально. _RecordSet же есть.
Но не советую. В смысле, как у тебя запрос был сформирован. В одном случае НД возвращается, а в другом - нет. Причём заранее определить нельзя - вернётся он или нет.
Это потенциальная дыра.
-
так вот интересно.
rec:_recordset;
rec:=AdoCommand.execute;
Это вобще правильно или нет?
-
реально но большого смысла нет.
AdoCommand как результат возвращает рекордсет т.что можно выполнить в нем и вытаскивать блоб из результирующего рекордсета если он не пустой (рекордсет возвращается в любом случае, просто по пустому в твоем случае уже ADODataSet генерит исключение, а до этого ты сам в процедуре делишь по проверке на пустой и нет... сплошные проверки в общем)
имхо, то что ты делаешь и в процедуру то "заворачивать" смысла нет... (как и 90% написанных sql процедур, их пишут не потому что они действительно нужны, а потому что начинающему сказали что это "круто"/правильно/лучше/удобнее(?)/...)
-
> В одном случае НД возвращается, а в другом - нет.
в любом случае возвращается.
-
просто хочется всю безопасность со своего кода на sql переложить
-
> в любом случае возвращается.
IF EXISTS(select .......)
BEGIN
SELECT ...........
RETURN 0
END
ELSE RETURN -1
Где тут НД возвращается, если not exists?
-
Ниче не вернет если нот ексистс проверено :)
-
sniknik, а че плохо чтоле? Получил 0 - работай, получил -1 не работай.
А если тебе нужно по сложному алгоритму что-то из базы получать. Клиентская машина итак еле шевелится. Перекладываешь все на SQL'ник и все. Код в дельфи прилично выглядит: не приходится запросы писать, а они ведь бывают очень длинными. Да и потом хранимые процедуры и с представлениями могут работать.. Попробуй ка все в делфи впихнуть :)
А проверки в хранимых процедурах... пустой набор записей когда возвращается - тоже вроде не очень приятно?
-
sniknik, а че плохо чтоле? Получил 0 - работай, получил -1 не работай.
А если тебе нужно по сложному алгоритму что-то из базы получать. Клиентская машина итак еле шевелится. Перекладываешь все на SQL'ник и все. Код в дельфи прилично выглядит: не приходится запросы писать, а они ведь бывают очень длинными. Да и потом хранимые процедуры и с представлениями могут работать.. Попробуй ка все в делфи впихнуть :)
А проверки в хранимых процедурах... пустой набор записей когда возвращается - тоже вроде не очень приятно?
-
> Где тут НД возвращается, если not exists?
AdoCommand.execute:_recordset;
> Ниче не вернет если нот ексистс проверено :)
тебе это просто не показывают... а на самом деле возвращается, без рекордсета оно не может, там кроме данных в структуре еще информационная инфа есть т.что. в любом случае. гарантированно.
-
> sniknik, а че плохо чтоле? Получил 0 - работай, получил -1 не работай.
то же самое от запроса. никакой выгоды... как минус разнесение логики на 2 места. (возможно именно это и нужно, но это как раз входит в оставшиеся 10% вместе со сложными процедурами. вряд ли твой случай)
-
Ну тут я не знаю.. Не специалист. Просто на деле получается исключение. Предлагаешь отключить integrated debugging и смотреть IsEmpty как ни в чем не бывало?
-
> Просто на деле получается исключение.
sniknik © (28.07.08 10:51) [19]
> просто по пустому в твоем случае уже ADODataSet генерит исключение
> AdoCommand.execute
-
sniknik, мы не поняли друг друга. На 2 проверки все разносится потому что я не могу использовать AdoCommand для выборки из базы blob поля. Если бы я это сделал - я бы использовал возвращаемые хранимой процедурой значения. А поскольку мне приходится использовать aDodataSet - получается что я сделал мартышкин труд. Когда я все это планировал - думал использовать только AdoCommand и только проверки внутри хранимой процедуры.
Объясни лучше как получить значение Blob поля из выборки, исползуя AdoCommand. Blob поле будет допустим в fields[0]
-
> На 2 проверки все разносится потому что я не могу использовать AdoCommand для выборки из базы blob поля.
тебе не предлагали использовать AdoCommand для blob, это было предложено уже для проверки, что и RETURN -1 вернет рекордсет.
по твоей "проблеме" нормальное решение предложил Ega23 © (28.07.08 10:18) [15], проверка в одном месте.
> Объясни лучше как получить значение Blob поля из выборки, исползуя AdoCommand.
это будет ненормальное решение... но раз так хочется, присвой результат execute рекордсету в ADODataSet и работай уже с ним (или посмотри как он это делает, и повтори... если желаешь еще больше мазохистских удовольствий.).
-
> А поскольку мне приходится использовать aDodataSet - получается что я сделал мартышкин труд.
именно им ты сейчас и занимаешься. нужно упрощать то, что делаешь а не усложнять.
-----------------------------
усложнять просто, упрощать сложно! © не помню чей
-
:) Сижу и не могу... Давай так: однозначный ответ на вопрос "можно вытащить из базы блоб поле и загрузить его в Stream используя AdoCommand, но не используя AdoDataSet"? Да или Нет? :)
Я же говорю, чисто теоретически. Проблема уже решена благодаря Ega23, за что большое спасибо.
Просто изначально планировалось, что с базой будет работать один единственный компонент AdoCommand. Вот я и мучаю себя и остальных, чтобы однозначно понять реально это или нет
-
> можно вытащить из базы блоб поле и загрузить его в Stream
> используя AdoCommand, но не используя AdoDataSet
Можно. Но не стОит.
-
> Просто изначально планировалось, что с базой будет работать
> один единственный компонент AdoCommand.
Это не самый лучший вариант. Есть такая вещь, как скомпилированные запросы (Prepared:=True); на такие лучше свой экземпляр TADODataSet или TADOCommand держать.
-
> однозначный ответ на вопрос
да. но показывать как не буду, ломает делать бессмысленную работу которая к тому же ухудшит программу если вдруг будет использовано.
> что с базой будет работать один единственный компонент AdoCommand.
а смысл? на компонентах экономить не стоит, раз уж чтото используется, то используется, хоть 1 раз встреченное хоть 128, на размере exe не скажется, проверь, добавь несколько пустышек (без запросов внутри, они то добавятся, а код нет. ООП однако.)
-
Не могу ниче понять. Может туплю...
Вот t-sql:
CREATE PROCEDURE s_select_vopros_by_id
@id_vopros int=0
AS
SELECT * FROM new_test.dbo.t_vopros WHERE id_vopros=@id_vopros
Вот Delphi:
with data.ADODataSet1 do begin
CommandText:='exec s_select_vopros_by_id @id_vopros=:id_vopros';
Parameters.ParamByName('id_vopros').Direction:=pdInput;
Parameters.ParamByName('id_vopros').Value:=number;
Open;
If not(IsEmpty) then
Showmessage(FieldByName('id_vopros').value);
end;
Первый раз код делфи проходит с number: = 110 - все норм, второй раз с number:=112 - showmessage ВОЗВРАЩАЕТ 110.
Как так?
-
>
> Как так?
А где Close?
-
Удалено модератором
-
> Спасибо за помощь, думаю не последний раз написал ;)
Не за что, удачи!
-
> sniknik (28.07.2008 12:14:36) [36]
На размере ехе скажется как раз один AdoCommand - не в лучшую сторону конечно.
-
Ко вчерашнему спрору о проверке внутри процедуры или в делфи:
Допустим хранимая процедура получает параметром идентификатор записи. Смотрит есть ли эта запись
if EXISTS(SELECT... WHERE Idn=@idn)
и удаляет запись и возвращает 0. Если записи нет, то возвращает -1.
Как мне в этом случае оставить проверку на стороне приложения? В смысле как это сделать более-менее коротко и красиво?
-
Способ 1.
Declare @X int;
Select @X=exec S_MyProc @Id=18;
Select Result=@X;
Способ 2.
CREATE PROCEDURE s_MyProc
@ID int =-1,
@SelOut int = 1,
@Debug int =0
As
Declare @result int;
if Exists (Select ... from ... where id=@ID)
begin
Delete from ... where ID=@ID
Set @Result=0
end
else
Set Result=-1;
if @SelOut=1
Select Result=@result;
return(@result);
GO
Вызов второго варианта.
Если хочешь получить результат, то через TADODataSet.Open:
exec S_MyProc @ID=...
Если не хочешь получить результат, то через TADOCommand.Execute:
exec S_MyProc @ID=..., @SelOut=0
-
Спс.
-
> удаляет запись и возвращает 0. Если записи нет, то возвращает -1.
способ 3... правильный. (бредите вы этими процедурами чтоли?)
- простейший запрос в ADOCommand1, внесенный в десигне, вида
delete from ... where ID=:ID
выполнение
var
RecAff: integer;
begin
ADOCommand1.Parameters.ParamByName('ID').Value:= ...;
ADOCommand1.Execute(RecAff);
if RecAff > 0
then
else
end;
все. и зачем сложности с процедурами? не нужна она тут.