Reputation: 12188
I have this schema:
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');
So the data in ord looks like:
id
1
2
and in orderpos:
id orderid descr
1 1 huba
2 1 blub
3 2 foo
I'd like to have:
oId opId orderid descr
1 1 1 huba
2 3 2 foo
but with this query:
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;
I get:
oId opId orderid descr
1 1 1 huba
1 2 1 blub
2 3 2 foo
So somehow I have to limit the innerjoin, but how? I tried severel approaches found via google, but nothing seems to work.
This seems to work in SQL-Editor of 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;
And it seems logical to me that it doesn't work as long as you have different values in 'descr'. No clue why this works in the SQL-Editor on W3Schools.
Sybase version: Adaptive Server Enterprise/15.5/EBF 19902 SMP ESD#5.1/P/x86_64/Enterprise Linux/asear155/2594/64-bit/FBO/Wed Jun 6 01:20:27 2012
Upvotes: 1
Views: 3324
Reputation: 14097
That's what CROSS APPLY
is used for:
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;
It's a mix of a sub-query and a join. It let's you return multiple columns and rows for a row based condition.
EDIT. Noticed that it's not a request for SQL Server, therefore CROSS APPLY
will not work, but this is normally being called a LATERAL JOIN
, which seems to be supported by Sybase: http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.help.sqlanywhere.12.0.1/dbreference/from-statement.html
Documentation has following syntax:
SELECT *
FROM A, LATERAL( SELECT * FROM B WHERE A.x = B.x ) LDT;
So perhaps this should work:
SELECT *
FROM ord, LATERAL( SELECT TOP 1 * FROM orderpos WHERE orderpos.orderid = ord.id) LDT;
Upvotes: 0
Reputation: 35451
Since no logic has been provided for determining which row is the 'first record' (see @HoneyBadger's comments), and you've commented that ordering is not important for your business case, we'll use max() to extract a single row per unique 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
Your join criteria between ord(o) and orderpos(op) remains the same; the addition of the derived table (dt) allows us to further limit the rows that are of interest from orderpos(op).
In this case it's just a coincidence that our use of max() generated the output you're looking for. [HINT: replace max() with min() to display '2/blub' instead of '1/huba'.]
Same idea but using a correlated sub-query instead of a derived 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
Alternatively we could have replaced max(op2.descr) with max(op2.id).
The key issue being to pick some method ... any method in this case ... that allows us to pick a single row from op2 for a given orderid (via the group by op2.orderid).
NOTE: The proposed solutions work as long a given descr value is unique for a given orderid (eg, you can't have 2x rows in orderpos with the same orderid and descr). If this is an invalid assumption then we'll need more sample data and/or a better description of the data in the orderpos table (eg, pk contraint, unique index, etc).
Upvotes: 2
Reputation: 183
You can use 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)
Upvotes: 0
Reputation: 2014
You can select first row or one row by 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
Upvotes: 0