Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
Топик располагается на нескольких страницах: Ctrl  назад   1 .. 31 32 33 34 35 36 37 38 [39] 40   вперед  Ctrl
 Re: FireDAC  [new]
Arioch
Member

Откуда:
Сообщений: 10006
fraks,

> вытянуть данные запроса в массив и дальше работать с ним

....это пока данных не очень много.

а то был такой "паттерн" - select * from TableX - после чего все фильтрация делается только на клиенте
поначалу хорошо и просто, но когда БД вырастает, и с ней одновременно работает десяток-другой клиентов....

А для выгрузки в массив из запроса в UIB надо объявить record с такими же полями как в запросе, а дальщше примерно так:

type RQuery = record {поля запроса} end;
var L: TList<RQuery>; Q: TUIBQuery; Row: RQuery;
.......
for Row in Q.All<RQuery> do L.Add(Row);

Ну и потом, еслиъ хочется, ..... := L.ToArray();

Только это копирование по памяти многократное туда-сюда. И фрагментация кучи.
27 июл 18, 13:27    [21608136]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
fraks
Member

Откуда: Новосибирск
Сообщений: 1385
Arioch
fraks,

> вытянуть данные запроса в массив и дальше работать с ним

....это пока данных не очень много.

а то был такой "паттерн" - select * from TableX - после чего все фильтрация делается только на клиенте
поначалу хорошо и просто, но когда БД вырастает, и с ней одновременно работает десяток-другой клиентов....


Не надо приписывать мне то что я не говорил.
А не говорил я то что нужно вытаскивать всю таблицу на клиента и работать с этими на клиенте.
Я писал что данные ЗАПРОСА вытаскиваются на клиента. Т.е. то же самое что и датасет, но только вместо датасета - массив, той или иной технологии.

Arioch
А для выгрузки в массив из запроса в UIB надо объявить record с такими же полями как в запросе, а дальщше примерно так:

type RQuery = record {поля запроса} end;
var L: TList<RQuery>; Q: TUIBQuery; Row: RQuery;
.......
for Row in Q.All<RQuery> do L.Add(Row);

Ну и потом, еслиъ хочется, ..... := L.ToArray();

Только это копирование по памяти многократное туда-сюда. И фрагментация кучи.


Примерно так я поначалу и делал. Объявлял record с нужными полями, делал динамический массив этих рекордов.
Довольно удобно и быстро, но главный минус - код получается для каждого запроса индивидуальным.
Мне это довольно быстро надоело и я сделал свой динамический массив, поля в котором объявляются в рантайме, а все методы работают независимо от количества и типа полей, и их не нужно переписывать.

Поля я объявляю в OnCreate формы, там задается
- имя
- заголовок для грида
- тип данных
- форматирование при выводе в виде строки (для грида)
- выравнивание данных
- выравнивание шапки (к сожаллению в TVirtualTreeView задать выравнивание для данных и для шапки нельзя)
- загружаю из Ini ширину полей с прошлого раза (или дефолтные значения, если в Ini еще ничего нет)

Если поле есть в запросе но не объявлено в массиве - при выполнении запроса оно создастся само.
Это удобно при написании программы, пока не полностью определен список полей в таблице, можно не заморачиваться объявлением сразу всего.

Так же есть привязка этого массива к TViirtualTreeView в режиме грида.
И к статус-бару, в котором отображается количество записей в массиве и время выполнения запроса (вместе с фетчем).
И к попам-меню на гриде. Туда добавляются пункты поиска по CTRL+F, сохранения данных в файл.

Понятие "текущая запись" у меня существует только в гриде. По массиву можно бегать как угодно.

Типичная процедура получения и отображения данных выглядит так:

procedure TFrmDNC.F5;
begin
  CDV.RowSavePosition;
  CDS.ExecSelect(QSel);
  CDV.Sync;
  CDV.RowRestorePositionID;
end;


Случай посложнее - вот так:

