0

I'm trying to call a SQL query (Oracle DB) to update a column in one table, when some columns in a linked table has certain values. My syntax works fine in the general code, but in my unit test, I get a "BadSQLGrammarException":

    org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [UPDATE (SELECT ex.STATUS FROM BRRS_EXECUTION ex, BRRS_DEMANDE dem WHERE dem.ID_DEMANDE=ex.ID_DEMANDE AND dem.UTILISATEUR=? AND dem.PROFIL=? AND dem.REGION=? AND dem.REGIME=? AND ex.ID_EXECUTION=?) SET STATUS=?]; nested exception is org.h2.jdbc.JdbcSQLException: Syntax error in SQL statement "UPDATE ([*]SELECT EX.STATUS FROM BRRS_EXECUTION EX, BRRS_DEMANDE DEM WHERE DEM.ID_DEMANDE=EX.ID_DEMANDE AND DEM.UTILISATEUR=? AND DEM.PROFIL=? AND DEM.REGION=? AND DEM.REGIME=? AND EX.ID_EXECUTION=?) SET STATUS=? "; expected "identifier"; SQL statement:
UPDATE (SELECT ex.STATUS FROM BRRS_EXECUTION ex, BRRS_DEMANDE dem WHERE dem.ID_DEMANDE=ex.ID_DEMANDE AND dem.UTILISATEUR=? AND dem.PROFIL=? AND dem.REGION=? AND dem.REGIME=? AND ex.ID_EXECUTION=?) SET STATUS=? [42001-190]
    at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:231)
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73)
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:649)
    at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:870)
    at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:894)
    at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.update(NamedParameterJdbcTemplate.java:287)
    at fr.cnamts.brrsm.services.app.majRequeteSAS.repository.impl.RequeteSASRepositoryOracle.deleteRequeteSAS(RequeteSASRepositoryOracle.java:191)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
    at com.sun.proxy.$Proxy46.deleteRequeteSAS(Unknown Source)
    at fr.cnamts.brrsm.services.app.majRequeteSAS.repository.RequeteSASRepositoryTest.testSupprimerRequete(RequeteSASRepositoryTest.java:157)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:55)
    at org.junit.rules.RunRules.evaluate(RunRules.java:20)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: org.h2.jdbc.JdbcSQLException: Syntax error in SQL statement "UPDATE ([*]SELECT EX.STATUS FROM BRRS_EXECUTION EX, BRRS_DEMANDE DEM WHERE DEM.ID_DEMANDE=EX.ID_DEMANDE AND DEM.UTILISATEUR=? AND DEM.PROFIL=? AND DEM.REGION=? AND DEM.REGIME=? AND EX.ID_EXECUTION=?) SET STATUS=? "; expected "identifier"; SQL statement:
UPDATE (SELECT ex.STATUS FROM BRRS_EXECUTION ex, BRRS_DEMANDE dem WHERE dem.ID_DEMANDE=ex.ID_DEMANDE AND dem.UTILISATEUR=? AND dem.PROFIL=? AND dem.REGION=? AND dem.REGIME=? AND ex.ID_EXECUTION=?) SET STATUS=? [42001-190]
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
    at org.h2.message.DbException.getSyntaxError(DbException.java:205)
    at org.h2.command.Parser.readIdentifierWithSchema(Parser.java:3065)
    at org.h2.command.Parser.readTableOrView(Parser.java:5270)
    at org.h2.command.Parser.readSimpleTableFilter(Parser.java:764)
    at org.h2.command.Parser.parseUpdate(Parser.java:707)
    at org.h2.command.Parser.parsePrepared(Parser.java:454)
    at org.h2.command.Parser.parse(Parser.java:304)
    at org.h2.command.Parser.parse(Parser.java:276)
    at org.h2.command.Parser.prepareCommand(Parser.java:241)
    at org.h2.engine.Session.prepareLocal(Session.java:460)
    at org.h2.engine.Session.prepareCommand(Session.java:402)
    at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1188)
    at org.h2.jdbc.JdbcPreparedStatement.<init>(JdbcPreparedStatement.java:72)
    at org.h2.jdbc.JdbcConnection.prepareStatement(JdbcConnection.java:276)
    at fr.cnamts.brrsm.services.app.utils.test.jdbc.UnclosableConnection.prepareStatement(UnclosableConnection.java:58)
    at org.springframework.jdbc.core.PreparedStatementCreatorFactory$PreparedStatementCreatorImpl.createPreparedStatement(PreparedStatementCreatorFactory.java:238)
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:627)
    ... 50 more

