Конференция "Базы" » Stream and AdoCommand [D7, MSSQL]
 
  • Viod © (11.07.08 11:40) [0]
    Здравствуйте!
    Есть такая задача: нужно сохранить 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);

    Параметру не передается значение из потока.
    такой вариант записи в базу вобще возможен?
  • Ega23 © (11.07.08 11:53) [1]
    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;

  • Viod © (11.07.08 13:03) [2]
    Это осилил, спасибо, а как теперь из базы выгрузить в stream?
  • Ega23 © (11.07.08 13:09) [3]
    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;

  • Viod © (11.07.08 13:12) [4]
    спасибо за оперативность :)
    пойду пробовать
  • Viod © (11.07.08 13:25) [5]
    Все работает.
    Теперь пытаюсь сделать вывод с помощью хранимой процедуры

    если просто то:
    CREATE PROCEDURE temp_out
    AS
    select code from temp_table
    GO

    В принципе я вызываю процедуру, она мне возвращает набор, и я его обрабатываю как описано выше... Так будет работать?
  • Ega23 © (11.07.08 13:32) [6]

    > Так будет работать?
    >


    Да.
    Только я бы сделал такую процедуру:

    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'
  • Viod © (11.07.08 13:42) [7]
    Круто, сейчас у меня глаза на место встанут (они на стол выпали), и я разберусь..
    Пока все временное, просто пробую - потом конечно все это обрастет кодом ;)

    Спасибо за точный и быстрый ответ
  • Viod © (14.07.08 06:17) [8]
    А еще такой вопросик, не стал новую тему создавать...
    Слышал, что в новых версиях msSQL не будет типа данных image. На сколько эти слуи - правда?
  • Anatoly Podgoretsky © (14.07.08 08:35) [9]
    > Viod  (14.07.2008 6:17:08)  [8]

    Тип будет, имени не будет.
    А зачем слухами пользуешься?
  • Viod © (14.07.08 10:01) [10]
    Да не то чтобы пользуюсь - услышал и спросил по быстрому.
    Имени не будет... Так процедуры хранимые переписывать придется при переводе на новую версию сервера?
  • clickmaker © (14.07.08 11:12) [11]
    > if @ActNam='SEL'
    > begin
    > Select code from temp_table;
    > Goto Fin;
    > end;

    Хм... а почему goto, а не else?
  • Anatoly Podgoretsky © (14.07.08 11:50) [12]

    > Имени не будет... Так процедуры хранимые переписывать придется
    > при переводе на новую версию сервера?

    Возможно и придется, имя типа будет другое.
  • Ega23 © (14.07.08 19:43) [13]

    > Хм... а почему goto, а не else?


    Это лишь шаблон, там этих @AcNam до чёртиков может быть.
    Короче, привык так...  :)
  • Viod © (28.07.08 10:09) [14]
    А вот такой вопрос: для того чтобы вытащить из базы 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 не хочет
  • Ega23 © (28.07.08 10:18) [15]

    > Хранимая процедура выглядит так:


    А не надо так делать. Возвращай 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;

  • Viod © (28.07.08 10:42) [16]
    Ясно... Ну а чисто теоретически с AdoCommand реально?
  • Ega23 © (28.07.08 10:47) [17]

    > Ну а чисто теоретически с AdoCommand реально?


    Реально. _RecordSet же есть.
    Но не советую. В смысле, как у тебя запрос был сформирован. В одном случае НД возвращается, а в другом - нет. Причём заранее определить нельзя - вернётся он или нет.
    Это потенциальная дыра.
  • Viod © (28.07.08 10:50) [18]
    так вот интересно.
    rec:_recordset;

    rec:=AdoCommand.execute;
    Это вобще правильно или нет?
  • sniknik © (28.07.08 10:51) [19]
    реально но большого смысла нет.
    AdoCommand как результат возвращает рекордсет т.что можно выполнить в нем и вытаскивать блоб из результирующего рекордсета если он не пустой (рекордсет возвращается в любом случае, просто по пустому в твоем случае уже ADODataSet генерит исключение, а до этого ты сам в процедуре делишь по проверке на пустой и нет... сплошные проверки в общем)

    имхо, то что ты делаешь и в процедуру то "заворачивать" смысла нет... (как и 90% написанных sql процедур, их пишут не потому что они действительно нужны, а потому что начинающему сказали что это "круто"/правильно/лучше/удобнее(?)/...)
  • sniknik © (28.07.08 10:53) [20]
    > В одном случае НД возвращается, а в другом - нет.
    в любом случае возвращается.
  • Viod © (28.07.08 11:00) [21]
    просто хочется всю безопасность со своего кода на sql переложить
  • Ega23 © (28.07.08 11:01) [22]

    > в любом случае возвращается.



    IF EXISTS(select .......)
      BEGIN
         SELECT ...........
         RETURN 0
      END
      ELSE RETURN -1



    Где тут НД возвращается, если not exists?
  • Viod © (28.07.08 11:03) [23]
    Ниче не вернет если нот ексистс проверено :)
  • Viod © (28.07.08 11:08) [24]
    sniknik, а че плохо чтоле? Получил 0 - работай, получил -1 не работай.
    А если тебе нужно по сложному алгоритму что-то из базы получать. Клиентская машина итак еле шевелится. Перекладываешь все на SQL'ник и все. Код в дельфи прилично выглядит: не приходится запросы писать, а они ведь бывают очень длинными. Да и потом хранимые процедуры и с представлениями могут работать.. Попробуй ка все в делфи впихнуть :)
    А проверки в хранимых процедурах... пустой набор записей когда возвращается - тоже вроде не очень приятно?
  • Viod © (28.07.08 11:08) [25]
    sniknik, а че плохо чтоле? Получил 0 - работай, получил -1 не работай.
    А если тебе нужно по сложному алгоритму что-то из базы получать. Клиентская машина итак еле шевелится. Перекладываешь все на SQL'ник и все. Код в дельфи прилично выглядит: не приходится запросы писать, а они ведь бывают очень длинными. Да и потом хранимые процедуры и с представлениями могут работать.. Попробуй ка все в делфи впихнуть :)
    А проверки в хранимых процедурах... пустой набор записей когда возвращается - тоже вроде не очень приятно?
  • sniknik © (28.07.08 11:10) [26]
    > Где тут НД возвращается, если not exists?
    AdoCommand.execute:_recordset;

    > Ниче не вернет если нот ексистс проверено :)
    тебе это просто не показывают... а на самом деле возвращается, без рекордсета оно не может, там кроме данных в структуре еще информационная инфа есть т.что. в любом случае. гарантированно.
  • sniknik © (28.07.08 11:13) [27]
    > sniknik, а че плохо чтоле? Получил 0 - работай, получил -1 не работай.
    то же самое от запроса. никакой выгоды... как минус разнесение логики на 2 места. (возможно именно это и нужно, но это как раз входит в оставшиеся 10% вместе со сложными процедурами. вряд ли твой случай)
  • Viod © (28.07.08 11:15) [28]
    Ну тут я не знаю.. Не специалист. Просто на деле получается исключение. Предлагаешь отключить integrated debugging и смотреть IsEmpty как ни в чем не бывало?
  • sniknik © (28.07.08 11:17) [29]
    > Просто на деле получается исключение.
    sniknik ©   (28.07.08 10:51) [19]
    > просто по пустому в твоем случае уже ADODataSet генерит исключение

    > AdoCommand.execute
  • Viod © (28.07.08 11:31) [30]
    sniknik, мы не поняли друг друга. На 2 проверки все разносится потому что я не могу использовать AdoCommand для выборки из базы blob поля. Если бы я это сделал - я бы использовал возвращаемые хранимой процедурой значения. А поскольку мне приходится использовать aDodataSet - получается что я сделал мартышкин труд. Когда я все это планировал - думал использовать только AdoCommand и только проверки внутри хранимой процедуры.
    Объясни лучше как получить значение Blob поля из выборки, исползуя  AdoCommand. Blob поле будет допустим в fields[0]
  • sniknik © (28.07.08 11:52) [31]
    > На 2 проверки все разносится потому что я не могу использовать AdoCommand для выборки из базы blob поля.
    тебе не предлагали использовать AdoCommand для blob, это было предложено уже для проверки, что и RETURN -1 вернет рекордсет.

    по твоей "проблеме" нормальное решение предложил Ega23 ©   (28.07.08 10:18) [15], проверка в одном месте.

    > Объясни лучше как получить значение Blob поля из выборки, исползуя  AdoCommand.
    это будет ненормальное решение... но раз так хочется, присвой результат execute рекордсету в ADODataSet и работай уже с ним (или посмотри как он это делает, и повтори... если желаешь еще больше мазохистских удовольствий.).
  • sniknik © (28.07.08 11:54) [32]
    > А поскольку мне приходится использовать aDodataSet - получается что я сделал мартышкин труд.
    именно им ты сейчас и занимаешься. нужно упрощать то, что делаешь а не усложнять.

    -----------------------------
    усложнять просто, упрощать сложно! © не помню чей
  • Viod © (28.07.08 12:03) [33]
    :) Сижу и не могу... Давай так: однозначный ответ на вопрос "можно вытащить из базы блоб поле и загрузить его в Stream используя AdoCommand, но не используя AdoDataSet"? Да или Нет? :)

    Я же говорю, чисто теоретически. Проблема уже решена благодаря Ega23, за что большое спасибо.

    Просто изначально планировалось, что с базой будет работать один единственный компонент AdoCommand. Вот я и мучаю себя и остальных, чтобы однозначно понять реально это или нет
  • Ega23 © (28.07.08 12:10) [34]

    > можно вытащить из базы блоб поле и загрузить его в Stream
    > используя AdoCommand, но не используя AdoDataSet


    Можно. Но не стОит.
  • Ega23 © (28.07.08 12:12) [35]

    > Просто изначально планировалось, что с базой будет работать
    > один единственный компонент AdoCommand.


    Это не самый лучший вариант. Есть такая вещь, как скомпилированные запросы (Prepared:=True); на такие лучше свой экземпляр TADODataSet или TADOCommand держать.
  • sniknik © (28.07.08 12:14) [36]
    > однозначный ответ на вопрос
    да. но показывать как не буду, ломает делать бессмысленную работу которая к тому же ухудшит программу если вдруг будет использовано.

    > что с базой будет работать один единственный компонент AdoCommand.
    а смысл? на компонентах экономить не стоит, раз уж чтото используется, то используется, хоть 1 раз встреченное хоть 128, на размере exe не скажется, проверь, добавь несколько пустышек (без запросов внутри, они то добавятся, а код нет. ООП однако.)
  • Viod © (28.07.08 12:32) [37]
    Не могу ниче понять. Может туплю...
    Вот 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.

    Как так?
  • Ega23 © (28.07.08 12:36) [38]

    >
    > Как так?


    А где Close?
  • Viod © (28.07.08 12:41) [39]
    Удалено модератором
  • Ega23 © (28.07.08 12:43) [40]

    > Спасибо за помощь, думаю не последний раз написал ;)


    Не за что, удачи!
  • Anatoly Podgoretsky © (28.07.08 13:01) [41]
    > sniknik  (28.07.2008 12:14:36)  [36]

    На размере ехе скажется как раз один AdoCommand - не в лучшую сторону конечно.
  • Viod © (29.07.08 10:05) [42]
    Ко вчерашнему спрору о проверке внутри процедуры или в делфи:
    Допустим хранимая процедура получает параметром идентификатор записи. Смотрит есть ли эта запись
    if EXISTS(SELECT... WHERE Idn=@idn)

    и удаляет запись и возвращает 0. Если записи нет, то возвращает -1.
    Как мне в этом случае оставить проверку на стороне приложения? В смысле как это сделать более-менее коротко и красиво?
  • Ega23 © (29.07.08 10:16) [43]
    Способ 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

  • Viod © (29.07.08 12:54) [44]
    Спс.
  • sniknik © (29.07.08 13:32) [45]
    > удаляет запись и возвращает 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 //есть запись, а может и не одна (что подразумевает ID?)
       else //нет записей
    end;



    все. и зачем сложности с процедурами? не нужна она тут.
 
Конференция "Базы" » Stream and AdoCommand [D7, MSSQL]
Есть новые Нет новых   [134473   +28][b:0][p:0.003]