+
procedure TFrmAM.F5;
var
  i         : integer;
  amin      : integer;
  ost_base  : integer;
  ost_base2 : integer;
  ost_shop  : integer;
  kol_in    : integer;
  kol       : integer;
  ord_kol   : integer;
  color_set : string;
begin
  CDV.RowSavePosition;
  {}
  QSel.ParamByName('data1'          ).AsDateTime := EditData1.Date;   // TODO - откусить оттуда время
  QSel.ParamByName('data2'          ).AsDateTime := EditData2.Date;   // TODO - откусить оттуда время
  QSel.ParamByName('data_in1'       ).AsDateTime := EditDataIn1.Date; // TODO - откусить оттуда время
  QSel.ParamByName('data_in2'       ).AsDateTime := EditDataIn2.Date; // TODO - откусить оттуда время
  QSel.ParamByName('nsklad_shop'    ).AsInteger  := Fnsklad_shop;
  QSel.ParamByName('nsklad_base'    ).AsInteger  := Fnsklad_base;
  QSel.ParamByName('nsklad_base2'   ).AsInteger  := Fnsklad_base2;
  QSel.ParamByName('lta'            ).AsInteger  := Flta;
  QSel.ParamByName('nord'           ).AsInteger  := Ford_nord;
  // фильтры
  QSel.ParamByName('filter_ost_base' ).AsInteger  := CBoxFilter_OstBase.ItemIndex;
  QSel.ParamByName('filter_ost_base2').AsInteger  := CBoxFilter_OstBase2.ItemIndex;
  QSel.ParamByName('filter_ost_shop' ).AsInteger  := CBoxFilter_OstShop.ItemIndex;
  QSel.ParamByName('filter_kol_in'   ).AsInteger  := CBoxFilter_KOL_IN.ItemIndex;
  QSel.ParamByName('filter_kol'      ).AsInteger  := CBoxFilter_KOL.ItemIndex;
  QSel.ParamByName('filter_am'       ).AsInteger  := CBoxFilter_AM.ItemIndex;
  QSel.ParamByName('filter_ord'      ).AsInteger  := CBoxFilter_ORD.ItemIndex;
  CDS.ExecSelect(QSel);
  {раскрасим}
  for i := 0 to CDS.Count-1 do begin
    ost_base   := CDS.ReadInt64FN(i, 'ost_base' );
    ost_base2  := CDS.ReadInt64FN(i, 'ost_base2');
    ost_shop   := CDS.ReadInt64FN(i, 'ost_shop' );
    kol_in     := CDS.ReadInt64FN(i, 'kol_in'   );
    kol        := CDS.ReadInt64FN(i, 'kol'      );
    amin       := CDS.ReadInt64FN(i, 'am'       );
    ord_kol    := CDS.ReadInt64FN(i, 'ord_kol'  );
    //
    color_set := '';
    if CheckBox_BLUE.Checked
      then if (kol > ost_shop) and (ost_base > 0) and (ord_kol = 0) // продажа за период больше остатка, и есть на основном складе, и не заказали
             then color_set := 'BLUE';
    if CheckBox_RED.Checked
      then if (amin > 0) and (ost_shop = 0) // входит в ассорт. минимум но нет в магазине
             then color_set := 'RED';
    //
    CDS.WriteStringFN(i, 'ROW_COLOR', color_set);
  end;{for}
  CDS.SortOnFields('-ROW_COLOR;GR_POD;NAME');
  CDS_CalcCena; //  расчитаем CENA_DISC - цена с учетом скидок по категориям наценки, с шапки заказа
  {}
  CDV.Sync;
  CDV.RowRestorePositionID;
end;


Запрос QSel для второго случая вот такой:
+
-- FrmAM.QSel
--
-- Проверка ассортиментного минимума по магазину
--

