在 sql 中是否可以根据数据子集执行连接?
Is it possible in sql to perform joins based on a subsets of data?
我 运行 遇到了一个问题,我误解了什么是左连接,而且我真的不知道如何表达这个问题。我下面有一个 MVCE
declare @matchableproperties table
(
pname varchar(100)
)
declare @users table
(
userid varchar(100),
pname varchar(100),
pvalue varchar(100)
)
insert into @matchableproperties values ('city')
insert into @matchableproperties values ('status')
insert into @matchableproperties values ('position')
insert into @users values (1, 'city', 'Wichita')
insert into @users values (1, 'status', 'Active')
insert into @users values (1, 'position', 'Captain')
insert into @users values (2, 'city', 'Wichita')
insert into @users values (2, 'status', 'Active')
select u.*, mp.* from @matchableproperties mp
left join @users u on mp.pname = u.pname
order by userid, mp.pname
哪个returns
u.userid
u.pname
u.pvalue
mp.pname
1
city
Wichita
city
1
position
Captain
position
1
status
Active
status
2
city
Wichita
city
2
status
Active
status
我的问题在于我要实现的目标。我想知道,对于每个用户 ID,哪些 pname 存在,哪些 pname 不存在。例如,对于用户 ID 2,“位置”pname 不存在,所以我想在下面添加一行以显示用户 ID 2 在所有指定属性上都不匹配。
u.userid
u.pname
u.pvalue
mp.pname
2
null
null
position
考虑之后,我意识到我想对用户的各个分区进行左连接 table——本质上我想要
的结果
select u.*, mp.* from @matchableproperties mp
left join (select * from @users where userid = 1) u on mp.pname = u.pname
union all
select u.*, mp.* from @matchableproperties mp
left join (select * from @users where userid = 2) u on mp.pname = u.pname
上面的查询给了我想要的结果(上面的两个 tables,总共六行),但是因为我不知道有多少用户将成为用户 table 我显然不能硬编码。我可以在左连接上使用一些神奇的“分区依据”或“分组依据”语法,从两个 tables 上的单个左连接语句中获取我想要的内容吗?
您需要 属性 和用户的所有可能组合的投影。那是 CROSS JOIN
。获得此投影后,您可以通过 LEFT JOIN 返回用户 table 以查看实际匹配的内容:
SELECT u0.userid, mp.pname, u.pvalue
FROM (
SELECT DISTINCT pname FROM @matchableproperties
) mp
CROSS JOIN (
SELECT DISTINCT userid FROM @users
) u0
LEFT JOIN @users u on u.userid = u0.userid and u.pname = mp.pname
在这里查看它的工作原理:
https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=533c75a50d6627fdc831b77c5dea47d3
交叉连接的需要往往会占用数据库服务器上的大量内存和资源,这是最好避免使用此类 EAV 模式的几个原因之一。
我 运行 遇到了一个问题,我误解了什么是左连接,而且我真的不知道如何表达这个问题。我下面有一个 MVCE
declare @matchableproperties table
(
pname varchar(100)
)
declare @users table
(
userid varchar(100),
pname varchar(100),
pvalue varchar(100)
)
insert into @matchableproperties values ('city')
insert into @matchableproperties values ('status')
insert into @matchableproperties values ('position')
insert into @users values (1, 'city', 'Wichita')
insert into @users values (1, 'status', 'Active')
insert into @users values (1, 'position', 'Captain')
insert into @users values (2, 'city', 'Wichita')
insert into @users values (2, 'status', 'Active')
select u.*, mp.* from @matchableproperties mp
left join @users u on mp.pname = u.pname
order by userid, mp.pname
哪个returns
u.userid | u.pname | u.pvalue | mp.pname |
---|---|---|---|
1 | city | Wichita | city |
1 | position | Captain | position |
1 | status | Active | status |
2 | city | Wichita | city |
2 | status | Active | status |
我的问题在于我要实现的目标。我想知道,对于每个用户 ID,哪些 pname 存在,哪些 pname 不存在。例如,对于用户 ID 2,“位置”pname 不存在,所以我想在下面添加一行以显示用户 ID 2 在所有指定属性上都不匹配。
u.userid | u.pname | u.pvalue | mp.pname |
---|---|---|---|
2 | null | null | position |
考虑之后,我意识到我想对用户的各个分区进行左连接 table——本质上我想要
的结果select u.*, mp.* from @matchableproperties mp
left join (select * from @users where userid = 1) u on mp.pname = u.pname
union all
select u.*, mp.* from @matchableproperties mp
left join (select * from @users where userid = 2) u on mp.pname = u.pname
上面的查询给了我想要的结果(上面的两个 tables,总共六行),但是因为我不知道有多少用户将成为用户 table 我显然不能硬编码。我可以在左连接上使用一些神奇的“分区依据”或“分组依据”语法,从两个 tables 上的单个左连接语句中获取我想要的内容吗?
您需要 属性 和用户的所有可能组合的投影。那是 CROSS JOIN
。获得此投影后,您可以通过 LEFT JOIN 返回用户 table 以查看实际匹配的内容:
SELECT u0.userid, mp.pname, u.pvalue
FROM (
SELECT DISTINCT pname FROM @matchableproperties
) mp
CROSS JOIN (
SELECT DISTINCT userid FROM @users
) u0
LEFT JOIN @users u on u.userid = u0.userid and u.pname = mp.pname
在这里查看它的工作原理:
https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=533c75a50d6627fdc831b77c5dea47d3
交叉连接的需要往往会占用数据库服务器上的大量内存和资源,这是最好避免使用此类 EAV 模式的几个原因之一。