Topic: Вычисляемое поле в SQL запросе

У меня не получается добавить вычисляемое поле в SQL запрос, при этом через поиск все работает
Может кто сможет помочь?

2 (edited by vovka3003 2023-09-25 17:05:15)

Re: Вычисляемое поле в SQL запросе

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

3 (edited by pavlenko.vladimir.v 2023-09-25 17:29:52)

Re: Вычисляемое поле в SQL запросе

vovka3003 wrote:

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

Сори, собрал
Таблица books поле writerList
кнопка SQL запроса frmMain.bSearchSQLWriter
действие происходит при выборе записи в таблице frmMain.tgWriter на вкладке (автор)
сам проект тут  https://drive.google.com/file/d/1zWJfVT … sp=sharing

Re: Вычисляемое поле в SQL запросе

Ладно, я понял, что это не возможно, хрен с ним, я уже придумал как решить эту проблему

Re: Вычисляемое поле в SQL запросе

pavlenko.vladimir.v wrote:

хрен с ним, я уже придумал как решить эту проблему

Ок.

Re: Вычисляемое поле в SQL запросе

Берем и вставляем вычилсяемое поле (не имя)

SELECT
img,           
nameBook, 
(SELECT group_concat(writer.nameWriter,",") 
From writer LEFT OUTER JOIN unionWriterToBooks ON writer.id=unionWriterToBooks.id_writer 
WHERE unionWriterToBooks.id_books=books.id) ,
allGenres,    
allSeries,
allPublishers, 
books.id
FROM books LEFT OUTER JOIN unionWriterToBooks ON books.id=unionWriterToBooks.id_books 
WHERE unionWriterToBooks.id_writer={tgWriter} 

7 (edited by pavlenko.vladimir.v 2023-09-26 05:47:03)

Re: Вычисляемое поле в SQL запросе

sparrow wrote:

Берем и вставляем вычисляемое поле (не имя)

Интересно, именно к этому решению я и прешёл. До меня дошло, что при обычном поиске программа не читает само поле (вычитаемое поле), так как его нет, а просто добавляет его код в сам запрос.

Но все равно всем СПАСИБО!

8 (edited by k245 2023-09-26 08:54:10)

Re: Вычисляемое поле в SQL запросе

Захотелось мне, братцы, блеснуть кодом, написал функцию InlineCalcFields(), которая автоматически подставляет вычисляемое поле в SQL, но... получились костыли... впрочем, судите сами, может, кому понравится:

procedure Form1_Button1_OnClick (Sender: TObject; var Cancel: boolean);
var
  tmpSQL: string;
begin
  tmpSQL :=
    'Select '+
    '  data, '+
    '  {test.data_calc} '+ // надо указывать таблицу и вычисляемоте поле
    'from '+
    '  test ';
  tmpSQL := InlineCalcFields(tmpSQL);
  TdbButton(Sender).dbSQL := tmpSQL;
end;

function InlineCalcFields( ASQL:string ):string;
var
  tmpStartPos: integer;
  tmpEndPos: integer;
  tmpDotPos: integer;
  tmpCalcField: string;
  tmpFieldSQL: string;
  tmpTableName: string;
  tmpPlaceHolder: string;
  tmpIniFile: TIniFile;
  tmpFileName: string;
  tmpFileName2: string;
  tmpList:TStringList;
  tmpList2:TStringList;
  s: string;
begin
  // сюрприз! файл tables.ini записан в кодировке UTF-8, с которорй TIniFile работает некорретно - пропускает первый раздел.
  // есть два варианта: преобразовать tables.ini в ANSI или не использовать стандартный TIniFile, а писать свой
  // --- преобразовать файл (вынести этот костыль за пределы функции, чтобы вызывать только один раз...)
  tmpFileName := ExtractFilePath(Application.ExeName)+'tables.ini';
  tmpFileName2 := ExtractFilePath(Application.ExeName)+'tables.dat';
  tmpList := TStringList.Create;
  tmpList2 := TStringList.Create;
  tmpList.LoadFromFile(tmpFileName);
  s := tmpList.Text;
  tmpList2.Text := Trim(s);
  tmpList2.SaveToFileANSI(tmpFileName2);
  tmpList.Free;
  tmpList2.Free;
  ////////////////////////////////////////////////////////////////////////////////////
  tmpIniFile := TIniFile.Create( tmpFileName2 );
  try
    repeat
      tmpStartPos := Pos( '{',ASQL);
      if tmpStartPos = 0 then
        exit;
      tmpEndPos := Pos('}',ASQL);
      if tmpEndPos = 0 then
        exit;
      // таблица.поле
      tmpCalcField := copy(ASQL,tmpStartPos+1,tmpEndPos-tmpStartPos-1);
      tmpDotPos := Pos( '.',tmpCalcField);
      if tmpDotPos = 0 then
        exit;
      tmpTableName := copy(tmpCalcField,1,tmpDotPos-1);
      delete(tmpCalcField,1,tmpDotPos);
      tmpFieldSQL := tmpIniFile.ReadString(tmpTableName,'%'+tmpCalcField,'');
      tmpFieldSQL := ReplaceStr( tmpFieldSQL, '\r' ,'');
      tmpFieldSQL := ReplaceStr( tmpFieldSQL, '\n' ,'');
      tmpPlaceHolder := '{'+tmpTableName+'.'+tmpCalcField+'}';
      ASQL := ReplaceStr( ASQL, tmpPlaceHolder ,tmpFieldSQL  );
    until 1=0;
  finally
    tmpIniFile.Free;
    Result := ASQL;
  end;