with dat as (
-- остаток склада-магазина
select
  id            as id,
  ost           as ost_shop,
  0             as ost_base,
  0             as ost_base2,
  0             as kol_in,
  0             as kol,
  0             as am,
  0             as ord_kol
from bost
where (nsklad = :nsklad_shop)
  and (ost > 0)

union all

-- остаток основного склада
select
  id            as id,
  0             as ost_shop,
  ost           as ost_base,
  0             as ost_base2,
  0             as kol_in,
  0             as kol,
  0             as am,
  0             as ord_kol
from bost
where (nsklad = :nsklad_base)
  and (ost > 0)

union all

-- остаток основного склада 2
select
  id            as id,
  0             as ost_shop,
  0             as ost_base,
  ost           as ost_base2,
  0             as kol_in,
  0             as kol,
  0             as am,
  0             as ord_kol
from bost
where (nsklad = :nsklad_base2)
  and (ost > 0)

union all

-- приходы за период
select
  btov.idtov    as id,
  0             as ost_shop,
  0             as ost_base,
  0             as ost_base2,
  sum(btov.kol) as kol_in,
  0             as kol,
  0             as am,
  0             as ord_kol
from bdok
  left join btov using (ndok, io)
where (bdok.nsklad = :nsklad_shop)
  and (bdok.io     = 'T')
  and (bdok.oper   = 0  ) --  кроме возвратов
  and (bdok.type_  = 0  ) -- только закрытые
  and (bdok.idpost > 0  ) -- исключим перемещения
  and not (btov.ndok is NULL) -- исключим шапки пустых документов и появление NULL в результатах
  and (bdok.data >= :data_in1)
  and (bdok.data <  :data_in2)

group by btov.idtov

union all

-- продажи за период
select
  btov.idtov    as id,
  0             as ost_shop,
  0             as ost_base,
  0             as ost_base2,
  0             as kol_in,
  sum(btov.kol) as kol,
  0             as am,
  0             as ord_kol
from bdok
  left join btov using (ndok, io)
where (bdok.nsklad = :nsklad_shop)
  and (bdok.io     = 'F')
  and (bdok.oper   = 0  ) --  кроме возвратов
  and (bdok.type_  = 0  ) -- только закрытые
  and (bdok.idpost > 0  ) -- исключим перемещения
  and not (btov.ndok is NULL) -- исключим шапки пустых документов и появление NULL в результатах
  and (bdok.data >= :data1)
  and (bdok.data <  :data2)

group by btov.idtov

union all

-- ассортиментный минимум
select
  ltb.id_stov   as id,
  0             as ost_shop,
  0             as ost_base,
  0             as ost_base2,
  0             as kol_in,
  0             as kol,
  1             as am,
  0             as ord_kol
from ltb
where (ltb.id_lta = :lta) -- Набор товаров "хиты продаж"

union all

-- заказ контрагента
select
  bord.idtov    as id,
  0             as ost_shop,
  0             as ost_base,
  0             as ost_base2,
  0             as kol_in,
  0             as kol,
  0             as am,
  bord.kol      as ord_kol

from bord
where (bord.nord   = :nord)

)

select
  dat.id                             as id,
  max(sag.name || ' / ' || sap.name) as gr_pod,
  max(sap.name           )           as pod,
  max(stov.idautor       )           as idautor,
  max(sautor.name        )           as autor,
  max(sat.name           )           as name,
  max(sat.cena_out/100.00)           as cena_out,
  max(stov.markup_cat    )           as markup_cat,
  sum(dat.ost_base       )           as ost_base,
  sum(dat.ost_base2      )           as ost_base2,
  sum(dat.ost_shop       )           as ost_shop,
  sum(dat.kol_in         )           as kol_in,
  sum(dat.kol            )           as kol,
  sum(dat.am             )           as am,
  sum(dat.ord_kol        )           as ord_kol

from dat
  left join stov      on (stov.id    = dat.id       )
  left join sautor    on (sautor.id  = stov.idautor )
  left join sa as sat on (sat.id_lcl = dat.id) and (sat.id_st = 3)
  left join sa as sap on (sap.id     = sat.id_parent)
  left join sa as sag on (sag.id     = sap.id_parent)

