Good day. I have a query in my Java code that deletes duplicate rows in a table. Initially it worked and for a while i didn't touch the project. But on running the file a few days ago, my code was throwing exceptions. This is my code:
String query = "DELETE error_log FROM error_log INNER JOIN "
+ "(SELECT min(id) minid, service_source, channel,transaction_type, provider_name, pido_account, beneficiary_id, error_description, error_date FROM error_log "
+ "GROUP BY service_source, channel, transaction_type, provider_name, pido_account, beneficiary_id, error_description, error_date "
+ "HAVING COUNT(1) > 1 AS duplicates ON "
+ "(duplicates.service_source = error_log.service_source AND duplicates.channel = error_log.channel "
+ "AND duplicates.transaction_type = error_log.transaction_type AND duplicates.provider_name = error_log.provider_name "
+ "AND duplicates.pido_account = error_log.pido_account AND duplicates.beneficiary_id = error_log.beneficiary_id "
+ "AND duplicates.error_description = error_log.error_description AND duplicates.error_date = error_log.error_date "
+ "AND duplicates.minid <> error_log.id"
+ ")"
+ ")";
int deploy = duplicate.executeUpdate(query);
I get this afterwards:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: 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 'AS duplicates ON (duplicates.service_source = error_log.service_source AND dupli' at line 1.
How do i correct this and have the duplicates deleted from the table?
You have a missing ) on line + "HAVING COUNT(1) > 1 AS duplicates ON " and have an extra ) at the end.
String query = "DELETE error_log FROM error_log INNER JOIN "
+ "(SELECT min(id) minid, service_source, channel,transaction_type, provider_name, pido_account, beneficiary_id, error_description, error_date FROM error_log "
+ "GROUP BY service_source, channel, transaction_type, provider_name, pido_account, beneficiary_id, error_description, error_date "
+ "HAVING COUNT(1) > 1 ) AS duplicates ON "
+ "(duplicates.service_source = error_log.service_source AND duplicates.channel = error_log.channel "
+ "AND duplicates.transaction_type = error_log.transaction_type AND duplicates.provider_name = error_log.provider_name "
+ "AND duplicates.pido_account = error_log.pido_account AND duplicates.beneficiary_id = error_log.beneficiary_id "
+ "AND duplicates.error_description = error_log.error_description AND duplicates.error_date = error_log.error_date "
+ "AND duplicates.minid <> error_log.id"
+ ")";
int deploy = duplicate.executeUpdate(query);
If you haven't made any changes and it stopped working, 1) are you sure you tested this code? and 2) has anyone else made any changes without your knowledge?
Related
I want to delete an "order" from my database using the primary key, orderID. The orderID is a foreign key in orderItem, OrderItem has a foreign key in foodItem called foodItemID, foodItem has a foreign key in menu called menuID.
Below is my query:
"DELETE FROM orders, orderitem, fooditem, menu " +
"USING orders " +
"INNER JOIN orderitem " +
"WHERE orderID = " + "'" + orderID + "' " + " AND orders.orderID = orderItem.orderID " +
"INNER JOIN foodItem " +
"WHERE orderItem.foodItemID = foodItemID.foodItemID " +
"INNER JOIN Menu " +
"WHERE foodItem.menuID = menu.menuID";
I am coding in JAVAFX..
The error I receive is:
Caused by: java.sql.SQLSyntaxErrorException: 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 'INNER JOIN foodItem WHERE orderItem.foodItemID = foodItemID.foodItemID INNER JOI' at line 1
You don't join WHERE, you join ON something. So
"DELETE FROM orders, orderitem, fooditem, menu " +
"USING orders " +
"INNER JOIN orderitem " +
"ON orderID = " + "'" + orderID + "' " + " AND orders.orderID = orderItem.orderID " +
"INNER JOIN foodItem " +
"ON orderItem.foodItemID = foodItemID.foodItemID " +
"ON JOIN Menu " +
"ON foodItem.menuID = menu.menuID";
Also, this part
"ON orderID = " + "'" + orderID + "' " + "
Is a SQL Injection waiting to happen. You should use prepared statements instead. How you use them depends on what library/framework you're using to connect to the db (which you didn't specify).
If i insert a quote symbol " in the codContract parameter I receive the following error.
Error querying database. Cause: java.sql.SQLSyntaxErrorException:
ORA-00972: identifier too long
The error may exist in mappers/existence.xml The error may involve
com.iv.queryinterface.AssistenzaMapper.getTitlesFromCodContratct-Inline
The error occurred while setting parameters
SQL:
SELECT t.id_title,
c.des_lastname,
c.des_firstname,
to_char(t.dta_raw, 'DD/MM/YYYY') AS DTA_RAW,
DECODE(t.cod_statustitle, '1', 'Raw', '2', 'Stated') AS STATUS_TITLE
FROM Ivf_Policy p,
Ivf_Title t,
Ivg_Client c,
Ivf_Price pr
WHERE Cod_Contract = TEST
AND p.id_policy = t.id_policy
AND t.cod_type_title IN(2, 3, 13)
AND t.cod_statustitle IN(1, 2)
AND t.cod_client = c.cod_client
AND t.id_price = pr.id_price;
Cause: java.sql.SQLSyntaxErrorException: ORA-00972: identifier too
long
In this example, i set " TEST as value for the codContract parameter. My questions are:
Is this an exploitable SQL injection or a false positive that just prints an sql error into the stack trace?
The code is susceptible to SQL injection, and does no escaping. All that is avoidable by the use of PreparedStatement. Where the query string is not composed dynamically.
Now "TEST is the first part of an SQL identifier till a closing double quote.
I do not want to instruct readers on hacking, but think what something like
"'' OR 1=1 "
+ "UNION SELECT u.login, u.password, '', '', '', '' "
+ "FROM users"
+ "\u0000-- ";
might reveal on data.
Use java.sql.PreparedStatement for avoiding SQL injection.
String query =
"SELECT " +
" t.id_title , " +
" c.des_lastname , " +
" c.des_firstname , " +
" TO_CHAR(t.dta_raw, 'DD/MM/YYYY') AS DTA_RAW, " +
" DECODE(t.cod_statustitle, '1', 'Raw', '2', 'Stated') AS STATUS_TITLE " +
"FROM " +
" Ivf_Policy p, " +
" Ivf_Title t, " +
" Ivg_Client c, " +
" Ivf_Price pr " +
"WHERE " +
"1 = 1 AND " +
" Cod_Contract = ? " +
"AND p.id_policy = t.id_policy " +
"AND t.cod_type_title IN(2, " +
" 3, " +
" 13) " +
"AND t.cod_statustitle IN(1, " +
" 2) " +
"AND t.cod_client = c.cod_client " +
"AND t.id_price = pr.id_price;";
PreparedStatement stmt = connection.prepareStatement(query);
stmt.setString(1, 'TEST');
ResultSet rs = stmt.executeQuery();
To avoid SQL injection, do not append parameter values directly to SQL queries.
Use bind variables instead.
Thanks.
I want to use pagination with a native query. I use for this this syntaxe as in this example : Spring Data and Native Query with pagination
and it's my query:
#Query(value="SELECT rownum() as RN, users.num, users .l_service,service.type_service, users.date, " +
"chambre.price," +
"price* ( case when(datediff(day,date_d,date_f)=0) then 1 " +
"else datediff(day,date_d,date_f) end ) as Montant," +
"case when (service.type_service='R') and datediff(day,date_d,date_f) >=21 " +
"then (21300+(datediff(day,date_d,date_f)-21)*200)" +
"else price*(case when(datediff(day,date_d,date_f)=0) then 1 else datediff(day,date_d,date_f)end) end AS Montant_final " +
" users.year, users.Etat, " +
" from chambre JOIN users ON chambre.code = users.type " +
"JOIN service on service.code = users.l_service " +
" WHERE users.Etat='V' and RN between ?#{ #pageable.offset -1} and ?#{#pageable.offset + #pageable.pageSize order by users.num",
countQuery ="select count(*) from users ",nativeQuery = true)
Page<Object> getStatistiques(Pageable pageable);
I get this error :
Cannot mix JPA positional parameters and native Hibernate positional/ordinal parameters
This is the solution I found to my problem:
#Query(value="SELECT * from (SELECT ROW_NUMBER() OVER (ORDER BY users.num) as RN, users.num, users .l_service,service.type_service, users.date, " +
"chambre.price," +
"price* ( case when(datediff(day,date_d,date_f)=0) then 1 " +
"else datediff(day,date_d,date_f) end ) as Montant," +
"case when (service.type_service='R') and datediff(day,date_d,date_f) >=21 " +
"then (21300+(datediff(day,date_d,date_f)-21)*200)" +
"else price*(case when(datediff(day,date_d,date_f)=0) then 1 else datediff(day,date_d,date_f)end) end AS Montant_final " +
" users.year, users.Etat, " +
" from chambre JOIN users ON chambre.code = users.type " +
"JOIN service on service.code = users.l_service " +
" WHERE users.Etat='V') AS STA where RN between ?#{ #pageable.offset -1} and ?#{#pageable.offset + #pageable.pageSize} order by STA.num",
countQuery ="select count(*) from users ",nativeQuery = true)
Page<Object> getStatistiques(Pageable pageable);
I share it with you perhaps it can help someone else!
Problem Synopsis:
When attempting to execute a SQL query in Java with a SQLite Database, the SQL statement fails to return from the execute() or executeQuery() method. In other words, the system "hangs" when executing this SQL statement.
Question:
What am I doing wrong to explain why the ResultSet never "returns?"
TroubleShooting
I tried to narrow the problem and the problem seems to be with the Java execute() or executeQuery(). A ResultSet never seems to return. For example, I tried executing exactly the same query directly in SQLite (that is, using a SQLite DB manager). The query (outside Java) executes in about 5ms and returns the valid result set.
NOTE: No exception is thrown. The system merely seems to "hang" and becomes unresponsive until a manual kill. (waiting more than 10 minutes.)
Code:
I heavily edited this code to make the problem simpler to see. (In production, this uses Prepared Statements. But, the error occurs in both methods--straight Statement and prepared Statement versions.)
Basically, the SELECT returns a single DB item so the user can review that item.
Statement st = conn.createStatement() ;
ResultSet rs = st.executeQuery("SELECT DISTINCT d1.id, d1.sourcefullfilepath, " +
"d1.sourcefilepath, d1.sourcefilename, d1.classificationid, d1.classid, " +
"d1.userid FROM MatterDataset, (SELECT MatterDataset.id, " +
"MatterDataset.sourcefullfilepath, MatterDataset.sourcefilepath, " +
"MatterDataset.sourcefilename, MatterDataset.matterid , " +
"DocumentClassification.classificationid, DocumentClassification.classid," +
" DocumentClassification.userid FROM MatterDataset " +
"LEFT JOIN DocumentClassification ON " +
"DocumentClassification.documentid = Matterdataset.id " +
"WHERE ( DocumentClassification.classid = 1 OR " +
"DocumentClassification.classid = 2 ) AND " +
"DocumentClassification.userid < 0 AND " +
"MatterDataset.matterid = \'100\' ) AS d1 " +
"LEFT JOIN PrivilegeLog ON " +
"d1.id = PrivilegeLog.documentparentid AND " +
"d1.matterid = PrivilegeLog.matterid " +
"WHERE PrivilegeLog.privilegelogitemid IS NULL " +
"AND MatterDataset.matterid = \'100\' " +
"ORDER BY d1.id LIMIT 1 ;") ;
Configuration:
Java 6,
JDBC Driver = Xerial sqlite-jdbc-3.7.2,
SQLite 3,
Windows
Update
Minor revision: as I continue to work with this, adding a MIN(d1.id) to the beginning of the SQL statement at least returns a ResultSet (rather than "hanging"). But, this is not really what I wanted as the MIN obviates the LIMIT function.
Statement st = conn.createStatement() ;
ResultSet rs = st.executeQuery("SELECT DISTINCT MIN(d1.id), d1.id,
d1.sourcefullfilepath, " +
"d1.sourcefilepath, d1.sourcefilename, d1.classificationid, d1.classid, " +
"d1.userid FROM MatterDataset, (SELECT MatterDataset.id, " +
"MatterDataset.sourcefullfilepath, MatterDataset.sourcefilepath, " +
"MatterDataset.sourcefilename, MatterDataset.matterid , " +
"DocumentClassification.classificationid, DocumentClassification.classid," +
" DocumentClassification.userid FROM MatterDataset " +
"LEFT JOIN DocumentClassification ON " +
"DocumentClassification.documentid = Matterdataset.id " +
"WHERE ( DocumentClassification.classid = 1 OR " +
"DocumentClassification.classid = 2 ) AND " +
"DocumentClassification.userid < 0 AND " +
"MatterDataset.matterid = \'100\' ) AS d1 " +
"LEFT JOIN PrivilegeLog ON " +
"d1.id = PrivilegeLog.documentparentid AND " +
"d1.matterid = PrivilegeLog.matterid " +
"WHERE PrivilegeLog.privilegelogitemid IS NULL " +
"AND MatterDataset.matterid = \'100\' " +
"ORDER BY d1.id LIMIT 1 ;") ;
What a messy SQL statement (sorry)! I don't know SQLite, but why not simplify to:
SELECT DISTINCT md.id, md.sourcefullfilepath, md.sourcefilepath, md.sourcefilename,
dc.classificationid, dc.classid, dc.userid
FROM MatterDataset md
LEFT JOIN DocumentClassification dc
ON dc.documentid = md.id
AND (dc.classid = 1 OR dc.classid = 2 )
AND dc.userid < 0
LEFT JOIN PrivilegeLog pl
ON md.id = pl.documentparentid
AND md.matterid = pl.matterid
WHERE pl.privilegelogitemid IS NULL
AND md.matterid = \'100\'
ORDER BY md.id LIMIT 1 ;
I was uncertain whether you wanted to LEFT JOIN or INNER JOIN to DocumentClassification (using LEFT JOIN and then put requirements on classid and userid in the WHERE statement is - in my opinion - contradictory). If DocumentClassification has to exist, then change to INNER JOIN and put the references to classid and userid into the WHERE clause, if DocumentClassification may or may not exist in your result set, then keep the query as I suggested above.
I went back and started over. The SQL syntax, while it worked outside Java, simply seemed too complex for the JDBC driver. This cleaned-up revision seems to work:
SELECT DISTINCT
MatterDataset.id, MatterDataset.sourcefullfilepath, MatterDataset.sourcefilepath,
MatterDataset.sourcefilename
FROM MatterDataset , DocumentClassification
ON DocumentClassification.documentid = MatterDataset.id
AND MatterDataset.matterid = DocumentClassification.matterid
LEFT JOIN PrivilegeLog ON MatterDataset.id = PrivilegeLog.documentparentid
AND MatterDataset.matterid = PrivilegeLog.matterid
WHERE PrivilegeLog.privilegelogitemid IS NULL
AND MatterDataset.matterid = '100'
AND (DocumentClassification.classid = 1 OR DocumentClassification.classid = 2)
AND DocumentClassification.userid = -99
ORDER BY MatterDataset.id LIMIT 1;
A nice lesson in: just because you can in SQL doesn't mean you should.
What this statement does is essentially locates items in the MatterDataset Table that are NOT in the PrivilegeLog table. The LEFT JOIN and IS NULL syntax locate the items that are "missing." That is, i want to find items that are in MatterDataset but not yet in PrivilegeLog and return those items.
I have a follow up to complicated mysql question that I recently asked: Show the ten first contacts that I have recieved message
Now I know that it is missing something, my last question was:
I want to create Sql statement that
show the ten first contacts that I
have recieved message from along with
their latest sent message and time.
The table columns is messageId,
message, fromProfileId, toProfileId,
timeStamp and table is called
messages. The database is Mysql and
Java is the language. But I want this
to happen in one single sql statement.
What's missing is that I want to show the message I've sent also, but it should be grouped with the messages that I've recieved from the user I've sent to:
ten first contacts that I have
received message from or sent to along
with their latest sent message and
time.
Little complicated to understand? Ok. think like this. the quoted first sql statement above only show messages that I reveived from. but what if I send a message? That message will never show up.
This is my code, but I failed to succed(look at where I marked the comment):
"SELECT M2.messageProfileId, profiles.profileMiniature, profiles.firstName, profiles.lastName, profiles.timeFormat, lastMessages.message, lastMessages.timeStamp " +
"FROM (" +
" SELECT IF(M1.fromProfileId = ?, M1.toProfileId, M1.fromProfileId) AS messageProfileId, " +
" max(M1.timeStamp) AS lastMessageTime " +
" FROM messages AS M1 " +
" WHERE M1.toProfileId = ? " +
" OR M1.fromProfileId = ? " +
" GROUP BY IF(M1.fromProfileId = ?, M1.toProfileId, M1.fromProfileId) " +
" ORDER BY max(M1.timeStamp) DESC " +
" LIMIT 10 " +
" ) AS M2 " +
"INNER JOIN messages AS lastMessages " +
"ON (" +
" lastMessages.timeStamp = M2.lastMessageTime " +
"AND lastMessages.fromProfileId = M2.messageProfileId" +//This to be like the if statements above, but how?
" )" +
"INNER JOIN profiles " +
"ON M2.messageProfileId = profiles.profileId ";
UPDATE:
All question marks in the above code will be replaced with a a same id, for example 27.
UPDATE:
You just have to solve one line now. Look at the commented line above. I dont know how to make if statement in where clause?
Ok figured it out myself
"SELECT M2.messageProfileId, profiles.profileMiniature, profiles.firstName, profiles.lastName, profiles.timeFormat, lastMessages.message, lastMessages.timeStamp " +
"FROM (" +
" SELECT IF(M1.fromProfileId = ?, M1.toProfileId, M1.fromProfileId) AS messageProfileId, " +
" max(M1.timeStamp) AS lastMessageTime " +
" FROM messages AS M1 " +
" WHERE (M1.toProfileId = ? " +
" OR M1.fromProfileId = ?) " +
" GROUP BY IF(M1.fromProfileId = ?, M1.toProfileId, M1.fromProfileId) " +
" ORDER BY max(M1.timeStamp) DESC " +
" LIMIT 10 " +
" ) AS M2 " +
"INNER JOIN messages AS lastMessages " +
"ON (" +
" lastMessages.timeStamp = M2.lastMessageTime " +
"AND (" +
" lastMessages.fromProfileId = M2.messageProfileId " +
"OR lastMessages.toProfileId = M2.messageProfileId " +
" )" +
" )" +
"INNER JOIN profiles " +
"ON M2.messageProfileId = profiles.profileId ";