Syntax error in SQL SELECT INTO FROM from Delphi - mysql

I am trying to insert a new record into my database using SQL, but it keeps telling me that I have a syntax error in the from clause.
I don't see the error.
Here is the code:
procedure TForm1.BitBtn7Click(Sender: TObject);
var
sCategoryName :string;
begin
sCategoryName := InputBox('Category Name', 'Please enter your category name that you would like to add','');
with dmRecords do
begin
qryRecords.Active := False;
qryRecords.SQL.Add('INSERT INTO [Category of Income]([Category Name])');
qryRecords.SQL.Add('VALUES ' + '(' + QuotedStr(sCategoryName) + ')');
qryRecords.ExecSQL;
qryRecords.SQL.Add('SELECT * FROM [Category of Income] ORDER BY [Category ID]');
qryRecords.Active := True;
end;
end;

You haven't cleared the SQL from the previous statement. When you open the query, SQL has three lines of text.
Add qryRecords.SQL.Clear before adding the SELECT statement.

Related

FireDAC, Array DML, SQL Server, and IDENTITY_INSERT

I'm trying to export data to SQL Server using Firedac Array DML feature. In the destination table, there is a IDENTITY column, and I need to put an explicit value to it.
But my query fails with the following error message:
SQL state: 23000. Native code: 544. Message: [Microsoft][SQL Server
Native Client 11.0][SQL Server]Cannot insert explicit value for
identity column in table 'dic_cities' when IDENTITY_INSERT is set to
OFF.
The destination table is defined as follows:
CREATE TABLE dbo.dic_cities (
id int IDENTITY(1,1) PRIMARY KEY,
city_name varchar(50) NOT NULL
)
My code:
MyFDQuery.Connection.ExecSQL('SET IDENTITY_INSERT dbo.dic_cities ON');
MyFDQuery.SQL.Text := 'INSERT INTO dbo.dic_cities (id, city_name) VALUES (:id, :city_name)';
//Populating parameters and preparing the query
{...}
//Execute Array DML query with batch size of 100
MyFDQuery.Execute(100, 0);
//Finally, set IDENTITY_INSERT off for the destination table
MyFDQuery.Connection.ExecSQL('SET IDENTITY_INSERT dbo.dic_cities OFF');
I must to note, that everything works well when I use a regular TFDQuery with parameters (i.e. when not using Array DML feature). But it fails for Array DML.
I also used Array DML for several other DBMS for years in a way like the code above, with success.
So, how to use the Array DML feature to insert explicit values to SQL Server IDENTITY column?
Update#2: See https://social.msdn.microsoft.com/Forums/sqlserver/en-US/e652377d-0607-45ca-b4a0-274361bff85a/how-to-set-identityinsert-in-dynamic-sql?forum=transactsql
I haven't fully digested it yet, but the OP's problem seems very similar.
I've tried constructing the SQL to use EXEC
FDQuery1.SQL.Text := 'EXEC (' + ''''+ sSetIIOn + ';' + sInsert + ';' + sSetIIOff + '''' + ')';
to avoid sp_executesql being used, but unfortunately FD then cannot parse the SQL properly so it produces an "argument out of range" error when setting up the parameters.
Update: Curiouser and curiouser...
The following code executes without error on SS2014 and inserts the expected 10 rows:
const
sEmptyTable = 'delete from dbo.identtest';
sSetIIOn = 'set identity_insert dbo.identtest ON';
sSetIIOff = 'set identity_insert dbo.identtest OFF';
sSelect = 'select * from dbo.identtest';
sInsert = 'insert dbo.identtest (ID, Name) values(%d, %s)';
procedure TForm2.TestIdentityInsert;
var
i : Integer;
S : String;
begin
FDQuery1.ExecSql(sEmptyTable);
FDQuery1.ExecSql(sSetIIOn);
for i := 1 to 10 do begin
S := Format(sInsert, [i, '''Name' + IntToStr(i) + '''']);
FDQuery1.ExecSQL(S);
end;
FDQuery1.ExecSql(sSetIIOff);
FDQuery1.Sql.Text := sSelect;
FDQuery1.Open;
end;
procedure TForm2.Button1Click(Sender: TObject);
begin
TestIdentityInsert;
end;
However, replacing the for loop by
FDQuery1.SQL.Text := sSetIIOn + ';' + sInsert + ';' + sSetIIOff;
FDQuery1.Params.ArraySize := Rows;
for i := 0 to Rows - 1 do begin
FDQuery1.Params[0].AsIntegers[i] := i;
FDQuery1.Params[1].AsStrings[i] := 'Name' + IntToStr(i);
end;
produces the exception you quote. I've verified using SSMS Profiler that the SQL sent to the server seems to be correct (and not f.i. being mangled by the MDac layer as sometimes happens):
exec sp_executesql N'set identity_insert dbo.identtest ON;insert dbo.identtest values(#P1, #P2);set identity_insert dbo.identtest OFF',N'#P1 int,#P2 nvarchar(4000)',0,N'Name0' [etc, repeated 9 times]
so the question seems to be why doesn't using sp_executesql respect the Identity_Insert setting and is there another way that does?

store function creation error in mysql #1064

I tried to create one function, ie if username exist, will return random number and character as a single string, but I tried below code, throwing syntax error like below, can u help to find the issue, I know that having issue in declaring string and returning string, but unable to find the issue. Thanks to the replies in advance
DELIMITER //
create function verifyEmail(userName varchar(25))
RETURNS TEXT
BEGIN
if EXISTS(select * from userdetails where name = userName)
then
SELECT #randomPass := select concat( char(round(rand()*36)+1), char(round(rand()*36)+1), char(round(rand()*36)+1));
return #randomPass;
else
return "not_exist";
end if;
end //
DELIMITER //
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'select concat( char(round(rand()*36)+1), char(round(rand()*36)+1), char(round(ra' at line 6
You are missing a closing ) on this line:
SELECT #randomPass := select concat( char(round(rand()*36)+1), char(round(rand()*36)+1), char(round(rand()*36)+1);
should be
SELECT #randomPass := select concat( char(round(rand()*36)+1), char(round(rand()*36)+1), char(round(rand()*36)+1));
Hooray, finally found answers.. This below code will help to solve the solution
DELIMITER //
create function verifyEmail(userName varchar(25))
RETURNS TEXT
BEGIN
DECLARE randomPass VARCHAR(8);
if EXISTS(select id from userdetails where name = userName)
THEN
SET randomPass = concat( char(rand()*25+65),char(rand()*25+65),char(rand()*25+65),char(rand()*25+65),char(rand()*25+65),char(rand()*25+65),char(rand()*25+65),char(rand()*25+65));
return randomPass;
else
return "not_exist";
end if;
end //
DELIMITER //

Receiving data from an SQL table in Delphi

I have a form which needs to fetch and display data from a MYSQL database.
The SQL code which I have written works fine, as I have tried to execute it within MYSQL.
I have also used a similar format of code to the one in my form, within another form, to fetch and display SQL data. The code works perfectly in the other form.
However, my code for this form does not seem to be receiving/displaying the data from the SQL table.
Here's a snippet of the code written for the OnShow event of the form.
procedure TfrmEditBooking.FormShow(Sender: TObject);
var
CustName: string;
begin
if SelectedID > 0 then
begin
with frmBookingData.ADOQuery1 do
begin
Open;
SQL.Clear;
SQL.Add('SELECT Name, Surname ' +
'FROM customers_main ' +
'WHERE customers_main.idcustomers_main ' +
'IN ' +
'(SELECT bookings_main.customers_main_idcustomers_main ' +
'FROM bookings_main ' +
'WHERE bookings_main.idbookings_main = ' + IntToStr(SelectedID) + ')');
ExecSQL;
CustName := FieldByName('Surname').AsString + ' ' + FieldByName('Name').AsString;
Label1.Caption := CustName;
Close;
end;
end;
end;
One uses 'execsql' when one is not expecting to receive a cursor into a dataset (in other words, use 'execsql' with 'update', 'insert' and 'delete' statements but not with 'select').
You should replace the 'execsql' command with 'open' ... and remove the 'open' before 'sql.clear'.
Don't use a subquery when you should be using a join.
I think that your code ought to look like this
procedure TfrmEditBooking.FormShow(Sender: TObject);
begin
if SelectedID > 0 then
with frmBookingData.ADOQuery1 do
begin
SQL.Clear;
SQL.Add ('SELECT Name, Surname ');
sql.add ('FROM customers_main inner join bookings_main');
sql.add ('on customers_main.idcustomers_main = ');
sql.add ('bookings_main.customers_main_idcustomers_main');
sql.add ('where bookings_main.idbookings_main = :p1');
sql.params[0].asinteger:= SelectedID;
open;
Label1.Caption := fieldbyname ('name').asstring + ' ' +
fieldbyname ('surname').asstring;
Close;
end;
end;
To get this running you should change it to
procedure TfrmEditBooking.FormShow(Sender: TObject);
var
CustName: string;
begin
if SelectedID > 0 then
begin
with frmBookingData.ADOQuery1 do
begin
Close; // close first
SQL.Clear;
SQL.Add(
'SELECT Name, Surname '+
'FROM customers_main '+
'WHERE customers_main.idcustomers_main '+
'IN '+
'(SELECT bookings_main.customers_main_idcustomers_main '+
'FROM bookings_main '+
'WHERE bookings_main.idbookings_main = '+IntToStr(SelectedID)+')');
Open; // open the query
if not Eof then
CustName := FieldByName('Surname').AsString+' '+FieldByName('Name').AsString
else
CustName := 'not found';
Close; // close when finished
end;
Label1.Caption := CustName;
end;
end;
But you should get some (negative) side effects, if frmBookingData.ADOQuery1 is already in use for something different

mySQL If statement

I am trying to make this If Statement work, but I can't seem to make it do what I want. If I do a select #result, It'll give me the value 0, then why doesn't the IF statement work?
SET #message = '((sometihng here))';
select LEFT(#message, 1) into #firstChar;
select STRCMP(#firstChar,'(') into #result;
IF (#result = 0) THEN
SET #message = 'true';
//more selects and cals here;
END IF;
select #message;
I should get true, but I don't it shows me an error:
SQL query: IF( #result =0 ) THEN SET #message = 'true';
MySQL said:
1064 - You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use
near 'IF (#result = 0) THEN SET #message = 'true'' at line 1
try use function http://dev.mysql.com/doc/refman/5.0/en/control-flow-functions.html#function_if
SELECT IF(#result = 0, 'true', '((something here))') AS message
As Max Mara pointed out, that's a good work aroud. The reason the IF wasn't working is not because the syntax is incorrect, but because flow control functions like IF ... THEN are only valid inside of stored procedures or functions, All this thanks to #TehShrike
The IF .. THEN .. ELSE syntax in MySQL is only available for procedural code (stored precudures, functions, triggers..), but not for SELECT statements.
IF ELSE USED IN STORED PROCEDURE EXAMPLE BELOW
DELIMITER //
CREATE PROCEDURE NAME(IN Number INT)
BEGIN
IF roll= 1
THEN SELECT * FROM table1 WHERE id = roll;
ELSE
SELECT * FROM table2 WHERE id = 2;
END IF;
END //
DELIMITER ;

Use MySql function variables as table name in the query

I need to have a function that increments the certain ID in a table (like auto_increment)
I have smth like this
DELIMITER $$
DROP FUNCTION IF EXISTS `GetNextID`$$
CREATE FUNCTION `GetNextID`(tblName TEXT, increment INT)
RETURNS INT
DETERMINISTIC
BEGIN
DECLARE NextID INT;
SELECT MAX(concat(tblName, 'ID')) + increment INTO NextID FROM concat('table_', tblName);
## SELECT MAX(articleID) + increment INTO NextID FROM table_article;
RETURN NextID;
END$$
DELIMITER ;
INSERT INTO `table_article` ( articleID, articleAlias ) VALUES ( GetNextID('article', 5), 'TEST' );
So i pass two variables: tblName (without table_ prefix), and the increment number. The commented line - SELECT query inside the function itself - works well, but i want to dynamically pass table name to the function and so get data from a certain col of certain table. What am I doing wrong?
The error is:
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '('table_', tblName);
RETURN NextID;
END' at line 6
if i simply try to select max value in such a way
SELECT MAX(articleID) + increment INTO NextID FROM tblName;
The error reports that tblName does not exist. How can i tell MySql that this is actually a var passed to the function, not an exact table name? If it is possible.
you need something like
prepare stmp from concat('SELECT MAX(ID) + ', increment, ' INTO NextID FROM table_', tblName);
execute stmp;
deallocate prepare stmp;