group by id

having (1=1)
  and (
      ((:filter_ost_base  = 0)                                   )
   or ((:filter_ost_base  = 1) and (sum(dat.ost_base       ) > 0))
   or ((:filter_ost_base  = 2) and (sum(dat.ost_base       ) = 0))
      )
  and (
      ((:filter_ost_base2 = 0)                                   )
   or ((:filter_ost_base2 = 1) and (sum(dat.ost_base2       ) > 0))
   or ((:filter_ost_base2 = 2) and (sum(dat.ost_base2       ) = 0))
      )
  and (
      ((:filter_ost_shop  = 0)                                   )
   or ((:filter_ost_shop  = 1) and (sum(dat.ost_shop       ) > 0))
   or ((:filter_ost_shop  = 2) and (sum(dat.ost_shop       ) = 0))
      )
  and (
      ((:filter_kol_in    = 0)                                   )
   or ((:filter_kol_in    = 1) and (sum(dat.kol_in         ) > 0))
   or ((:filter_kol_in    = 2) and (sum(dat.kol_in         ) = 0))
      )
  and (
      ((:filter_kol       = 0)                                   )
   or ((:filter_kol       = 1) and (sum(dat.kol            ) > 0))
   or ((:filter_kol       = 2) and (sum(dat.kol            ) = 0))
      )
  and (
      ((:filter_am        = 0)                                   )
   or ((:filter_am        = 1) and (sum(dat.am             ) > 0))
   or ((:filter_am        = 2) and (sum(dat.am             ) = 0))
      )
  and (
      ((:filter_ord       = 0)                                   )
   or ((:filter_ord       = 1) and (sum(dat.ord_kol        ) > 0))
   or ((:filter_ord       = 2) and (sum(dat.ord_kol        ) = 0))
      )


И поля объявляются вот так:

