{"record":{"id":"fc1eb9efe31f831e","repo":"mybatis/mybatis-3","slug":"selectkey-returned-more-than-one-value","errorCode":null,"errorMessage":"SelectKey returned more than one value.","messagePattern":"SelectKey returned more than one value\\.","errorType":"exception","errorClass":"ExecutorException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/apache/ibatis/executor/keygen/SelectKeyGenerator.java","lineNumber":72,"sourceCode":"      processGeneratedKeys(executor, ms, parameter);\n    }\n  }\n\n  private void processGeneratedKeys(Executor executor, MappedStatement ms, Object parameter) {\n    try {\n      if (parameter != null && keyStatement != null && keyStatement.getKeyProperties() != null) {\n        String[] keyProperties = keyStatement.getKeyProperties();\n        final Configuration configuration = ms.getConfiguration();\n        final MetaObject metaParam = configuration.newMetaObject(parameter);\n        // Do not close keyExecutor.\n        // The transaction will be closed by parent executor.\n        Executor keyExecutor = configuration.newExecutor(executor.getTransaction(), ExecutorType.SIMPLE);\n        List<Object> values = keyExecutor.query(keyStatement, parameter, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);\n        if (values.isEmpty()) {\n          throw new ExecutorException(\"SelectKey returned no data.\");\n        }\n        if (values.size() > 1) {\n          throw new ExecutorException(\"SelectKey returned more than one value.\");\n        } else {\n          MetaObject metaResult = configuration.newMetaObject(values.get(0));\n          if (keyProperties.length == 1) {\n            if (metaResult.hasGetter(keyProperties[0])) {\n              setValue(metaParam, keyProperties[0], metaResult.getValue(keyProperties[0]));\n            } else {\n              // no getter for the property - maybe just a single value object\n              // so try that\n              setValue(metaParam, keyProperties[0], values.get(0));\n            }\n          } else {\n            handleMultipleProperties(keyProperties, metaParam, metaResult);\n          }\n        }\n      }\n    } catch (ExecutorException e) {\n      throw e;\n    } catch (Exception e) {","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/mybatis/mybatis-3/blob/008069adb1b089579b5dcba87ee591908b263274/src/main/java/org/apache/ibatis/executor/keygen/SelectKeyGenerator.java#L54-L90","documentation":"SelectKeyGenerator requires the <selectKey> statement to produce exactly one row, because a single key value is assigned to one keyProperty set. If the query returns two or more rows, MyBatis cannot decide which value is the key and throws this ExecutorException.","triggerScenarios":"A <selectKey> like SELECT id FROM t WHERE name = #{name} matching duplicates; a sequence select accidentally returning multiple rows (bad FROM clause, join fan-out); MAX(id) queries without aggregation over a filtered join.","commonSituations":"Non-unique lookup columns inside selectKey; forgetting FROM DUAL on Oracle scalar selects; test data introducing duplicates.","solutions":["Constrain the selectKey SQL to one row: use aggregates (MAX), LIMIT 1 / FETCH FIRST 1 ROWS ONLY, or a proper sequence","Add uniqueness guarantees (unique index) for lookup-based key strategies","Test the selectKey SQL in a DB client against production-like data"],"exampleFix":"<!-- before -->\n<selectKey keyProperty=\"id\" resultType=\"long\" order=\"BEFORE\">\n  SELECT id FROM codes WHERE name = #{name}\n</selectKey>\n\n<!-- after -->\n<selectKey keyProperty=\"id\" resultType=\"long\" order=\"BEFORE\">\n  SELECT id FROM codes WHERE name = #{name} LIMIT 1\n</selectKey>","handlingStrategy":"validation","validationCode":"// For lookup-based selectKeys, assert uniqueness first\nInteger count = jdbcTemplate.queryForObject(\"SELECT COUNT(*) FROM codes WHERE name=?\", Integer.class, name);\nif (count != null && count > 1) throw new IllegalStateException(\"selectKey lookup not unique\");","typeGuard":null,"tryCatchPattern":"try { mapper.insert(entity); } catch (PersistenceException e) { if (String.valueOf(e.getMessage()).contains(\"more than one value\")) { /* constrain the selectKey query */ } throw e; }","preventionTips":["Constrain selectKey SQL with aggregates or LIMIT 1","Add unique indexes for columns used in key lookups"],"tags":["selectkey","insert","sql"],"backgroundTag":null,"analyzedSha":"008069adb1b089579b5dcba87ee591908b263274","analyzedAt":"2026-08-14T13:07:10.264Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}