web-dev-qa-db-fra.com

Sélectionnez le premier enregistrement dans une relation un-à-plusieurs à l'aide de la jointure gauche

J'essaie de joindre deux tables à l'aide d'une jointure gauche. Et le jeu de résultats ne doit inclure que le premier enregistrement de la table jointe "droite".

Disons que j'ai deux tableaux A et B comme ci-dessous;

Tableau "A"

code | emp_no

101  | 12222
102  | 23333
103  | 34444
104  | 45555
105  | 56666

Tableau "B"

code | city       | county
101  | Glen Oaks  | Queens
101  | Astoria    | Queens
101  | Flushing   | Queens
102  | Ridgewood  | Brooklyn
103  | Bayside    | New York

Sortie attendue:

code | emp_no | city      | county
101  | 12222  | Glen Oaks | Queens
102  | 23333  | Ridgewood | Brooklyn
103  | 34444  | Bayside   | New York
104  | 45555  | NULL      | NULL
105  | 56666  | NULL      | NULL

Si vous remarquez que mon résultat n'a que le seul enregistrement correspondant de la table "B" (peu importe quel enregistrement correspond) après la jointure gauche (et il s'agit d'un mappage un à plusieurs)

Je dois choisir le premier enregistrement correspondant dans le tableau B et ignorer toutes les autres lignes.

Veuillez aider!

Merci

41
Sandra

Après avoir joué un peu, cela s'avère plus compliqué que ce à quoi je m'attendais! En admettant que table_b a une seule colonne unique (disons, une clé primaire à un seul champ), il semble que vous pouvez faire ceci:

SELECT table_a.code,
       table_a.emp_no,
       table_b.city,
       table_b.county
  FROM table_a
  LEFT
  JOIN table_b
    ON table_b.code = table_a.code
   AND table_b.field_that_is_unique =
        ( SELECT TOP 1
                 field_that_is_unique
            FROM table_b
           WHERE table_b.code = table_a.code
       )
;
33
ruakh

Une autre option: OUTER APPLY

Si pris en charge par la base de données, OUTER APPLY est une option efficace et concise.

SELECT *
FROM 
    Table_A a
OUTER APPLY
    (SELECT TOP 1 * 
    FROM Table_B b_1
    WHERE b_1.code = a.code
    ) b
;

Il en résulte une jointure gauche au indéterminé premier enregistrement correspondant. Mes tests montrent qu'il est plus rapide que toute autre solution publiée (sur MS SQL Server 2012).

7
QuintinDB

La réponse la plus votée ne me semble pas correcte et semble trop compliquée. Il vous suffit de regrouper par le champ de code du tableau B dans votre sous-requête et de sélectionner l'ID maximum par regroupement.

SELECT 
    table_a.code,
    table_a.emp_no,
    table_b.city,
    table_b.county
FROM 
    table_a
    LEFT JOIN 
        table_b
        ON table_b.code = table_a.code
        AND table_b.field_that_is_unique IN
            (SELECT MAX(field_that_is_unique)
             FROM table_b
             GROUP BY table_b.code)
6
CShark

Si vous utilisez SQL Server 2005 ou une version ultérieure, vous pouvez utiliser ranking pour obtenir ce que vous voulez. En particulier, ROW_NUMBER() semble bien correspondre à vos besoins:

WITH B_ranked AS (
  SELECT
    *,
    rnk = ROW_NUMBER() OVER (PARTITION BY code ORDER BY city)
  FROM B
)
SELECT
  A.code,
  A.emp_no,
  B.city,
  B.county
FROM A
  LEFT JOIN B_ranked AS B ON A.code = B.code AND b.rnk = 1

OR

WITH B_unique_code AS (
  select * from(
     SELECT
      *,
      rnk = ROW_NUMBER() OVER (PARTITION BY code ORDER BY city)
      FROM B
     ) AS s
  where rnk = 1
)
SELECT
  A.code,
  A.emp_no,
  B.city,
  B.county
FROM A
  LEFT JOIN B_unique_code AS B ON A.code = B.code
4
Andriy M

J'ai modifié la réponse de ruakh et cela semble fonctionner parfaitement avec mysql.

SELECT 
   table_a.code,
   table_a.emp_no,
   table_b.city,
   table_b.county
FROM table_a a
LEFT JOIN table_b b
ON b.code = a.code 
AND b.id = (  SELECT id FROM table_b 
              WHERE table_b.code = table_a.code 
              LIMIT 1
           )
;
2
Gayan

Dans Oracle, vous pouvez faire:

WITH first_b AS (SELECT code, min(rowid) AS rid FROM b GROUP BY code)) 
SELECT a.code, a.emp_no, b.city, b.county
FROM a 
INNER JOIN first_b 
 ON first_b.code = a.code
INNER JOIN b
 ON b.rowid = first_b.rid
1
kevin cline

c'est ainsi:

 Select * From TableA a
     Left Join TableB b
         On b.Code = a.Code 
             And [Here put criteria predicate that 'defines' what the first record is]

Hé, si la ville et le comté sont uniques, alors utilisez-les

   Select * From TableA a
     Left Join TableB b
         On b.Code = a.Code 
             And b.City + b.county =
                  (Select Min(city + county)
                   From TableB 
                   Where Code = b.Code)

Mais le fait est que vous devez y mettre une expression pour dire au processeur de requêtes ce que signifie être premier.

0
Charles Bretana