+
procedure TFrmAM.FormCreate(Sender: TObject);
begin
  {исправим косяки Delphi}
  AssignDatabase (self);
  {размер и положение окна}
  Top    := Ini.ReadInteger(IniSectionName, 'Top'   ,  10);
  Left   := Ini.ReadInteger(IniSectionName, 'Left'  ,  10);
  Width  := Ini.ReadInteger(IniSectionName, 'Width' , 500);
  Height := Ini.ReadInteger(IniSectionName, 'Height', 500);
  {датасет}
  CDS.FieldsDefs.AddField('ID'            , 'ID'                    , '>>', '<<', dtInteger  ,    0, '3'   ,  80, True);
  CDS.FieldsDefs.AddField('GR_POD'        , 'Группа / Подгруппа'    , '<<', '<<', dtString   ,  255, ''    , 100, True );
  CDS.FieldsDefs.AddField('POD'           , 'Подгруппа'             , '<<', '<<', dtString   ,  255, ''    , 100, True );
  CDS.FieldsDefs.AddField('IDAUTOR'       , 'IDAUTOR'               , '>>', '<<', dtInteger  ,    0, '3'   ,  80, False);
  CDS.FieldsDefs.AddField('AUTOR'         , 'Автор'                 , '<<', '<<', dtString   ,  100, ''    , 100, True );
  CDS.FieldsDefs.AddField('NAME'          , 'Наименование'          , '<<', '<<', dtString   ,  255, ''    , 100, True );
  CDS.FieldsDefs.AddField('CENA_OUT'      , 'Цена полка'            , '>>', '>>', dtCurrency ,    0, '%.*n', 100, True );
  CDS.FieldsDefs.AddField('MARKUP_CAT'    , 'Категория наценки'     , '>>', '<<', dtInteger  ,    0, ''    ,  80, False);
  CDS.FieldsDefs.AddField('CENA_DISC'     , 'Цена по скидкам заказа', '>>', '>>', dtCurrency ,    0, '%.*n', 100, True );
  CDS.FieldsDefs.AddField('OST_BASE'      , 'Склад'                 , '>>', '<<', dtInteger  ,    0, '#3'  ,  80, True );
  CDS.FieldsDefs.AddField('OST_BASE2'     , 'Склад 2'               , '>>', '<<', dtInteger  ,    0, '#3'  ,  80, True );
  CDS.FieldsDefs.AddField('OST_SHOP'      , 'Магазин'               , '>>', '<<', dtInteger  ,    0, '#3'  ,  80, True );
  CDS.FieldsDefs.AddField('KOL_IN'        , 'Приходы в магазине'    , '>>', '<<', dtInteger  ,    0, '#3'  ,  80, True );
  CDS.FieldsDefs.AddField('KOL'           , 'Продажи в магазине'    , '>>', '<<', dtInteger  ,    0, '#3'  ,  80, True );
  CDS.FieldsDefs.AddField('AM'            , 'Ассорт.минимум'        , '>>', '<<', dtInteger  ,    0, '#3'  ,  80, True );
  CDS.FieldsDefs.AddField('ORD_KOL'       , 'Заказ'                 , '>>', '<<', dtInteger  ,    0, '#3'  ,  80, True );
  CDS.FieldsDefs.AddField('ROW_FONTSTYLE' , 'ROW_FONTSTYLE'         , '<<', '<<', dtString   ,    3, ''    ,  30, False);
  CDS.FieldsDefs.AddField('ROW_COLOR'     , 'ROW_COLOR'             , '<<', '<<', dtString   ,   12, ''    ,  30, False);
  {}
  CDS.FieldsDefs.LoadColumnsWidth( Ini.ReadString(IniSectionName, 'CDS.Width', '') );
  CDV.FindDialog.FindText  := Ini.ReadString(IniSectionName, 'CDV.Ctrl+F'             , ''   );
  CDV.SaveToFilePath       := Ini.ReadString('Настройки'   , 'ПапкаРабочая'       , ''   );
  CDV.FontSize             := CFG.GridFontSize;
  //
end;
30 июл 18, 04:36    [21613030]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
Arioch
Member

Откуда:
Сообщений: 10006
fraks,

....а обращение к полям потом что-то типа CDS.Row[RowCount-5].GetFieldAsInteger('AM') ?
30 июл 18, 12:28    [21614122]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
Stalker4
Member

Откуда:
Сообщений: 236
Delphi 10.2.3

В главном модуле программы устанавливаю разделитель для даты и другие настройки FormatSettings:
initialization
 Application.UpdateFormatSettings := False;
 FormatSettings.TimeSeparator := ':';
 FormatSettings.ShortTimeFormat := 'hh'+FormatSettings.TimeSeparator+'mm';
 FormatSettings.DateSeparator := '.';
 FormatSettings.ShortDateFormat := 'dd'+FormatSettings.DateSeparator+'mm'+FormatSettings.DateSeparator+'yyyy';
 FormatSettings.DecimalSeparator := '.';
 FormatSettings.TwoDigitYearCenturyWindow := 50;

Далее в коде программы устанавливаю фильтр по полю типа TDateField
FDQuery.Filter := 'MYDATE = 01.01.2018';
FDQuery.Filtered := True;
и получаю ошибку:
'01.01.2018' is not a valid floating point value.

Если же дату в фильтре указать в виде
FDQuery.Filter := 'MYDATE = 01/01/2018'
то ошибки нет.

Так же нет ошибки, если дату заключить в дополнительные кавычки:
FDQuery.Filter := 'MYDATE = ''01/01/2018'''

Получается, что FireDAC не смотрит значение в FormatSettings.DateSeparator ?
Это ошибка FD или так и должно быть ?

Кстати говоря, в региональных настройках разделитель даты тоже точка, откуда FD берет наклонную не понятно.
30 июл 18, 12:54    [21614274]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
wadman
Member

