Sequelize - where 子句中的子查询

问题描述 投票:0回答:3

我在 Express 应用程序中使用 Sequelize。我需要生成一个在

WHERE
子句中有子查询的查询。

SELECT *
  FROM MyTable
 WHERE id NOT IN (
       SELECT fkey
         FROM MyOtherTable
        WHERE field1 = 1
          AND field2 = 2
          AND field3 = 3
       )

我首先尝试通过我的模型建立关系/关联,但无法使其发挥作用。比如:

MyTable.find( {
    where: {
        id: {
            $notIn: // <= what goes here? Can I somehow reference my include model?
        }
    },
    include: [ {
        model: MyOtherTable,
        where: {
          field1: 1,
          field2: 2,
          field3: 3
    } ]
} );

然后我尝试使用

Sequelize.where()
,但没有运气。

然后我尝试了

Sequelize.literal()
,这可行,但不确定这是否是在Sequelize中的where子句中执行子查询的“正确”方式,因为我是新手。

MyTable.find( {
    where: {
        id: {
            $notIn: sequelize.literal( 
                '( SELECT fkey ' +
                    'FROM MyOtherTable ' +
                   'WHERE field1 = ' + field1 +
                    ' AND field2 = ' + field2 +
                    ' AND field3 = ' + field3 + 
                ')'
        }
    } 
} );

我也知道我可以使用

Sequelize.query()
,但真的不知道我是否应该使用它,或者
literal()
是否是正确的,因为我觉得有一些我忽略的东西。

我真的很想知道如何在

WHERE
子句中使用 Sequelize 以 “正确” 的方式执行子查询。

感谢您的反馈!

orm subquery where-clause sequelize.js
3个回答
54
投票

我在项目中也遇到过类似的问题。 我选择的实现方式有点不同,原因有两个:

  1. 如果在某个时间点 Sequelize 决定实现子查询 - 语法已准备就绪。
  2. 使用 Sequelize 防护 SQL 注入。

这是我的代码片段,希望有帮助。

续集 v5

const tempSQL = sequelize.dialect.QueryGenerator.selectQuery('MyOtherTable',{
    attributes: ['fkey'],
    where: {
          field1: 1,
          field2: 2,
          field3: 3
    }})
    .slice(0,-1); // to remove the ';' from the end of the SQL

MyTable.find( {
    where: {
        id: {
              [Sequelize.Op.notIn]: sequelize.literal(`(${tempSQL})`)
        }
    } 
} );

续集 v6

const tempSQL = sequelize.dialect.queryGenerator.selectQuery('MyOtherTable',{
    attributes: ['fkey'],
    where: {
          field1: 1,
          field2: 2,
          field3: 3
    }})
    .slice(0,-1); // to remove the ';' from the end of the SQL

MyTable.find( {
    where: {
        id: {
              [Sequelize.Op.notIn]: sequelize.literal(`(${tempSQL})`)
        }
    } 
} );

有些人可能选择不使用 tempSQL 变量,而只是在 find 结构中构建 SQL(也许使用辅助方法?)

我还认为这可能是sequelize子查询扩展的基础,因为它几乎使用相同的语法。


4
投票

除了@Shahar Hadas 的回答之外,因为我使用他展示的代码遇到了一些错误。

这是一个更复杂的例子。在此示例中,我们有一个名为“Artist”的主表,与“Tag”存在多对多关系。 “标签”与名为“TagType”的预定义标签列表相关联。 我们想要获取链接到所有搜索标签的所有艺术家(TagType Id)。

const tagsSearched = [1, 2];

const subQueryOptions = {
    attributes: ['id'], // You have to list at least one attribute
    include: [
        {
            model: models.Tag,
            required: true,
            attributes: [], // Avoid the only_full_group_by error
            through: {
                attributes: [], // Avoid the only_full_group_by error
            },
            include: {
                model: models.TagType,
                required: true,
                attributes: [], // Avoid the only_full_group_by error
                where: {
                    id: {
                        [Op.in]: tagsSearched, // Array of tags searched
                    }
                },
            },
        }
            ],
    group: sequelize.col('artist.id'), // Group by the main parent ID of this query
    having: sequelize.where(sequelize.fn('count', 
            sequelize.col('tags.tagType.id')), {
                [Op.gte]: tagsSearched.length,
    }), // Get only the artists that have at least the "tagsSearched" associated
}

// Parse the subQueryOptions, this operation would serialize the queryOptions
Model._validateIncludedElements.bind(models.Artist)(subQueryOptions);

// First argument has to be a string (table name, by default in plural)
// Second argument is our serialized query options
// Third argument is the model used
const artistsSubQuery = sequelize.dialect.queryGenerator.selectQuery("artists", subQueryOptions, models.Artist)
.slice(0,-1); // to remove the ';' from the end of the SQL query

models.Artist.findAll({
    where: {
        id: {
            [Op.in]: sequelize.literal(`(${artistsSubQuery})`),
        }
    }
});

如果有问题我会更新。


0
投票

如果主where子句中的id来自左连接模型怎么办?我的案例还需要检查左连接模型属性的条件

© www.soinside.com 2019 - 2024. All rights reserved.