2009-04-21 4 views
9

Ich muss nur die erste Zeile aus einer Abfrage auswählen, die Tabellen A und B verbindet. In Tabelle B existieren mehrere Datensätze mit demselben Namen. In keiner der beiden Tabellen sind Identifikatoren vorhanden. Ich kann das Schema auch nicht ändern, weil ich die DB nicht besitze.Wählen Sie die erste Zeile in einem Join von zwei Tabellen in einer Anweisung

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 

Das gibt mir

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

aber ich brauche nur eine Zeile pro Namen abzurufen

NAME  DATA1 DATA2 
sameName 1  2 
otherName 5  7 

Ich konnte dies tun, indem das Ergebnis in eine temporäre Tabelle mit einem Zusatz Identitätsspalte und wählen Sie dann die Mindest-ID pro Name.

Das Problem hier ist, dass ich dies in einer einzigen Anweisung tun muss.

Antwort

0

Nicht sicher, ob dies Ihr Problem löst oder nicht, aber Sie könnten versuchen, die GROUP BY-Klausel zu verwenden und nach einer der Namensspalten zu gruppieren.

DB2 Group by tutorial

7

eine GROUP BY verwenden, kann man Weg dorthin trennen, aber in Acht nehmen. Wenn Sie so etwas tun:

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

werden Sie das Ergebnis erhalten Sie suchen:

NAME  DATA1 DATA2 
    sameName 1  2  
    otherName 5  7 

Aber nur wegen der Daten, die Sie mit testen. Wenn Sie die Daten ändern, so dass statt:

otherName 8  9 

Sie hatte:

otherName 8  4 

Es wäre zurück:

NAME  DATA1 DATA2 
    sameName 1  2  
    otherName 5  4 

Beachten Sie, dass other nicht zurückkehrt DATA1 und DATA2 aus der gleicher Rekord!

Update: Eine Selbstverknüpfung mit einem Vergleich auf einem des Datenwertes können Ihnen helfen, wie zum Beispiel:

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; 

Dies wird jedoch nur funktionieren, wenn die Werte in DATA2 eindeutig sind pro Namen.

+0

Es gibt einen kleinen Tippfehler bei der letzten Aussage. Es sollte "IS NOT NULL" anstelle von "IN NOT NULL" sein. – mbp

+0

+1 du bist ein Retter. Ihr bearbeiteter Self-Join funktioniert sogar mit SQL CE, wo andere Lösungen für diese Frage aufgrund der Einschränkungen von SQL CE nicht verfügbar sind. –

0

Wenn Sie zu einer temporären Tabelle hinzufügen und dann abfragen können, können Sie es auf einmal tun.

Es gibt viele andere Möglichkeiten, dies zu schreiben, aber so habe ich ähnliche Dinge gemacht.

0

Try B wie dieses

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))

hinzufügen mehr OR-Klauseln, wenn mehr DATAx Spalten existieren Deduplizierung.

Wenn A auch Duplikate enthält, verwenden Sie einfach DISTINCT wie im OP.

10

Dies funktioniert:

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 

Wenn Sie den kleinsten Wert von data1 auswählen möchten und in ihm Daten2, dann diese Variante verwenden:

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 

Sowohl die Abfragen werden pro Zeile geben Name.

+0

Es wäre besser, die Partition mit 'B.name' zu ​​erstellen, so dass Sie einen Index verwenden können (falls vorhanden). Sie müssten sich nicht einmal Mühe geben, 'A.name' zu ​​melden (wegen des Vergleichs). –

+1

Große Lösung. Vielen Dank. –

+1

@KobyDouek froh, dass es geholfen hat :) Prost! –

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) 

Dies wird Ihr gewünschtes Ergebnis, B.DATA1 Werte sind einzigartigen innerhalb des Satzes Bereitstellung in Zusammenhang mit Tabelle A.

Wenn sie nicht eindeutig zuzuordnen sind, die einzige andere Weg, ich weiß verwendet CROSS APPLY in MSSQL 2005 und höher.

0

Der Tag dieser Frage zeigt, dass es eine Lösung für DB2 wäre, aber das ist sehr ähnlich wie MS-SQL-Server, wenn ja, diese Lösungen versuchen:

CROSS benutzen, wird es möglich sein, was angezeigt existiert nur in den beiden Tabellen

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

Aber es ist möglich, OUTER zu ändern, was ohne die Verpflichtung in A angezeigt werden existiert in B

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

im structu zu existieren re der Anweisung apply, wäre es auch möglich, eine ORDER-Anweisung aufzunehmen, da die Reihenfolge der Exits in Tabelle B

0

nicht angezeigt wird. Sie können die Zeilennummer verwenden, um für jeden Namen eine Zeile zu erhalten unter

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 
Verwandte Themen