Откуда: Санкт-Петербург
Сообщений: 24148
Stalker4
FDQuery.Filter := 'MYDATE = 01.01.2018';

Прямо так? Дата как строка и без кавычек?
30 июл 18, 12:59    [21614313]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
Arioch
Member

Откуда:
Сообщений: 10006
Stalker4
Так же нет ошибки, если дату заключить в дополнительные кавычки:
FDQuery.Filter := 'MYDATE = ''01/01/2018'''


внутри вторых кавычек - слэши или точки?
30 июл 18, 18:20    [21615940]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
fraks
Member

Откуда: Новосибирск
Сообщений: 1385
Arioch
....а обращение к полям потом что-то типа CDS.Row[RowCount-5].GetFieldAsInteger('AM') ?


ost_base   := CDS.ReadInt64FN(i, 'ost_base' ); // обращение по имени поля
ost_base   := CDS.ReadInt64(i, j ); // обращение по индексу поля

// для каждого из используемых типов данных сделано по 2 функции чтения и по 2 записи.
// поле любого типа можно прочитать как строку (ибо гриду именно это и требуется)
// при этом используется форматирование заявленное в объявлении поля


В сообщении 21613030 под спойлером был пример кода с чтением и записью.

Сделаны еще некоторые "служебные" имена полей. Такие поля несут специальные функции.
Например поле ROW_COLOR позволяет раскрасить цвет фона этой записи в гриде. Заполнить его можно как в запросе так и позже, уже в CDS.

ROW_FONTSTYLE - стиль шрифта B/I/U/S
ROW_NUM - порядковый номер строки
ROW_FOOTER dtInteger - при любой сортировке грида первым полем сортировки неявно задается это поле. Таким образом все записи у которых ROW_FOOTER > 0 всегда будут внизу, а у которых < 0 - вверху списка. Типа заголовок и подвал.
ну и т.д.
30 июл 18, 20:33    [21616160]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
Stalker4
Member

Откуда:
Сообщений: 236
wadman
Stalker4
FDQuery.Filter := 'MYDATE = 01.01.2018';

Прямо так? Дата как строка и без кавычек?
Да. Я переводил в своей программе код, который ранее использовал TMemTableEh (из EhLib) на TFDMemTable.
Так вот, TMemTableEh без проблем работал с таким фильтром. А вот с TFDMemTable возникли проблемы - пришлось дату заворачивать в дополнительные кавычки.

Arioch
Stalker4
Так же нет ошибки, если дату заключить в дополнительные кавычки:
FDQuery.Filter := 'MYDATE = ''01/01/2018'''

внутри вторых кавычек - слэши или точки?
Тут я ошибся, когда писал это сообщение, вот правильный вариант:
=============================
Если же дату в фильтре указать в виде
FDQuery.Filter := 'MYDATE = 01/01/2018'
то ошибки нет.

Так же нет ошибки, если дату заключить в дополнительные кавычки:
FDQuery.Filter := 'MYDATE = ''01.01.2018'''
=============================

То есть или меняем разделители с точки на слеши или заключаем дату в дополнительные кавычки.
2 авг 18, 10:19    [21623511]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
Dmitry Arefiev
Member

Откуда:
Сообщений: 9583
MYDATE = (01/01/2018)
MYDATE = 4,955401387512389e-4
2 авг 18, 10:49    [21623643]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
Arioch
Member

Откуда:
Сообщений: 10006
Дим, а в это можешь глянуть? тут что-то относительно низкоуровневое

Arioch
TFDTable edit fails with Firebird 2.5.7 not 2.5.3

https://stackoverflow.com/questions/51169547

Какая-то странная фигня. Там что, какие-то косяки были в FB 2.
2 авг 18, 13:39    [21624600]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
Stalker4
Member

Откуда:
Сообщений: 236
Dmitry Arefiev
MYDATE = (01/01/2018)
MYDATE = 4,955401387512389e-4

Честно говоря я не совсем понял Ваш ответ.
Разъясните его пожалуйста.

И хотелось бы более полный вариант ответа на 21614274, что бы понять такая работа с датой в фильтре это моя ошибка или FD или это его особенность.

И очень хотелось бы получить Ваши ответы на сообщения
21543276
21548055
21584268
3 авг 18, 09:40    [21627157]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
yashcher
Member

Откуда:
Сообщений: 1
Добрый день.

При попытке выполнить запрос
select * from pg_proc where proacl is not null

Выдается ошибка:
[FireDAC][Phys][PG][libpq] ОШИБКА: для типа aclitem нет функции вывода двоичных данных.

PostgreSQL 10.1
FireDAC = 13.0.1 (Build 82709)

Сам тип в недрах FIREDAC объявлен

Как можно преобразовать его хотя бы в БЛОБ?
13 авг 18, 17:00    [21640850]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
Stalker4
Member

Откуда:
Сообщений: 236
yashcher
При попытке выполнить запрос
select * from pg_proc where proacl is not null
Как можно преобразовать его хотя бы в БЛОБ?

Ну на уровне БД его можно попробовать преобразовать через cast,
например так:
cast(myfield as long varchar) или cast(myfield as long binary)
15 авг 18, 16:24    [21643368]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
green_2005
Member

Откуда:
Сообщений: 12
Добрый день.
При попытке выполнить запрос вида
select * from dbo.[имя_таблицы]

компонент fdQuery выдает ошибку "Invalid object name dbo."
Имя таблицы задано кириллицей, от этого никак не уйти.
В MS Studio и в AdoQuery этот запрос отрабатывает.
Добавление параметра CharacterSet=WIN1251 в FDConnection не помогает.
Как эту проблему можно победить?
27 авг 18, 12:13    [21654792]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
Dmitry Arefiev
Member

Откуда:
Сообщений: 9583
green_2005,

1) Приведи стэк вызова для исключения.
2) Какая версия RAD Studio ?
3) Исключение fiMeta из FetchOptions.Items помагает ?
27 авг 18, 12:48    [21654867]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
green_2005
Member

Откуда:
Сообщений: 12
Dmitry Arefiev,

1. во вложении
2. нет, не помогает
3. Delphi 10.2 update 2

К сообщению приложен файл (bugreport.txt - 5Kb) cкачать
27 авг 18, 13:15    [21654922]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
Dmitry Arefiev
Member

Откуда:
Сообщений: 9583
Ok ...
4) Приведи буквальный текст запроса.
5) Приведи DDL таблицы в запросе.
27 авг 18, 13:19    [21654929]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
green_2005
Member

Откуда:
Сообщений: 12
Dmitry Arefiev,

4) select * from [dbo].[!Договор]
5) Во вложении
27 авг 18, 14:27    [21655027]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
green_2005
Member

Откуда:
Сообщений: 12
green_2005,
сорри, не прикрепилось

