2011-01-14 32 views
19

Tôi đã có bảng hóa đơn và bảng con của dữ liệu liên quan có liên quan theo khóa. Cụ thể, đối với mỗi hóa đơn, tôi chỉ quan tâm đến hàng liên quan đầu tiên từ bảng con. Vì tôi muốn một hàng có liên quan cho mỗi khóa hóa đơn - làm thế nào để tôi thực hiện điều này?Làm cách nào để tham gia hàng đầu tiên của truy vấn phụ?

Select i.[Invoice Number], 
     c.[Carrier Name] 
From Invoice i 
    Left Join Carriers c on i.[InvoiceKey] = c.[InvoiceKey] 
Where -- what? 

Tôi đoán nói ngữ nghĩa, những gì tôi đang tìm kiếm một cái gì đó tương tự như khái niệm về Top 1 c.CarrierName Group by InvoiceKey (hoặc những gì sẽ là khái niệm rằng nếu điều đó là có thể trong T-SQL.)

tôi đã nghĩ về việc tham gia trái vào một truy vấn con, nhưng điều đó dường như không hiệu quả lắm. Có ai có bất kỳ thủ thuật T-SQL để đạt được điều này một cách hiệu quả?

Chỉnh sửa: Xin lỗi các bạn, tôi quên đề cập đến đây là SQL Server 2000, vì vậy trong khi tôi sẽ cung cấp cho upvotes cho câu trả lời SQL Server 2005/2008 hiện tại sẽ hoạt động, tôi không thể chấp nhận chúng sợ.

+0

Có bảng thứ hai có bất kỳ thuộc tính mà nói mà hàng là đầu tiên thứ hai, vv – Chandu

+0

@Cybernate Không, không phải là một chuỗi các chỉ số – BenAlabaster

Trả lời

24

Với điều kiện là CarriersPRIMARY KEY gọi id:

SELECT i.[Invoice Number], 
     c.[Carrier Name] 
FROM Invoice i 
JOIN Carriers c 
ON  c.id = 
     (
     SELECT TOP 1 ID 
     FROM Carriers ci 
     WHERE ci.InvoiceKey = i.InvoiceKey 
     ORDER BY 
       id -- or whatever 
     ) 
+0

Điều đó thực sự tuyệt vời! – abatishchev

+0

Hiệu suất của điều này có thể là xấu so với một nhóm và có mệnh đề. Bạn đang thực hiện truy vấn con tương quan với bảng Carriers cho mỗi hàng trong Invoice. –

+4

@Chris: so với cái gì? Bạn đã không cung cấp một ví dụ làm việc. – Quassnoi

1

này làm việc cho tôi:

select ir.[Invoice Number], c.[Carrier Name] 
from 
    (select ROW_NUMBER() over (order by i.[Invoice Number] asc) AS RowNumber, i.[Invoice Number], i.InvoiceKey 
    from Invoice i) AS ir 
left join Carriers c 
on ir.InvoiceKey = c.InvoiceKey 
where RowNumber = 1 
union all 
select ir.[Invoice Number], NULL as [Carrier Name] 
from 
    (select ROW_NUMBER() over (order by i.[Invoice Number] asc) AS RowNumber, i.[Invoice Number] 
    from Invoice i) AS ir 
where RowNumber > 1 

hoặc

select TOP 1 i.[Invoice Number], c.[Carrier Name] 
from Invoice i 
left join Carriers c 
on i.InvoiceKey = c.InvoiceKey 
union all 
select ir.[Invoice Number], NULL as [Carrier Name] 
from 
    (select ROW_NUMBER() over (order by i.[Invoice Number] asc) AS RowNumber, i.[Invoice Number] 
    from Invoice i) AS ir 
where RowNumber > 1 
+0

1 Sẽ làm công việc nếu tôi đã trên SQL Server 2005+, nhưng tôi quên đề cập đến tôi cần điều này chạy trên một hộp SQL Server 2000. – BenAlabaster

0
group by carriername having max(invoicenumber) 

để có được chiếc tàu sân bay đầu tiên cho mỗi hóa đơn:

group by invoicenumber having max(carriername) 
-- substitute the column you want to order by for carrier name to change which is 'first' 
+0

Điều này sẽ không hoạt động - điều này sẽ chỉ cung cấp cho tôi tên nhà cung cấp dịch vụ của nhà cung cấp dịch vụ có số hóa đơn cao nhất. Những gì tôi cần là người vận chuyển đầu tiên cho mỗi hóa đơn. – BenAlabaster

