Sequelize:两次加入同一张表
Posted
技术标签:
【中文标题】Sequelize:两次加入同一张表【英文标题】:Sequelize: join two times the same table 【发布时间】:2016-04-05 10:09:42 【问题描述】:背景:
我有一个表 Users
与 Userlang
具有一对多关系。例如:
userlang.id userlang.userid userlang.lang
+-----------+---------------+-------------+
1 1 EN
2 1 FR
3 1 IT
4 2 EN
5 2 DE
6 3 IT
我想选择所有用户及其用户语言至少有一个userlang.lang=EN.
所以,我不能使用以下查询:
Select USERS.id from USERS inner join USERLANG on USERS.ID=USERLANG.USERID where USERLANG.LANG="EN"
因为它只会选择带有lang="EN"
的Userlangs
行,而我想选择每个用户的所有userlang
行,其中至少一个有lang="EN"
我已经能够使用 SQL 以两种方式编写这样的查询:
使用子查询:
Select *
from USERS inner join USERLANG on USERS.ID=USERLANG.USERID
where USERS.ID in (
Select USERS.id
from USERS inner join USERLANG on USERS.ID=USERLANG.USERID
where USERLANG.LANG="EN"
)
虽然内部查询将只选择带有lang="EN"
的用户语言行,但外部查询将为此类用户选择所有userlangs
。
使用同一张表的两个内连接:
Select *
from USERS innerjoin USERLANG as FILTER on FILTER.userid=USERS.userid
inner join USERLANG on USERLANG.userid=FILTER.userid
where FILTER.lang="EN"
问题:将它们移植到 sequelize
我完全无法在 sequelize 上编写子查询:我想避免编写纯 SQL,因为它会打开可能的注入攻击。
这是我失败的尝试,由于“过滤器”与用户没有关系而导致错误:
models.User.findAll(
include:[models.Userlang,model:models.Userlang,as:'FILTER']
)
【问题讨论】:
您提到子查询不适用于 Sequelize,但是您的联接查询呢? @TimBiegeleisen,在问题的最后,我尝试加入查询。 Sequelize 会报错,因为FILTER
与 ORM 模型中的 Users
没有关联。看来我无法进行任意连接。
【参考方案1】:
select userid,lang
from t
where userid in (
select userid
from t where lang="en"
group by userid having count(lang)>=1)
select a.userid,a.lang
from t a left join ( select userid,lang from t where lang ="en") b
on a.userid=b.userid
where b.lang is not null
不确定您的问题是什么,但也可以通过分两步来获得相同的结果;用临时表替换子查询。
【讨论】:
【参考方案2】:尝试用一些别名来定义你的关联:
List.belongsTo(Task,
as: 'dailyTask',
foreignKey: 'dailyTask'
);
List.belongsTo(Task,
as: 'weeklyTask',
foreignKey: 'weeklyTask'
);
创建者的示例在此链接中: https://github.com/sequelize/sequelize/issues/3678
【讨论】:
【参考方案3】:这是一个非常古老的帖子,但希望这可以为某人提供有用的答案。有很多方法可以实现这一点,包括一些原始的续集选项。
但是,假设这是一个可重用的参考,我会尝试将 [USERLANG] 上的关联与 [USERLANG] 关联并基于此进行查询。这会修改模型,因此对于一次性查询来说可能有点多。
models.UserLang.hasMany(models.UserLang, as: 'Filter', foreignKey: 'UserId', targetKey: 'UserId');
models.User.findAll(
include:[ model: models.Userlang,
required: true,
include:[ model: models.Userlang,
required: true, // redundant
as: 'Filter',
where: lang: 'EN'
]
]
)
您还可以在 attributes
列表中放置一个原始 SQL 子查询(使用 sequelize.literal()
),并使用 where
子句根据结果进行过滤。那将是一种不需要修改模型的一次性解决方案。但这确实可以追溯到您对原始 SQL 的厌恶。
【讨论】:
以上是关于Sequelize:两次加入同一张表的主要内容,如果未能解决你的问题,请参考以下文章