end;
Post's attachments

Attachment icon 321.rar 295.56 kb, 66 downloads since 2023-09-26 

Визуальное программирование: блог и телеграм-канал.

Re: Вычисляемое поле в SQL запросе

k245 wrote:

Захотелось мне, братцы, блеснуть кодом, написал функцию InlineCalcFields(), которая автоматически подставляет вычисляемое поле в SQL, но... получились костыли... впрочем, судите сами, может, кому понравится:

По любому пригодится

10 (edited by sparrow 2023-10-10 13:44:21)

Re: Вычисляемое поле в SQL запросе

k245 wrote:

... написал функцию InlineCalcFields(), которая автоматически подставляет вычисляемое поле в SQL, но... получились костыли... впрочем, судите сами, может, кому понравится:

Константин как вариант пример имеет право на жизнь но не хватает одной вещи, обработки "=" (^equally^)

Re: Вычисляемое поле в SQL запросе

sparrow wrote:
k245 wrote:

... написал функцию InlineCalcFields(), которая автоматически подставляет вычисляемое поле в SQL, но... получились костыли... впрочем, судите сами, может, кому понравится:

Константин как вариант пример имеет право на жизнь но не хватает одной вещи, обработки "=" (^equally^)

Прошу уточнить, о какой обработке идет речь?

Визуальное программирование: блог и телеграм-канал.

12 (edited by sparrow 2023-10-10 14:50:45)

Re: Вычисляемое поле в SQL запросе

Так выглядит вычисляемое поле в файле tables.ini где есть знак "="

%data_calc=(SELECT data || 'Бумс!' FROM test t WHERE t.id ^equally^ test.id )\r\n

как можно заметить "=" меняется на ^equally^. Кому будет нужно добавит себе обработку.

13 (edited by k245 2023-10-11 06:22:01)

Re: Вычисляемое поле в SQL запросе

Действительно.... тогда добавляем одну строчку в InlineCalcFields()


procedure Form1_Button1_OnClick (Sender: TObject; var Cancel: boolean);
var
  tmpSQL: string;
begin
  tmpSQL :=
    'Select '+
    '  data, '+
    '  {test.data_calc} '+ // надо указывать таблицу и вычисляемое поле
    'from '+
    '  test ';
  tmpSQL := InlineCalcFields(tmpSQL);
  TdbButton(Sender).dbSQL := tmpSQL;
end;

function InlineCalcFields( ASQL:string ):string;
var
  tmpStartPos: integer;
  tmpEndPos: integer;
  tmpDotPos: integer;
  tmpCalcField: string;
  tmpFieldSQL: string;
  tmpTableName: string;
  tmpPlaceHolder: string;
  tmpIniFile: TIniFile;
  tmpFileName: string;
  tmpFileName2: string;
  tmpList:TStringList;
  tmpList2:TStringList;
  s: string;