+0

Không, điều này sẽ cung cấp cho bạn số hóa đơn cao nhất cho mỗi nhà cung cấp dịch vụ. Bằng cách đảo ngược nhóm theo/có, bạn có thể nhận được nhà cung cấp dịch vụ đầu tiên cho mỗi hóa đơn. –

+0

Hãy nhớ rằng có các điều khoản được áp dụng SAU nhóm theo mệnh đề :-) –

1
;with cteRowNumber as (
    select c.InvoiceKey, c.[Carrier Name], ROW_NUMBER() over (partition by c.InvoiceKey order by c.[Carrier Name]) as RowNum 
     from Carriers c 
) 
select i.[Invoice Number], 
     rn.[Carrier Name] 
    from Invoice i 
     left join cteRowNumber rn 
      on i.InvoiceKey = rn.InvoiceKey 
       and rn.RowNum = 1 
+0

Không hoạt động. Tham gia tất cả các bản ghi, không chỉ đầu tiên – abatishchev

+0

@abatishchev: Tôi không thấy nó. Nếu tôi bao gồm 'rn.RowNum = 1' như một phần của điều kiện kết nối của tôi, thì nó chỉ nên tham gia" đầu tiên "(như được định nghĩa bởi thứ tự của hàm cửa sổ). –

+0

+1 Về mặt kỹ thuật, nhưng tôi quên đề cập đến rằng tôi đang tìm kiếm SQL Server 2000, vì vậy CTE không phải là một tùy chọn. – BenAlabaster

1

Đây là cách tôi sẽ làm điều đó, sử dụng một cú pháp hơi khác so với bạn (MySQL phong cách), nhưng tôi đoán bạn có thể áp dụng nó vào giải pháp của bạn cũng như:

SELECT i.invoiceNumber, c.carrierName 
FROM Invoice as i 
LEFT JOIN Carriers as c ON (c.id = (SELECT id FROM Carriers WHERE invoiceKey = i.invoiceKey ORDER BY id LIMIT 1)) 

này sẽ đưa tất cả hồ sơ từ hóa đơn, và tham gia nó với một bản ghi (hoặc không) từ các Hãng vận tải, cụ thể là bản ghi có cùng một hoá đơn và chỉ là bản ghi đầu tiên.

Miễn là bạn có chỉ mục trên Carriers.invoiceKey, hiệu suất của truy vấn này phải được chấp nhận.

Sebastian

1

Trong trường hợp này, tôi thường sử dụng một thiết bị mà tôi ở đây áp dụng đối với ví dụ của bạn và mô tả dưới đây:

SELECT 
    i.[Invoice Number], 
    c.[Carrier Name] 
FROM Invoice i 
    INNER JOIN Carriers c ON i.InvoiceKey = c.InvoiceKey 
    INNER JOIN (
    SELECT MIN(ID) AS ID 
    FROM Carriers 
    GROUP BY InvoiceKey 
) c_top ON c.ID = c_top.ID 

Tôi nghĩ, đây là khoảng những gì Quassnoi đã đăng, chỉ có tôi cố gắng tránh sử dụng SELECT TOP như thế.

Invoice được kết hợp với Carriers dựa trên biểu thức liên kết của chúng (InvoiceKey trong trường hợp này). Bây giờ, Carriers có thể có nhiều hàng cho cùng một InvoiceKey, vì vậy chúng tôi cần giới hạn đầu ra. Và điều đó được thực hiện bằng cách sử dụng một bảng có nguồn gốc.

Bảng dẫn xuất nhóm các hàng từ Carrier dựa trên cùng một biểu thức được sử dụng để liên kết hai bảng (InvoiceKey).

Và có một cách khác: thay vì tham gia bảng dẫn xuất bạn có thể sử dụng IN (subquery) với cùng tác dụng. Đó là, các truy vấn hoàn chỉnh sau đó sẽ trông như thế này:

SELECT 
    i.[Invoice Number], 
    c.[Carrier Name] 
FROM Invoice i 
    INNER JOIN Carriers c ON i.InvoiceKey = c.InvoiceKey 
    AND c.ID IN (SELECT MIN(ID) FROM Carriers GROUP BY InvoiceKey) 
Các vấn đề liên quan