Topic: Вычисляемое поле в SQL запросе
У меня не получается добавить вычисляемое поле в SQL запрос, при этом через поиск все работает
Может кто сможет помочь?
My Visual Database → Russian → Вычисляемое поле в SQL запросе
У меня не получается добавить вычисляемое поле в SQL запрос, при этом через поиск все работает
Может кто сможет помочь?
А проблемный пример никто не полюбляет приложить... Ни новички, ни старички...
Если правильно понял вопрос - задача на "зацикливание"...
А проблемный пример никто не полюбляет приложить... Ни новички, ни старички...
Если правильно понял вопрос - задача на "зацикливание"...
Сори, собрал
Таблица books поле writerList
кнопка SQL запроса frmMain.bSearchSQLWriter
действие происходит при выборе записи в таблице frmMain.tgWriter на вкладке (автор)
сам проект тут https://drive.google.com/file/d/1zWJfVT … sp=sharing
Ладно, я понял, что это не возможно, хрен с ним, я уже придумал как решить эту проблему
хрен с ним, я уже придумал как решить эту проблему
Ок.
Берем и вставляем вычилсяемое поле (не имя)
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}
Берем и вставляем вычисляемое поле (не имя)
Интересно, именно к этому решению я и прешёл. До меня дошло, что при обычном поиске программа не читает само поле (вычитаемое поле), так как его нет, а просто добавляет его код в сам запрос.
Но все равно всем СПАСИБО!
Захотелось мне, братцы, блеснуть кодом, написал функцию 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;
Захотелось мне, братцы, блеснуть кодом, написал функцию InlineCalcFields(), которая автоматически подставляет вычисляемое поле в SQL, но... получились костыли... впрочем, судите сами, может, кому понравится:
По любому пригодится
... написал функцию InlineCalcFields(), которая автоматически подставляет вычисляемое поле в SQL, но... получились костыли... впрочем, судите сами, может, кому понравится:
Константин как вариант пример имеет право на жизнь но не хватает одной вещи, обработки "=" (^equally^)
k245 wrote:... написал функцию InlineCalcFields(), которая автоматически подставляет вычисляемое поле в SQL, но... получились костыли... впрочем, судите сами, может, кому понравится:
Константин как вариант пример имеет право на жизнь но не хватает одной вещи, обработки "=" (^equally^)
Прошу уточнить, о какой обработке идет речь?
Так выглядит вычисляемое поле в файле tables.ini где есть знак "="
%data_calc=(SELECT data || 'Бумс!' FROM test t WHERE t.id ^equally^ test.id )\r\n
как можно заметить "=" меняется на ^equally^. Кому будет нужно добавит себе обработку.
Действительно.... тогда добавляем одну строчку в 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
Тут еще один "костыль" образовался.
По мотивам костыля Константина.
(...вся эта ваша «технология», все эти домны, колеса и прочая маета-суета — чтобы меньше работать и больше жрать.
Все это — костыли и протезы. "Сталкер")
Избавляемся от костылей!
У меня есть две новости: одна - плохая, другая - хорошая.
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.
1. Метод TIniFile.ReadSectionValues не работает
должен работать, тут я применял его
https://myvisualdatabase.com/forum/view … hp?id=7125
k245 wrote:1. Метод TIniFile.ReadSectionValues не работает
должен работать, тут я применял его
https://myvisualdatabase.com/forum/view … hp?id=7125
Проверил ещё раз, действительно работает! Значит, это у меня в коде какой-то баг был, и остаётся только одна новость - хорошая, про TMemIniFile )))
pavlenko.vladimir.v wrote:k245 wrote:1. Метод TIniFile.ReadSectionValues не работает
должен работать, тут я применял его
https://myvisualdatabase.com/forum/view … hp?id=7125Проверил ещё раз, действительно работает! Значит, это у меня в коде какой-то баг был, и остаётся только одна новость - хорошая, про TMemIniFile )))
я помню при чтении ini возникала ошибка из-за строки? Вроде как первую строку не читает
я помню при чтении ini возникала ошибка из-за строки? Вроде как первую строку не читает
TIniFile - не читает, потому как он работает с кодировкой ANSI
TMemIniFile - читает, потому как он работает с кодировкой UTF-8
А разве в проге нет преобразования utf8<>win1251?
А разве в проге нет преобразования utf8<>win1251?
Как отдельной функции - нет.
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
My Visual Database → Russian → Вычисляемое поле в SQL запросе
Powered by PunBB, supported by Informer Technologies, Inc.
Theme Hydrogen by Kushi