LIMIT of query placed in subquery when using include
See original GitHub issueThis is related to #6025
The situation
I have simplified the ‘issue’ to this: Say I have a Book, a Book has one or more authors. Authors have written one or more books. I want to do count and get all Books that are written by authors with the name ‘Scott’ in their name field.
The code
Book model:
var Book = sequelize.define('book', {
title: Sequelize.STRING,
description: Sequelize.TEXT
})
Author model:
var Author= sequelize.define('author', {
name: Sequelize.STRING,
})
Associations:
Book.belongsToMany(Author, {as: 'authors', foreignKey: 'book_id', through: 'j_author_book'});
Author.belongsToMany(Book, {as: 'books', foreignKey: 'author_id', through: 'j_author_book'});
Query:
Book.findAndCountAll({
limit: 15,
include: [ {model: Author, as: 'authors', where: {name: {$like: '%' + 'Scott' + '%'}}, order: [ ['name', 'ASC'] ]}
})
What do you expect to happen?
I expect 2 queries: 1: A count (this works, it is not the point) 2: A select that gets me the first 15 results that apply to the ‘%Scott%’ LIKE in the include statement.
What is actually happening?
I get a COUNT that for example says ‘5’ while the actual get query gives me no results. I have tracked this down to how sequelize seems to generate a subquery and puts the LIMIT in that subquery instead of in the parent query. See below for the SQL it generates. This would mean it would effectively ‘look in the first 15 books and then apply the ‘Scott’ LIKE statement to those 15’ even though the database might have hundreds of books. I have simplified the query slightly.
I have also ran a few scenarios where I left out the LIMIT (it works then) but also where I left out the LIKE (it works then as well), but if both are present, wham, no result.
SELECT
`Book`.*
FROM
(
SELECT
`Book`.*
FROM
`books` AS `Book`
WHERE
(
`Book`.`deleted_at` >= CURRENT_TIMESTAMP
OR `Book`.`deleted_at` IS NULL
)
AND (
SELECT
`j_author_book`.`author_id`
FROM
`j_author_book` AS `j_author_book`
INNER JOIN `authors` AS `Author` ON `j_author_book`.`author_id` = `Author`.`id`
WHERE
(
`Book`.`id` = `j_author_book`.`book_id`
)
LIMIT
1
) IS NOT NULL
ORDER BY
`Book`.`title` asc
LIMIT
0, 15 # <---- THIS IS THE PROBLEM
) AS `Scenario`
INNER JOIN (
`j_author_book` AS `authors.j_author_book`
INNER JOIN `authors` AS `authors` ON `authors`.`id` = `authors.j_author_book`.`author_id`
) ON `Book`.`id` = `authors.j_author_book`.`book_id`
AND (
(
`authors`.`deleted_at` >= CURRENT_TIMESTAMP
OR `authors`.`deleted_at` IS NULL
)
AND `authors`.`name` LIKE '%Scott%'
)
ORDER BY
`Book`.`title` asc
Dialect: mysql (not tested with anything else) Database version: MySQL 5.6 Sequelize version: Most recent build on github: https://github.com/sequelize/sequelize/commit/cc4ee8b86f656f9706e1dbf3a5d5600333f8975b
Why I referenced the other issue at the top
The situation seems more or less the same and adding ‘duplicating: false’ to the include DOES fix it, because it will remove the subquery. That issue did not seem to actually lead to a fix for the problem though. My opinion is that sequelize is placing that LIMIT in the wrong place and using ‘duplicating: false’ to work around it does not seem like a solution to me. With all due respect of course. 😃
Issue Analytics
- State:
- Created 7 years ago
- Reactions:7
- Comments:10 (2 by maintainers)
@suksin subQuery: false did the trick for me.
I also noticed, that if you have two includes, both must have
duplicating: false
.Following call will give an error: