将内部连接的结果限制为 1
Limit result of inner join to 1
我有这个架构:
create table ord(id int);
create table orderpos(id int, orderid int, descr varchar(255));
insert into ord(id) values (1);
insert into ord(id) values (2);
insert into orderpos(id, orderid, descr) values(1,1,'huba');
insert into orderpos(id, orderid, descr) values(2,1,'blub');
insert into orderpos(id, orderid, descr) values(3,2,'foo');
所以数据顺序如下:
id
1
2
按顺序pos:
id orderid descr
1 1 huba
2 1 blub
3 2 foo
我想要:
oId opId orderid descr
1 1 1 huba
2 3 2 foo
但是对于这个查询:
select o.id as oId, op.id as opId, op.orderid, op.descr from ord o
inner join orderpos op on op.orderid = o.id;
我得到:
oId opId orderid descr
1 1 1 huba
1 2 1 blub
2 3 2 foo
所以我必须以某种方式限制 innerjoin,但是如何?我尝试了通过 google 找到的几种方法,但似乎没有任何效果。
这似乎适用于 SQL-W3-Schools 的编辑:
select o.id as oId, op.id as opId, op.orderid, op.descr
from ord o
inner join (select * from orderpos op2 group by op2.orderid) op on op.orderid = o.id;
在我看来,只要您在 'descr' 中有不同的值,它就不起作用,这似乎合乎逻辑。不知道为什么这在 W3Schools 的 SQL-Editor 中有效。
Sybase 版本:Adaptive Server Enterprise/15.5/EBF 19902 SMP ESD#5.1/P/x86_64/Enterprise Linux/asear155/2594/64-bit/FBO/Wed 6 月 6 日 01:20:27 2012
你可以使用 exists
select
o.id as oId,
op.id as opId,
op.orderid,
op.descr
from
ord o inner join
orderpos op
on
op.orderid = o.id and
not exists
(select 1 from orderpos op2 where op2.orderid = o.id and op2.id < op.id)
您可以 select 第一行或第一行 row_number fucntion
WITH x
AS (
SELECT o.id AS oId
,op.id AS opId
,op.orderid
,op.descr
,row_number() OVER (
PARTITION BY orderid ORDER BY orderid
) rows
FROM ord o
INNER JOIN orderpos op
ON op.orderid = o.id
)
SELECT otd
,opid
,orderid
,DESC
FROM x
WHERE row = 1
由于没有提供逻辑来确定哪一行是 'first record'(请参阅@HoneyBadger 的评论),并且您评论说排序对您的业务案例不重要,我们将使用 max( ) 为每个唯一的 orderid 提取一行:
select o.id as oId,
op.id as opId,
op.orderid,
op.descr
from ord o,
orderpos op,
(select op2.orderid,
max(op2.descr) as descr
from orderpos op2
group by op2.orderid
) dt
where op.orderid = o.id
and op.orderid = dt.orderid
and op.descr = dt.descr
order by 1,2
go
oId opId orderid descr
------- ------- -------- ----------
1 1 1 huba
2 3 2 foo
ord(o) 和 orderpos(op) 之间的连接条件保持不变;添加派生的 table (dt) 允许我们进一步限制来自 orderpos(op).
感兴趣的行
在这种情况下,我们使用 max() 生成您正在寻找的输出只是巧合。 [提示:将 max() 替换为 min() 以显示“2/blub”而不是“1/huba”。]
相同的想法,但使用相关的子查询而不是派生的 table:
select o.id as oId,
op.id as opId,
op.orderid,
op.descr
from ord o,
orderpos op
where op.orderid = o.id
and op.descr = (select max(op2.descr)
from orderpos op2
where op2.orderid = op.orderid)
order by 1,2
go
oId opId orderid descr
------- ------- -------- ----------
1 1 1 huba
2 3 2 foo
或者我们可以将 max(op2.descr) 替换为 max(op2.id).
关键问题是选择某种方法……在这种情况下的任何方法……允许我们从 op2 中为给定的 orderid 选择一行(通过 group by op2.orderid).
注意:只要给定的 descr 值对于给定的 orderid 是唯一的,建议的解决方案就可以工作(例如,您不能在 orderpos 中有 2x 行具有相同的 orderid 和 descr)。如果这是一个无效的假设,那么我们将需要更多样本数据 and/or 更好地描述 orderpos table 中的数据(例如,pk 约束、唯一索引等)。
这就是 CROSS APPLY
的用途:
SELECT o.id as oId, op.id as opId, op.orderid, op.descr
FROM ord AS o
CROSS APPLY ( SELECT TOP (1) *
FROM orderpos AS op
WHERE op.orderid = o.id
ORDER BY op.id) AS op;
它是子查询和连接的混合体。它让您 return 多列和多行用于基于行的条件。
编辑。注意到它不是对 SQL 服务器的请求,因此 CROSS APPLY
将不起作用,但这通常被称为 LATERAL JOIN
,Sybase 似乎支持它:http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.help.sqlanywhere.12.0.1/dbreference/from-statement.html
文档具有以下语法:
SELECT *
FROM A, LATERAL( SELECT * FROM B WHERE A.x = B.x ) LDT;
所以也许这应该有效:
SELECT *
FROM ord, LATERAL( SELECT TOP 1 * FROM orderpos WHERE orderpos.orderid = ord.id) LDT;
我有这个架构:
create table ord(id int);
create table orderpos(id int, orderid int, descr varchar(255));
insert into ord(id) values (1);
insert into ord(id) values (2);
insert into orderpos(id, orderid, descr) values(1,1,'huba');
insert into orderpos(id, orderid, descr) values(2,1,'blub');
insert into orderpos(id, orderid, descr) values(3,2,'foo');
所以数据顺序如下:
id
1
2
按顺序pos:
id orderid descr
1 1 huba
2 1 blub
3 2 foo
我想要:
oId opId orderid descr
1 1 1 huba
2 3 2 foo
但是对于这个查询:
select o.id as oId, op.id as opId, op.orderid, op.descr from ord o
inner join orderpos op on op.orderid = o.id;
我得到:
oId opId orderid descr
1 1 1 huba
1 2 1 blub
2 3 2 foo
所以我必须以某种方式限制 innerjoin,但是如何?我尝试了通过 google 找到的几种方法,但似乎没有任何效果。
这似乎适用于 SQL-W3-Schools 的编辑:
select o.id as oId, op.id as opId, op.orderid, op.descr
from ord o
inner join (select * from orderpos op2 group by op2.orderid) op on op.orderid = o.id;
在我看来,只要您在 'descr' 中有不同的值,它就不起作用,这似乎合乎逻辑。不知道为什么这在 W3Schools 的 SQL-Editor 中有效。
Sybase 版本:Adaptive Server Enterprise/15.5/EBF 19902 SMP ESD#5.1/P/x86_64/Enterprise Linux/asear155/2594/64-bit/FBO/Wed 6 月 6 日 01:20:27 2012
你可以使用 exists
select
o.id as oId,
op.id as opId,
op.orderid,
op.descr
from
ord o inner join
orderpos op
on
op.orderid = o.id and
not exists
(select 1 from orderpos op2 where op2.orderid = o.id and op2.id < op.id)
您可以 select 第一行或第一行 row_number fucntion
WITH x
AS (
SELECT o.id AS oId
,op.id AS opId
,op.orderid
,op.descr
,row_number() OVER (
PARTITION BY orderid ORDER BY orderid
) rows
FROM ord o
INNER JOIN orderpos op
ON op.orderid = o.id
)
SELECT otd
,opid
,orderid
,DESC
FROM x
WHERE row = 1
由于没有提供逻辑来确定哪一行是 'first record'(请参阅@HoneyBadger 的评论),并且您评论说排序对您的业务案例不重要,我们将使用 max( ) 为每个唯一的 orderid 提取一行:
select o.id as oId,
op.id as opId,
op.orderid,
op.descr
from ord o,
orderpos op,
(select op2.orderid,
max(op2.descr) as descr
from orderpos op2
group by op2.orderid
) dt
where op.orderid = o.id
and op.orderid = dt.orderid
and op.descr = dt.descr
order by 1,2
go
oId opId orderid descr
------- ------- -------- ----------
1 1 1 huba
2 3 2 foo
ord(o) 和 orderpos(op) 之间的连接条件保持不变;添加派生的 table (dt) 允许我们进一步限制来自 orderpos(op).
感兴趣的行在这种情况下,我们使用 max() 生成您正在寻找的输出只是巧合。 [提示:将 max() 替换为 min() 以显示“2/blub”而不是“1/huba”。]
相同的想法,但使用相关的子查询而不是派生的 table:
select o.id as oId,
op.id as opId,
op.orderid,
op.descr
from ord o,
orderpos op
where op.orderid = o.id
and op.descr = (select max(op2.descr)
from orderpos op2
where op2.orderid = op.orderid)
order by 1,2
go
oId opId orderid descr
------- ------- -------- ----------
1 1 1 huba
2 3 2 foo
或者我们可以将 max(op2.descr) 替换为 max(op2.id).
关键问题是选择某种方法……在这种情况下的任何方法……允许我们从 op2 中为给定的 orderid 选择一行(通过 group by op2.orderid).
注意:只要给定的 descr 值对于给定的 orderid 是唯一的,建议的解决方案就可以工作(例如,您不能在 orderpos 中有 2x 行具有相同的 orderid 和 descr)。如果这是一个无效的假设,那么我们将需要更多样本数据 and/or 更好地描述 orderpos table 中的数据(例如,pk 约束、唯一索引等)。
这就是 CROSS APPLY
的用途:
SELECT o.id as oId, op.id as opId, op.orderid, op.descr
FROM ord AS o
CROSS APPLY ( SELECT TOP (1) *
FROM orderpos AS op
WHERE op.orderid = o.id
ORDER BY op.id) AS op;
它是子查询和连接的混合体。它让您 return 多列和多行用于基于行的条件。
编辑。注意到它不是对 SQL 服务器的请求,因此 CROSS APPLY
将不起作用,但这通常被称为 LATERAL JOIN
,Sybase 似乎支持它:http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.help.sqlanywhere.12.0.1/dbreference/from-statement.html
文档具有以下语法:
SELECT *
FROM A, LATERAL( SELECT * FROM B WHERE A.x = B.x ) LDT;
所以也许这应该有效:
SELECT *
FROM ord, LATERAL( SELECT TOP 1 * FROM orderpos WHERE orderpos.orderid = ord.id) LDT;