Apparently the problem is between the parenthesis and the select. It seems that it does not accept the "UPDATE (SELECT..." syntax. if you want more of this, here's the query (with constant for column and table names) and the function in which it's used:

private static final String UPDATE_REQUETE_SAS_SQL = "UPDATE (SELECT ex."+ COL_STATUS +
        " FROM " + TABLE_BRRS_EXECUTION + " ex, " + TABLE_BRRS_DEMANDE + " dem "
        + "WHERE dem." + COL_ID_DEMANDE + "=ex." + COL_ID_DEMANDE + " "
        + "AND dem." + COL_UTILISATEUR + "=:UTILISATEUR " 
        + "AND dem." + COL_PROFIL + "=:PROFIL " 
        + "AND dem." + COL_REGION + "=:REGION "
        + "AND dem." + COL_REGIME + "=:REGIME " 
        + "AND ex." + COL_ID_EXECUTION + "=:ID_EXECUTION)"
        + " SET " + COL_STATUS +"=:STATUS";

 @Override
    public void deleteRequeteSAS(RequeteSASEntity requeteSASEntity, String user, String region, String profil, String regime) {
        // affectation des parametres nommés
        final SqlParameterSource params = new MapSqlParameterSource()
                .addValue(COL_STATUS, STATUS_SUPPRIME)
                .addValue(COL_ID_EXECUTION, requeteSASEntity.getIdExecution())
                .addValue(COL_UTILISATEUR, user)
                .addValue(COL_REGION, region)
                .addValue(COL_PROFIL, profil)
                .addValue(COL_REGIME, regime);


        // execution de l'update
        jdbcTemplate.update(UPDATE_REQUETE_SAS_SQL, params);


    }

And finally here's my test :

@Test public void testSupprimerRequete() throws IOException {

    String mockUser = "QUAREFMETIER-00001";
    String mockRegion = "99";
    String mockProfil = "030";
    String mockRegime = "01";

    List<RequeteSASEntity> listReqInit = new ArrayList<RequeteSASEntity>();
    listReqInit.add(requeteSASJdbc1);
    listReqInit.add(requeteSASJdbc2);

    requeteSASRepository.deleteRequeteSAS(requeteSASJdbc1, mockUser, mockRegion, mockProfil, mockRegime);

    assertTrue(!listReqInit.isEmpty());
    assertTrue(listReqInit.get(1).getStatus() == 7);
}

Of course for my tests I use a similar xml defined base, with the very same structure.

So where is the problem in my query and how can I correct it? Or, if it's a problem with the UPDATE (SELECT... syntax, how can I have a similar query which would work? Thank you.

Djbapt
  • 21
  • 4
  • Perhaps see https://stackoverflow.com/questions/2334712/how-do-i-update-from-a-select-in-sql-server – D M Sep 26 '17 at 16:56
  • In general, you can't start off with `UPDATE (SELECT ...`. You have to start with `UPDATE TableName ...` After all, you're updating the table - you're not updating your `select` statement. – D M Sep 26 '17 at 16:59
  • 1
    @DM Some database systems (including the SQL standard), considers subqueries to be virtual tables and allow updates to this virtual table under certain conditions. Likely the database used in the test doesn't allow it, while the actual database does. – Mark Rotteveel Sep 26 '17 at 18:17

1 Answers1

0
Update TableName Set COL_STATUS =(
SELECT EX.STATUS FROM BRRS_EXECUTION EX, BRRS_DEMANDE DEM WHERE 
DEM.ID_DEMANDE=EX.ID_DEMANDE AND DEM.UTILISATEUR=? AND DEM.PROFIL=? AND 
DEM.REGION=? AND DEM.REGIME=? AND EX.ID_EXECUTION=?);

You can modify your query in this way.

Kamal Chanda
  • 163
  • 2
  • 12
  • Hum, no it's not the same query. I want to set the COL_STATUS to an absolute value (=7 -> :STATUS) when there is the given conditions on the other columns of the two tables. Yours doesn't do this. – Djbapt Sep 27 '17 at 07:26