I need to execute several SQL statements in one MyBatis Mapper method, because the SQLs are dependend on each other. With H2, this is no problem:
#Delete("DELETE FROM DETAIL_TABLE " +
" WHERE MASTER_ID IN " +
" (SELECT ID FROM MASTER WHERE BUSINESS_KEY = #{businessKey});" +
"DELETE FROM MASTER " +
" WHERE BUSINESS_KEY = #{businessKey}; ")
void delete(#Param("businessKey") Integer businessKey);
When switching to DB2 the statement does not work anymore, because the JDBC driver throws the following exception:
Caused by: com.ibm.db2.jcc.am.SqlSyntaxErrorException: DB2 SQL Error: SQLCODE=-104, SQLSTATE=42601, SQLERRMC=?;DELETE FROM MASTER WHERE;TAIL WHERE BUSINESS_KEY =;<space>, DRIVER=4.26.14
This is just an easy example to demonstrate the issue. I am aware that you can send a cascading delete statement in the shown situation.
I read a StackOverflow post, that multiple SQL statements in one call are not supported by some JDBC drivers and are not recommended, but sometimes you need to execute different SQLs in a certain order, so defining several MyBatis mapper methods does not solve the issue.
Does anybody has any idea how this can be achieved?
On the DB2 side, you can run a compound statement
"BEGIN ATOMIC" +
" DELETE FROM DETAIL_TABLE" +
" WHERE MASTER_ID IN" +
" (SELECT ID FROM MASTER WHERE BUSINESS_KEY = #{businessKey});" +
" DELETE FROM MASTER" +
" WHERE BUSINESS_KEY = #{businessKey};" +
"END"
or create and call a stored procedure
Related
I am working on a SSIS package that rejects already loaded files & load only new files to table.
I used for each loop and exceute SSQL to validate if the files are already loaded. When I evaluate
the expression of Execute SQL Task, it evaluates fine. But When I run the paackage I get the following error.
[Execute SQL Task] Error: Executing the query "DECLARE #FileName VARCHAR(100)
SET #FileName=Custo..." failed with the following error: "Incorrect syntax near ''.".
Possible failure reasons: Problems with the query, "ResultSet" property not set correctly,
parameters not set correctly, or connection not established correctly.
The Expression I used in the Execute SQL task is :
"DECLARE #FileName VARCHAR(100)
SET #FileName="+#[User::FileName]+"'
IF EXISTS (SELECT 1
FROM [dbo].[FileLoadStatus]
WHERE filename =#FileName)
BEGIN
SELECT 1 AS FileExistsFlg
END
ELSE
BEGIN
Select 0 AS FileExistsFlg
END"
screen shot of the execute SQL Task
I really apprecaite if you can tell where the problem is ?
You could simplify your expression a little bit to make clear where the SSIS variable is being used:
"SELECT COUNT(*) AS FileExistsFlg
FROM (
SELECT TOP(1) *
FROM
dbo.FileLoadStatus
WHERE
[filename] = '" + #[User::FileName] + "'
) x;"
On the other hand for the SQL Task you could use a standard parameterized query. Assuming you are using an OLEDB connection, the parameter placeholder is the ? sign. No expression is needed and the equivalent Direct Input for the task is:
SELECT COUNT(*) AS FileExistsFlg
FROM (
SELECT TOP(1) *
FROM
dbo.FileLoadStatus
WHERE
[filename] = ?
) x;
With OLEDB you have to map your variable to the placeholder by position (zero based) so in this case the Parameter Name is the number zero. The other properties depend on your metadata and correspond to the variable you would have declare in SQL...
This is less error prone, clearer and reusable for multiple calls as it generates a Prepared Statement.
If your connection type was ADO.Net, the mapping is name based. So check the documentation for the Parameter names and markers for each connection type.
I'm new to Firebird and I'm testing a few things to check out the differences between Fb and SQlite (and the .net driver).
I am trying to do a drop table if exists followed by the creation of a table. In Sqlite I am able to do this by:
command.CommandText = #"DROP TABLE IF EXISTS Persons; CREATE TABLE Persons (
PersonID int,
LastName text,
FirstName text,
Address text,
City text); ";
command.ExecuteNonQuery();
However in Firebird the same query fails. I've read that this is not possible to use IFs directly in Firebird SQL, so I've tried to use:
command.CommandText = #"
EXECUTE BLOCK AS
BEGIN IF EXISTS
(SELECT RDB$RELATION_NAME FROM RDB$RELATIONS WHERE RDB$RELATION_NAME = 'Persons')
THEN DROP TABLE Persons; END CREATE TABLE Persons (
PersonID int,
LastName varchar(255),
FirstName varchar(255),
Address varchar(255),
City varchar(255)
); ";
command.ExecuteNonQuery();
But it fails also with the following error:
Dynamic SQL Error SQL error code = -104 Token unknown - line 1, column
27
Can you please help me on this? I've tried to find more info on the web that could help me, but did not have any luck.
Firebird's SQL syntax doesn't have a drop table if exists, instead use recreate table. recreate table will try to drop the table if it exists before creating it. The syntax of recreate table is - other than recreate instead of create - the same as create table.
Your attempt to use execute block fails for two reasons:
You cannot execute two statements together as a command. If you want to execute a script of multiple statements, you'll need to execute each statement individually or use the FbScript class which will parse the script and execute the individual statements for you.
Even if you execute these statements individually, it will still fail, because PSQL (the stored procedure language used in execute block) does not allow execution of DDL. You can use execute statement to circumvent this limitation, but it is better not to do that. In that way you could also address the previous point by executing both - using execute statement - within the execute block.
Alternatively you could just drop the table unconditionally and catch (and ignore) the resulting exception.
I cannot seem to figure out why it keep giving me this: executeQuery method can not be used for update. The way my code works is it takes in text from 5 jTextFields then converted to string double and int values. These values are sent to a method which will be pasted below. The problem is the sql statement is not working correctly at least I believe that is the problem. The columns are correct as well.
try{
String host = "jdbc:derby://localhost:1527/Comics";
String uName = "Brenton";
String uPass = "password";
Connection con = DriverManager.getConnection(host, uName, uPass);
Statement stat = con.createStatement();
String sql = "INSERT INTO LIBRARY(TITLE, ISSUE, PRICE, PUBLISHER, YEAR_ISSUED)" + "VALUES( '" + title + "', " + issue + ", " + price + ", '" + publisher + "', " + year + ")";
ResultSet rs = stat.executeQuery(sql);
}
catch(SQLException err){
System.out.println(err.getMessage());
}
Your immediate error (I think) is that your insert statement has no spaces between the end of the column names and the start of the VALUES keyword. But all this could be avoided if you used prepared statements:
String sql = "INSERT INTO LIBRARY(TITLE, ISSUE, PRICE, PUBLISHER, YEAR_ISSUED) VALUES(?, ?, ?, ?, ?)";
PreparedStatement ps = con.prepareStatement(sql);
ps.setString(1, title);
ps.setString(2, issue);
ps.setDouble(3, price);
ps.setString(4, publisher);
ps.setYear(5, year);
Note several obvious advantages here to this approach. First, you may write your insert query as a single string, with no concatenation. This helps avoid the mistake you made with whitespace. Second, statements do the work of escaping the string values (and any other value) properly.
What "executeQuery method can not be used for update" means is as follows:
Some SQL statements are used for queries. A SQL query is generally a SELECT statement, and it returns a set of rows from a database, which you process using a a JDBC ResultSet.
A SQL update is an INSERT, UPDATE, or DELETE statement, and it modifies rows in the database, but does not return any rows back to you (rather it returns the number of rows that you modified).
So, you can query, or you can update.
To query, you use executeQuery, and you get back a ResultSet.
To update, you use executeUpdate, and you get back a int.
For executeQuery, you pass a SELECT SQL statement.
For executeUpdate, you pass a INSERT, UPDATE, or DELETE SQL statement.
In your code, you are trying to perform a INSERT SQL statement, but you are calling executeQuery.
If id is present in flowVars, i will fetch user from database by id. If not present, I will fetch all users. I tried to use this expression but no success:
select * from user #[flowVars.userId != null ? 'where id = ' + flowVars.userId : '']
error is :
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 ''where id = 1'' at line 1 (com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException).
I think it creates single quote in query.
Insert into info Values (#[payload.Cname], #[payload.orderid], #[payload.customerid], #[payload.allergies])
you can write like this a dynamic query
I have linked SQL Server 2005 to an Oracle Server, and am using OpenQuery() to pass data from Oracle to SQL Server.
So, for instance, the following query works fine:
SELECT *
FROM OPENQUERY(ORACLE_LINK, 'SELECT FIELD1
FROM ORACLE.TABLE1');
Everything works, unless I ask for a field which is a date/time in the Oracle database. For instance, say that TABLE1 has ten fields, one of which is a timestamp. If I ask for all nine fields except for the timestamp, it works. If I ask:
SELECT *
FROM OPENQUERY(ORACLE_LINK, 'SELECT *
FROM ORACLE.TABLE1');
I get the following error:
OLE DB provider "MSDAORA" for linked server "ORACLE_LINK" returned message "Oracle error occurred, but error message could not be retrieved from Oracle.".
OLE DB provider "MSDAORA" for linked server "ORACLE_LINK" returned message "Data type is not supported.".
I also get the same error if I ask for only the timestamp field.
What is the best way of handling this error? Thanks.
I do it with this function (partial code):
select #StringOut = '{ts ''''' + convert(varchar(20), #DateIn, 20) + ''''' }';
RETURN #StringOut
and this goes into the query:
and procedure_date_dt = ' + dbo.TimestampString(#date) + '
and event_type = ''''Time Notation''''
and it works when I run it.