{"record":{"id":"48e61bf4dec82f16","repo":"greenrobot/greenDAO","slug":"joins-are-not-supported-for-delete-queries","errorCode":null,"errorMessage":"JOINs are not supported for DELETE queries","messagePattern":"JOINs are not supported for DELETE queries","errorType":"exception","errorClass":"DaoException","httpStatus":null,"severity":"error","filePath":"DaoCore/src/main/java/org/greenrobot/greendao/query/QueryBuilder.java","lineNumber":348,"sourceCode":"        int offsetPosition = -1;\n        if (offset != null) {\n            if (limit == null) {\n                throw new IllegalStateException(\"Offset cannot be set without limit\");\n            }\n            builder.append(\" OFFSET ?\");\n            values.add(offset);\n            offsetPosition = values.size() - 1;\n        }\n        return offsetPosition;\n    }\n\n    /**\n     * Builds a reusable query object for deletion (Query objects can be executed more efficiently than creating a\n     * QueryBuilder for each execution.\n     */\n    public DeleteQuery<T> buildDelete() {\n        if (!joins.isEmpty()) {\n            throw new DaoException(\"JOINs are not supported for DELETE queries\");\n        }\n        String tablename = dao.getTablename();\n        String baseSql = SqlUtils.createSqlDelete(tablename, null);\n        StringBuilder builder = new StringBuilder(baseSql);\n\n        // tablePrefix gets replaced by table name below. Don't use tableName here because it causes trouble when\n        // table name ends with tablePrefix.\n        appendJoinsAndWheres(builder, tablePrefix);\n\n        String sql = builder.toString();\n        // Remove table aliases, not supported for DELETE queries.\n        // TODO(?): don't create table aliases in the first place.\n        sql = sql.replace(tablePrefix + \".\\\"\", '\"' + tablename + \"\\\".\\\"\");\n        checkLog(sql);\n\n        return DeleteQuery.create(dao, sql, values.toArray());\n    }\n","sourceCodeStart":330,"sourceCodeEnd":366,"githubUrl":"https://github.com/greenrobot/greenDAO/blob/0bbb338e17c4cf28aba5aae62d42f73f50186157/DaoCore/src/main/java/org/greenrobot/greendao/query/QueryBuilder.java#L330-L366","documentation":"DELETE statements in SQL cannot reference joined tables, so QueryBuilder.buildDelete() rejects any builder that has joins registered. The library throws a DaoException early rather than emitting invalid SQL. DeleteQuery only supports single-table deletes with where conditions.","triggerScenarios":"Calling queryBuilder.join(...)...buildDelete() — i.e. buildDelete() on a QueryBuilder where joins is non-empty (from join(Class, Property) calls).","commonSituations":"Developers write a SELECT with a JOIN to filter rows, then call buildDelete() on the same builder expecting it to delete the matched rows; joins are valid for select queries only.","solutions":["Rewrite the delete using a subquery-style condition (e.g. where(Property.in(...query with join...))) — build the joined select as a separate query collecting keys, then delete with where(key.in(keys)).","Execute raw SQL via the database handle if a correlated multi-table delete is required.","Loop over the joined SELECT results and delete each entity individually (slower but simple)."],"exampleFix":"// before\nQueryBuilder<User> qb = userDao.queryBuilder();\nqb.join(DeptDao.class, UserDao.Properties.DeptId)\n  .where(DeptDao.Properties.Name.eq(\"old\"));\nqb.buildDelete(); // DaoException\n// after\nList<Long> ids = userDao.queryBuilder()\n  .join(DeptDao.class, UserDao.Properties.DeptId)\n  .where(DeptDao.Properties.Name.eq(\"old\"))\n  .list() // collect matching users\n  .stream().map(User::getId).collect(toList());\nuserDao.deleteByKeyInTx(ids);","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { qb.buildDelete().executeDeleteWithoutDetachingEntities(); } catch (DaoException e) { deleteByKeyInTx(collectKeysViaJoinedSelect()); }","preventionTips":["Treat buildDelete() as single-table only; keep joins on select builders.","Collect matching keys with a joined select, then deleteByKeyInTx().","Document this constraint in query-building helpers."],"tags":["greendao","sql","delete","android"],"backgroundTag":"unsupported-operation","analyzedSha":"0bbb338e17c4cf28aba5aae62d42f73f50186157","analyzedAt":"2026-09-08T03:22:36.050Z","contentChangedAt":"2026-09-08T03:22:36.050Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}