begin
  // сюрприз! файл tables.ini записан в кодировке UTF-8, с которой TIniFile работает некорректно - пропускает первый раздел.
  // есть два варианта: преобразовать tables.ini в ANSI или не использовать стандартный TIniFile, а писать свой
  // --- преобразовать файл (вынести этот костыль за пределы функции, чтобы вызывать только один раз...)
  tmpFileName := ExtractFilePath(Application.ExeName)+'tables.ini';
  tmpFileName2 := ExtractFilePath(Application.ExeName)+'tables.dat';
  tmpList := TStringList.Create;
  tmpList2 := TStringList.Create;
  tmpList.LoadFromFile(tmpFileName);
  s := tmpList.Text;
  tmpList2.Text := Trim(s);
  tmpList2.SaveToFileANSI(tmpFileName2);
  tmpList.Free;
  tmpList2.Free;
  ////////////////////////////////////////////////////////////////////////////////////
  tmpIniFile := TIniFile.Create( tmpFileName2 );
  try
    repeat
      tmpStartPos := Pos( '{',ASQL);
      if tmpStartPos = 0 then
        exit;
      tmpEndPos := Pos('}',ASQL);
      if tmpEndPos = 0 then
        exit;
      // таблица.поля
      tmpCalcField := copy(ASQL,tmpStartPos+1,tmpEndPos-tmpStartPos-1);
      tmpDotPos := Pos( '.',tmpCalcField);
      if tmpDotPos = 0 then
        exit;
      tmpTableName := copy(tmpCalcField,1,tmpDotPos-1);
      delete(tmpCalcField,1,tmpDotPos);
      tmpFieldSQL := tmpIniFile.ReadString(tmpTableName,'%'+tmpCalcField,'');
      tmpFieldSQL := ReplaceStr( tmpFieldSQL, '\r' ,'');
      tmpFieldSQL := ReplaceStr( tmpFieldSQL, '\n' ,'');
      tmpFieldSQL := ReplaceStr( tmpFieldSQL, '^equally^' ,'=');
      tmpPlaceHolder := '{'+tmpTableName+'.'+tmpCalcField+'}';
      ASQL := ReplaceStr( ASQL, tmpPlaceHolder ,tmpFieldSQL  );
    until 1=0;
  finally
    tmpIniFile.Free;
    Result := ASQL;
  end;
end;

sparrow, благодарю, вы как всегда очень внимательны и зорко следите за правильностью кода, словно eagle  smile

Визуальное программирование: блог и телеграм-канал.

Re: Вычисляемое поле в SQL запросе

Тут еще один "костыль" образовался.
По мотивам костыля Константина.


(...вся эта ваша «технология», все эти домны, колеса и прочая маета-суета — чтобы меньше работать и больше жрать.
Все это — костыли и протезы.  "Сталкер")

Post's attachments

Attachment icon 321-s.zip 330.15 kb, 56 downloads since 2023-10-12 

15 (edited by k245 2023-10-15 09:40:05)

Re: Вычисляемое поле в SQL запросе

Избавляемся от костылей!

У меня есть две новости: одна - плохая, другая - хорошая.


1. Метод TIniFile.ReadSectionValues не работает
2. В MVDB есть класс TMemIniFile, который работает с ini-фалом в кодировке UTF-8.


Продолжая идею sparrow о необходимости разовой загрузки формул вычисляемых полей, доделал InlineCalcFields(), костыли отнес в больничку )))


var
  DB_CalcFields: TStringList;  // список хранимых полей из файла tables.ini


procedure Form1_Button1_OnClick (Sender: TObject; var Cancel: boolean);
var
  tmpSQL: string;
begin
  tmpSQL :=
    'Select '+
    ' "$checkbox",'+
    ' "$autoinc",'+
    '  data, '+
    '  {test.data_calc} '+ // надо указывать таблицу и вычисляемоте поле
    'from '+
    '  test ';
  tmpSQL := InlineCalcFields(tmpSQL);
  TdbButton(Sender).dbSQL := tmpSQL;
end;

function InlineCalcFields( ASQL:string ):string;
var
  tmpStartPos: integer;
  tmpEndPos: integer;
  tmpCalcField: string;
  tmpFieldSQL: string;
  tmpPlaceHolder: string;
begin
  try
    repeat
      tmpStartPos := Pos( '{',ASQL);
      if tmpStartPos = 0 then
        exit;
      tmpEndPos := Pos('}',ASQL);
      if tmpEndPos = 0 then
        exit;
      //
      tmpCalcField := copy(ASQL,tmpStartPos+1,tmpEndPos-tmpStartPos-1);
      if DB_CalcFields.IndexOfName(tmpCalcField) < 0 then
      begin
        ShowMessage('Вычисляемое поле '+tmpCalcField+' не найдено!');
        exit;
      end;
      tmpFieldSQL := DB_CalcFields.Values(tmpCalcField);
      tmpFieldSQL := ReplaceStr( tmpFieldSQL, '\r' ,'');
      tmpFieldSQL := ReplaceStr( tmpFieldSQL, '\n' ,'');
      tmpFieldSQL := ReplaceStr( tmpFieldSQL, '^equally^' ,'=');
      tmpPlaceHolder := '{'+tmpCalcField+'}';
      ASQL := ReplaceStr( ASQL, tmpPlaceHolder ,tmpFieldSQL  );
    until 1=0;
  finally
    Result := ASQL;
  end;
end;

procedure ReadCalcFields;
// заполняем список вычисляемых полей DB_CalcFields
var
  tmpIniFile: TMemIniFile;
  tmpList:TStringList;
  tmpList2:TStringList;
  s: string;
  i: integer;
  j: integer;
  tmpTableName: string;
  tmpFieldName: string;
