2009-04-21 48 views
9

Tôi chỉ cần chọn hàng đầu tiên từ truy vấn tham gia bảng A và B. Trên bảng B tồn tại nhiều bản ghi có cùng tên. Không có số nhận dạng nào trong hai bảng. Tôi không thể thay đổi chương trình vì tôi không sở hữu DB.Chọn hàng đầu tiên trong một kết hợp của hai bảng trong một câu lệnh

TABLE A 
NAME 

TABLE B 
NAME 
DATA1 
DATA2 

Select Distinct A.NAME,B.DATA1,B.DATA2 
From A 
Inner Join B on A.NAME = B.NAME 

này mang lại cho tôi

NAME  DATA1 DATA2 
sameName 1  2 
sameName 1  3 
otherName 5  7 
otherName 8  9 

nhưng tôi cần phải lấy chỉ có một hàng cho mỗi tên

NAME  DATA1 DATA2 
sameName 1  2 
otherName 5  7 

tôi đã có thể làm điều này bằng cách thêm kết quả vào một bảng tạm thời với một cột nhận dạng và sau đó chọn id tối thiểu cho mỗi tên.

Vấn đề ở đây là tôi yêu cầu thực hiện điều này trong một câu lệnh duy nhất.

Trả lời

0

Không chắc chắn điều này có giải quyết được sự cố của bạn hay không, nhưng bạn có thể thử sử dụng mệnh đề GROUP BY và nhóm theo một trong các cột tên.

DB2 Group by tutorial

7

Sử dụng GROUP BY có thể giúp bạn một phần, nhưng hãy cẩn thận. Nếu bạn làm điều gì đó như thế này:

Select A.NAME, min(B.DATA1), min(B.DATA2) 
From A Inner Join B on A.NAME = B.NAME 
Group by A.NAME; 

Bạn sẽ nhận được kết quả bạn đang tìm kiếm:

NAME  DATA1 DATA2 
    sameName 1  2  
    otherName 5  7 

Nhưng chỉ vì các dữ liệu bạn đang thử nghiệm với. Nếu bạn thay đổi dữ liệu, do đó thay vì:

otherName 8  9 

bạn có:

otherName 8  4 

Nó sẽ trở lại:

NAME  DATA1 DATA2 
    sameName 1  2  
    otherName 5  4 

Lưu ý rằng otherName không trả lại data1 và data2 từ cùng một kỷ lục!

Cập nhật: Một tự tham gia với một sự so sánh trên một trong các giá trị dữ liệu có thể giúp bạn, chẳng hạn như:

SELECT a.*, b.* FROM a,b 
    LEFT JOIN b b2 ON b.name = b2.name AND b.data2 < b2.data2 
    WHERE a.name = b.name AND b2.data2 IS NOT NULL; 

Tuy nhiên, điều này chỉ sẽ làm việc nếu các giá trị trong data2 là duy nhất cho mỗi TÊN.

+0

Có một lỗi nhỏ trong tuyên bố cuối cùng. Nó phải là "IS NOT NULL" thay vì "IN NOT NULL". – mbp

+0

+1 bạn là một vị cứu tinh. Việc tự chỉnh sửa của bạn tham gia hoạt động ngay cả với SQL CE, nơi các giải pháp khác cho câu hỏi này không phải do các hạn chế của SQL CE. –

0

Nếu bạn có thể thêm vào một bảng tạm thời và sau đó truy vấn từ đó, bạn có thể làm điều đó trong một lần.

WITH T AS (temp table select), RN AS (select min row-numbers from T) SELECT T.NAME, T.DATA1, T.DATA2 FROM T INNER JOIN RN on T.row_number = RN.row_number 

Có nhiều cách khác để viết điều này, nhưng đó là cách tôi đã làm những việc tương tự.

0

Cố gắng dedupe B như thế này

SELECT A.NAME, bb.DATA1, bb.DATA2 
FROM A 
JOIN B bb 
ON  A.NAME = B.NAME 
WHERE NOT EXISTS (SELECT * 
        FROM B 
        WHERE NAME = bb.NAME 
          AND (DATA1 > bb.DATA1 
           OR DATA1 = bb.DATA1 AND DATA2 > bb.DATA2))

Thêm HOẶC khoản nếu nhiều cột datax tồn tại.

Nếu A chứa các bản sao quá, chỉ cần sử dụng DISTINCT như trong OP.

10

này sẽ làm việc:

with temp as (
    select A.NAME, B.DATA1, B.DATA2, 
     row_number() over (partition by A.NAME order by A.NAME) as rownum 
    from TABLEA A inner join TABLEB B 
    on A.NAME = B.NAME 
) 
select NAME, DATA1, DATA2 from temp where rownum = 1 

Nếu bạn muốn chọn giá trị nhỏ nhất của data1 và bên trong nó data2, sau đó sử dụng sự thay đổi này:

with temp as (
    select A.NAME, B.DATA1, B.DATA2, 
     row_number() over (partition by A.NAME order by B.DATA1, B.DATA2) as rownum 
    from TABLEA A inner join TABLEB B 
    on A.NAME = B.NAME 
) 
select NAME, DATA1, DATA2 from temp where rownum = 1 

Cả truy vấn sẽ cung cấp một hàng cho mỗi Tên.

+0

Sẽ tốt hơn nếu thực hiện phân vùng bằng 'B.name', vì vậy bạn có thể sử dụng chỉ mục (nếu có). Bạn thậm chí sẽ không phải bận tâm báo cáo 'A.name' (vì so sánh). –

+1

Giải pháp tuyệt vời. Cảm ơn. –

+1

@KobyDouek vui vì nó đã giúp :) chúc mừng! –

0
SELECT A.NAME, bb.DATA1, bb.DATA2 
From A Inner Join B on A.NAME = B.NAME 
WHERE B.DATA1 = (SELECT MIN(DATA1) FROM B WHERE NAME = A.NAME) 

Điều này sẽ cho kết quả mong muốn của bạn, cung cấp giá trị B.DATA1 là độc đáo trong tập liên quan đến bảng A.

Nếu họ phải là duy nhất, chỉ có cách khác mà tôi biết đang sử dụng CROSS ÁP DỤNG trong MSSQL 2005 trở lên.

0

Thẻ của câu hỏi này chỉ ra rằng nó sẽ là một giải pháp cho DB2, nhưng điều này rất giống với MS-SQL server, nếu vì vậy hãy thử các giải pháp này:

Sử dụng CROSS, nó sẽ có thể để hiển thị những gì chỉ tồn tại trong cả hai bảng

select A.*, B.DATA1, B.DATA2 
from A 
cross apply (select top 1 * from B where B.name = A.name) B 

Nhưng nó có thể thay đổi để OUTER để hiển thị những gì tồn tại trong A mà không có nghĩa vụ phải tồn tại trong B

select A.*, B.DATA1, B.DATA2 
from A 
OUTER apply (select top 1 * from B where B.name = A.name) B 

trong structu trong tuyên bố áp dụng, bạn cũng có thể đưa vào tuyên bố ORDER, vì không có dấu hiệu nào về thứ tự thoát trong bảng B

0

Bạn có thể sử dụng số hàng để lấy một hàng cho mỗi tên, thử một số thứ như bên dưới

Select name,data1,data2 from 
(Select A.NAME,B.DATA1,B.DATA2,row_number() over(partitioj by a.name order by a.name) rn 
From A 
Inner Join B on A.NAME = B.NAME) where rn=1 
Các vấn đề liên quan