/****** Object:  Table [dbo].[!Договор]    Script Date: 08/27/2018 14:17:53 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

SET ANSI_PADDING ON
GO

CREATE TABLE [dbo].[!Договор](
	[idVersion] [int] NOT NULL,
	[idMain] [int] NULL,
	[stNumber] [varchar](255) NULL,
	[inidType] [int] NULL,
	[idState] [int] NULL,
	[product] [varchar](255) NULL,
	[!Дата выполнения] [datetime] NULL,
	[!Должность] [varchar](255) NULL
	[!Номер ИГК] [varchar](255) NULL,
 CONSTRAINT [!Договор_idx] PRIMARY KEY CLUSTERED 
(
	[idVersion] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO
27 авг 18, 14:30    [21655030]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
Dmitry Arefiev
Member

Откуда:
Сообщений: 9583
http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Preprocessing_Command_Text_(FireDAC)#Special_Character_Processing
27 авг 18, 15:12    [21655086]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
green_2005
Member

Откуда:
Сообщений: 12
Dmitry Arefiev,
спасибо!
27 авг 18, 15:29    [21655111]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
green_2005
Member

Откуда:
Сообщений: 12
Dmitry Arefiev,

не работает аутентификация для пользователя sql server с паролем, содержащим символ '{'.
Пишет 'Login failed for user "UserName"'.
Свойства ResourceOptions.MacroCreate, MacroExpand и EscapeExpand установлены в False, не помогает.
27 авг 18, 18:47    [21655321]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
Dmitry Arefiev
Member

Откуда:
Сообщений: 9583
Не помню точно, вроде бы это ограничение SQL Server ODBC драйвера
27 авг 18, 19:06    [21655346]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
cptngrb
Member

Откуда:
Сообщений: 163
Дмитрий, посмотрите пожалуйста [url=]http://www.sql.ru/forum/1291095/reconnect-firedac-oracle [/url]
3 сен 18, 09:40    [21662274]     Ответить | Цитировать Сообщить модератору
 Re: FireDAC  [new]
Stalker4
Member

Откуда:
Сообщений: 236
Dmitry Arefiev,

Возможно нашел ошибку в FireDAC из Delphi 10.2.3 (25.0.31059.3231) связанную с контролем AutoReconnect через события OnRecover и OnRestored.

См. демку в атаче.
Для нее надо установить сервер Sybase SQL AnyWhere (сейчас он называются SAP SQL AnyWhere), базу можно взять любую, только надо будет настроить доступ к ней для FDConnection1.
Тест делал на локальном соединении с сервером.

Итак есть связка FDConnection1+FDPhysASADriverLink+FDQuery.
Свойство AutoReconnect установлено в True.

1) Делаем тест на AutoReconnect БЕЗ использования обработчиков событий OnRecover и OnRestored (в демке их надо отключить).
Соединяемся с базой (в демке жмем кнопку Connect) и открываем запрос (в демке жмем кнопку Test).
Дальше принудительно останавливаем сервер и переносим базу в какое нибудь другое место.
Опять жмем кнопку Test.
FD делает три попытки восстановить соединение с БД и после этого успокаивается с криком что БД не найдена.
Тут все нормально как и ожидалось.

2) Делаем тест на AutoReconnect С использования обработчиков событий OnRecover и OnRestored

Сами обработчики очень простые и смысл их в том, что бы FD в случае потери связи с БД, делал не три попытки восстановления связи, а одну.
procedure TForm4.FDConnection1Recover(ASender, AInitiator: TObject; AException: Exception; var AAction: TFDPhysConnectionRecoverAction);
begin
 if FDConnection1.Tag > 0 then
   aAction := faFail
 else begin
   FDConnection1.Tag := 1;
   aAction := faRetry;
 end;
end;

procedure TForm4.FDConnection1Restored(Sender: TObject);
begin
 FDConnection1.Tag := 0;
end;

Соединяемся с базой (в демке жмем кнопку Connect) и открываем запрос (в демке жмем кнопку Test).
Дальше принудительно останавливаем сервер и переносим базу в какое нибудь другое место.
Опять жмем кнопку Test.
Сначала FD скажет, что соединение потеряно и попадет на код "aAction := faRetry". Потом он скажет что БД не найдена и попадет на код "aAction := faFail".
А после этого произойдет AV в процедуре
TFDPhysASAConnection.InternalDisconnect
на строке
if ODBCConnection.Connected and (FDVerStr2Int(ODBCConnection.DRIVER_VER) >= cvSybaseASA9) then

AV тут происходит потому, что ODBCConnection почему то становиться равным nil.

В атаче так же приведен CallStack этой ошибки.

В общем надо исправление этой ошибки.

К сообщению приложен файл (fd_autoreconnect_error.rar - 2Kb) cкачать
6 сен 18, 10:47    [21666633]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: Ctrl  назад   1 .. 31 32 33 34 35 36 37 38 [39] 40   вперед  Ctrl
Все форумы / Delphi Ответить