begin
  DB_CalcFields := TStringList.Create;
  tmpList := TStringList.Create;
  tmpList2 := TStringList.Create;
  tmpIniFile := TMemIniFile.Create(ExtractFilePath(Application.ExeName)+'tables.ini');
  try
    tmpIniFile.ReadSections(tmpList);
    for i:=0 to tmpList.Count - 1 do
    begin
      tmpTableName := tmpList.Strings[i];
      tmpIniFile.ReadSectionValues( tmpTableName, tmpList2 );
      for j := 0 to tmpList2.Count - 1 do
      begin
        tmpFieldName := tmpList2.Names[j];
        if copy(tmpFieldName,1,1) = '%' then
        begin
          DB_CalcFields.Add( tmpTableName+'.'+copy( tmpList2.Strings[j],2,Length(tmpList2.Strings[j])-1 ) );
        end
      end;
    end;
  finally
    tmpIniFile.Free;
    tmpList.Free;
    tmpList2.Free;
  end;
end;

begin
  ReadCalcFields;
end.
Post's attachments

Attachment icon 321.rar 296.21 kb, 68 downloads since 2023-10-15 

Визуальное программирование: блог и телеграм-канал.

Re: Вычисляемое поле в SQL запросе

k245 wrote:

1. Метод TIniFile.ReadSectionValues не работает

должен работать, тут я применял его
https://myvisualdatabase.com/forum/view … hp?id=7125

Re: Вычисляемое поле в SQL запросе

pavlenko.vladimir.v wrote:
k245 wrote:

1. Метод TIniFile.ReadSectionValues не работает

должен работать, тут я применял его
https://myvisualdatabase.com/forum/view … hp?id=7125

Проверил ещё раз, действительно работает!  Значит, это у меня в коде какой-то баг был, и остаётся только одна новость -  хорошая, про TMemIniFile )))

Визуальное программирование: блог и телеграм-канал.

Re: Вычисляемое поле в SQL запросе

k245 wrote:
pavlenko.vladimir.v wrote:
k245 wrote:

1. Метод TIniFile.ReadSectionValues не работает

должен работать, тут я применял его
https://myvisualdatabase.com/forum/view … hp?id=7125

Проверил ещё раз, действительно работает!  Значит, это у меня в коде какой-то баг был, и остаётся только одна новость -  хорошая, про TMemIniFile )))

я помню при чтении ini возникала ошибка из-за строки? Вроде как первую строку не читает

Re: Вычисляемое поле в SQL запросе

pavlenko.vladimir.v wrote:

я помню при чтении ini возникала ошибка из-за строки? Вроде как первую строку не читает

TIniFile - не читает, потому как он работает с кодировкой ANSI
TMemIniFile - читает, потому как он работает с кодировкой UTF-8

Визуальное программирование: блог и телеграм-канал.

Re: Вычисляемое поле в SQL запросе

А разве в проге нет преобразования utf8<>win1251?

Re: Вычисляемое поле в SQL запросе

vovka3003 wrote:

А разве в проге нет преобразования utf8<>win1251?

Как отдельной функции - нет.

Визуальное программирование: блог и телеграм-канал.

Re: Вычисляемое поле в SQL запросе

function Utf8ToWinCP(s:string):string;
var sc:variant;
begin
  sc:=CreateOleObject('ScriptControl');
  sc.Language := 'JavaScript';
  sc.reset;
  sc.AddCode(
    'function Utf8ToWinCP(s){'+
    'var stream = new ActiveXObject("ADODB.Stream");'+
    'stream.mode = 3;'+
    'stream.type = 2;'+
    'stream.charset = "UTF-8";'+
    'stream.open();'+
    'stream.writeText(s);'+
    'stream.position = 0;'+
    'stream.charset = "Windows-1251";'+
    'return stream.readText();'+
    'stream.close();'+
    '}'
  );
  result := sc.Run('Utf8ToWinCP',s);
  sc:=0;
end;


function WinCPToUtf8(s:string):string;
var sc:variant;
begin
  sc:=CreateOleObject('ScriptControl');
  sc.Language := 'JavaScript';
  sc.reset;
  sc.AddCode(
    'function WinCPToUtf8(s){'+
    'var stream = new ActiveXObject("ADODB.Stream");'+
    'stream.mode = 3;'+
    'stream.type = 2;'+
    'stream.charset = "Windows-1251";'+
    'stream.open();'+
    'stream.writeText(s);'+
    'stream.position = 0;'+
    'stream.charset = "UTF-8";'+
    'return stream.readText();'+
    'stream.close();'+
    '}'
  );
  result := sc.Run('WinCPToUtf8',s);
  sc:=0;
end;

var s:string;
//...
  s := Utf8ToWinCP('Привет'); 

  ShowMessage(s); // Привет
  ShowMessage(length(s)); // 15

  s := WinCPToUtf8(s);

  ShowMessage(s); // Привет
  ShowMessage(length(s)); // 6