L'identifiant en plusieurs parties n'a pas pu être lié

196

J'ai vu des erreurs similaires sur SO, mais je ne trouve pas de solution à mon problème. J'ai une requête SQL comme:

SELECT DISTINCT
        a.maxa ,
        b.mahuyen ,
        a.tenxa ,
        b.tenhuyen ,
        ISNULL(dkcd.tong, 0) AS tongdkcd
FROM    phuongxa a ,
        quanhuyen b
        LEFT OUTER JOIN ( SELECT    maxa ,
                                    COUNT(*) AS tong
                          FROM      khaosat
                          WHERE     CONVERT(DATETIME, ngaylap, 103) BETWEEN 'Sep 1 2011'
                                                              AND
                                                              'Sep 5 2011'
                          GROUP BY  maxa
                        ) AS dkcd ON dkcd.maxa = a.maxa
WHERE   a.maxa <> '99'
        AND LEFT(a.maxa, 2) = b.mahuyen
ORDER BY maxa;

Lorsque j'exécute cette requête, le résultat de l'erreur est: L'identifiant en plusieurs parties "a.maxa" n'a pas pu être lié. Pourquoi?
P / s: si je divise la requête en 2 requêtes individuelles, cela fonctionne bien.

SELECT DISTINCT
        a.maxa ,
        b.mahuyen ,
        a.tenxa ,
        b.tenhuyen
FROM    phuongxa a ,
        quanhuyen b
WHERE   a.maxa <> '99'
        AND LEFT(a.maxa, 2) = b.mahuyen
ORDER BY maxa;

et

SELECT  maxa ,
        COUNT(*) AS tong
FROM    khaosat
WHERE   CONVERT(DATETIME, ngaylap, 103) BETWEEN 'Sep 1 2011'
                                        AND     'Sep 5 2011'
GROUP BY maxa;
PhamMinh
la source
Le phuongxatableau comprend-il une colonne maxa?
Michael Petrotta
1
Que se passe-t-il si vous ajoutez un groupe par maxa, tong - juste après le 5 septembre 2011.
user710502
Oui, c'est vrai. Si je divise la requête en 2 sous-requêtes, cela fonctionne correctement
PhamMinh
On dirait que vous exécutez sur la mauvaise base de données. Ajoutez une instruction "USE [nom de la base de données]" au début de la requête et voyez si vous obtenez toujours l'erreur.
brian
1
Non, je l'avais dit ci-dessus, si je divise la requête en 2 requêtes individuelles, cela fonctionne bien.
PhamMinh

Réponses:

226

Vous mélangez des jointures implicites avec des jointures explicites. C'est autorisé, mais vous devez savoir comment le faire correctement.

Le fait est que les jointures explicites (celles qui sont implémentées à l'aide du JOINmot - clé) ont priorité sur les jointures implicites (les jointures «virgule», où la condition de jointure est spécifiée dans la WHEREclause).

Voici un aperçu de votre requête:

SELECT
  
FROM a, b LEFT JOIN dkcd ON 
WHERE 

Vous vous attendez probablement à ce qu'il se comporte comme ceci:

SELECT
  
FROM (a, b) LEFT JOIN dkcd ON 
WHERE 

c'est-à-dire la combinaison de tables aet best jointe à la table dkcd. En fait, ce qui se passe est

SELECT
  
FROM a, (b LEFT JOIN dkcd ON …)
WHERE 

c'est-à-dire, comme vous l'avez peut-être déjà compris, dkcdest joint spécifiquement contre bet uniquement b, puis le résultat de la jointure est combiné aet filtré davantage avec la WHEREclause. Dans ce cas, toute référence à ala ONclause n'est pas valide, aest inconnue à ce stade. C'est pourquoi vous obtenez le message d'erreur.

Si j'étais vous, j'essaierais probablement de réécrire cette requête, et une solution possible pourrait être:

SELECT DISTINCT
  a.maxa,
  b.mahuyen,
  a.tenxa,
  b.tenhuyen,
  ISNULL(dkcd.tong, 0) AS tongdkcd
FROM phuongxa a
  INNER JOIN quanhuyen b ON LEFT(a.maxa, 2) = b.mahuyen
  LEFT OUTER JOIN (
    SELECT
      maxa,
      COUNT(*) AS tong
    FROM khaosat
    WHERE CONVERT(datetime, ngaylap, 103) BETWEEN 'Sep 1 2011' AND 'Sep 5 2011'
    GROUP BY maxa
  ) AS dkcd ON dkcd.maxa = a.maxa
WHERE a.maxa <> '99'
ORDER BY a.maxa

Ici les tables aet bsont jointes en premier, puis le résultat est joint à dkcd. Fondamentalement, il s'agit de la même requête que la vôtre, en utilisant uniquement une syntaxe différente pour l'une des jointures, ce qui fait une grande différence: la référence a.maxadans la dkcdcondition de jointure de est désormais absolument valide.

Comme @Aaron Bertrand l'a correctement noté, vous devriez probablement vous qualifier maxaavec un alias spécifique, probablement a, dans la ORDER BYclause.

Andriy M
la source
COMMANDER PAR maxa est toujours ambigu, non? De plus, je serais prudent avec '1 septembre 2011' comme date, ne fonctionnera pas avec différents paramètres de langue / région.
Aaron Bertrand
@Aaron: D'accord ORDER BY maxa, merci. Quant aux dates, je crois que c'est ainsi que le PO a choisi de les préciser dans leur environnement.
Andriy M
"jointures explicites ... ont priorité sur les jointures implicites" - pouvez-vous fournir une citation pour cela, s'il vous plaît? Par exemple, est-ce défini dans les normes SQL ou s'agit-il d'une fonctionnalité du produit? Merci.
quand le
1
@onedaywhen: Je crains que ce ne soit pour l'instant qu'une observation de mon côté. Je suis quelque peu soulagé par le fait que je ne suis pas le premier à parler de la priorité des jointures ici, mais à part cela, je serais heureux de trouver moi-même toute sorte de confirmation officielle.
Andriy M
1
Dans mon cas, j'oubliais de mettre des espaces lorsque j'ai concaténé des chaînes pour construire le sql, donc 'FROM dbo.table_a a' + 'INNER JOIN dbo.table_b b' est devenu 'FROM dbo.table_a aINNER JOIN dbo.table_b b', et il est devenu confus et m'a donné ce message d'erreur. Détails, détails, détails.
Guy Schalnat
40

Parfois, cette erreur se produit lorsque vous utilisez votre schéma (dbo) dans votre requête de manière incorrecte.

par exemple si vous écrivez:

select dbo.prd.name
from dbo.product prd

vous obtiendrez l'erreur.

Dans ces situations, changez-le en:

select prd.name
from dbo.product prd
Bobs
la source
1
C'est assez ennuyeux et cela m'a pris beaucoup trop de temps pour le comprendre. Merci. La partie la plus ennuyeux est parfois naggs à ce sujet , mais d' autres fois , il passe normaly
DanteTheSmith
12

si vous avez donné un nom à alies, changez-le en nom réel

par exemple

SELECT  
    A.name,A.date
  FROM [LoginInfo].[dbo].[TableA] as A
   join 
  [LoginInfo].[dbo].[TableA] as B 
  on  [LoginInfo].[dbo].[TableA].name=[LoginInfo].[dbo].[TableB].name;

changer cela en

SELECT  
    A.name,A.date
  FROM [LoginInfo].[dbo].[TableA] as A
   join 
  [LoginInfo].[dbo].[TableA] as B 
  on  A.name=B.name;
Alexander Zaldostanov
la source
1
Aussi, si vous créez la chaîne sql, faites attention au manque d'espaces de fin à la fin de la ligne. Il a converti mon alias M en MINNER lorsqu'il a rejoint la prochaine ligne INNER JOIN ci-dessous. Le profileur SQL montrant la chaîne exécutée a aidé à résoudre mon problème. (Commenté ici car il est lié au problème de nom réel alias v)
Simon
wow @Simon merci je n'y ai même pas pensé et me cognais la tête contre le mur en essayant de comprendre pourquoi ma requête ne fonctionnait pas, il me manquait un espace à la fin de l'un des retours de chariot de chaîne!
buradd
9

Je rencontrais des difficultés avec le même message d'erreur dans SQL SERVER, car j'avais plusieurs jointures, ce qui changeait l' ordre des jointures pour moi.

Pavel M.
la source
3

Dans mon cas, le problème s'est avéré être le nom d'alias que j'avais donné à la table. "oa" ne semble pas acceptable pour SQL Server.

Hashim Akhtar
la source
2

J'avais la même erreur de JDBC. J'ai tout vérifié et ma requête allait bien. Il s'est avéré, dans la clause où j'ai un argument:

where s.some_column = ?

Et la valeur de l'argument que je transmettais était nulle. Cela donne également la même erreur qui est trompeuse car lorsque vous effectuez une recherche sur Internet, vous vous rendez compte que quelque chose ne va pas avec la structure de la requête, mais ce n'est pas dans mon cas. Je pensais juste que quelqu'un pourrait être confronté au même problème

xbmono
la source
2

Ce qui a fonctionné pour moi a été de changer ma clause WHERE en une sous-requête SELECT

DE:

    DELETE FROM CommentTag WHERE [dbo].CommentTag.NoteId = [dbo].FetchedTagTransferData.IssueId

À:

    DELETE FROM CommentTag WHERE [dbo].CommentTag.NoteId = (SELECT NoteId FROM FetchedTagTransferData)
SauerTrout
la source
1

Je suis nouveau dans SQL, mais je suis tombé sur ce problème dans un cours que je suivais et j'ai constaté que l'attribution de la requête au projet a spécifiquement aidé à éliminer l'erreur en plusieurs parties. Par exemple, le projet que j'ai créé était CTU SQL Project, donc je me suis assuré que j'ai commencé mon script avec USE [CTU SQL Project] comme première ligne comme ci-dessous.

USE [CTU SQL Project]
SELECT Advisors.First_Name, Advisors.Last_Name...and so on.
Bogartz
la source
1
Quand vous dites "projet", je suppose que vous voulez dire base de données et non projection. L'instruction use change simplement la base de données dans laquelle vous étendez la requête
Charleh
Oui, projet Charleh comme dans la base de données sur laquelle je travaillais. Je n'étais pas sûr de ce que je faisais mal avec ma base de données, mais en indiquant «utilisation» et la base de données spécifique à la portée a éliminé mon erreur.
Bogartz
1

Si cette erreur se produit dans un UPDATE, revérifiez le JOINsur la table avec la colonne / le champ à l'origine de l'erreur.

Dans mon cas, cela était dû à l'absence de JOINlui - même, ce qui a généré la même erreur en raison d'un champ inconnu (comme l'a souligné Andriy ).

CPHPython
la source
1

Au lieu de cela, vous pouvez essayer de joindre des tables comme,

select 
  .... 
from 
   dkcd 
     right join 
                a
                  , b

Cela devrait fonctionner

Suman Kumar
la source
1
SELECT DISTINCT
        phuongxa.maxa ,
        quanhuyen.mahuyen ,
        phuongxa.tenxa ,
        quanhuyen.tenhuyen ,
        ISNULL(dkcd.tong, 0) AS tongdkcd
FROM    phuongxa ,
        quanhuyen
        LEFT OUTER JOIN ( SELECT    khaosat.maxa ,
                                    COUNT(*) AS tong
                          FROM      khaosat
                          WHERE     CONVERT(DATETIME, ngaylap, 103) BETWEEN 'Sep 1 2011'
                                                              AND
                                                              'Sep 5 2011'
                          GROUP BY  khaosat.maxa
                        ) AS dkcd ON dkcd.maxa = maxa
WHERE   phuongxa.maxa <> '99'
        AND LEFT(phuongxa.maxa, 2) = quanhuyen.mahuyen
ORDER BY maxa;
SVaidya
la source
Utilisez les noms de table eux-mêmes au lieu d'utiliser l'alias si un problème lié à plusieurs parties se présente.
SVaidya
1

Mon erreur a été d'utiliser un champ qui n'existait pas dans la table.

table1.field1 => n'existe pas

table2.field1 => est correct

Corrigez le nom de votre table.

mon erreur s'est produite en raison de l'utilisation de WITH

WITH RCTE AS (
   SELECT...
)
SELECT RCTE.Name, ...
FROM 
  RCTE INNER JOIN Customer
  ON RCTE.CustomerID = Customer.ID 

lorsqu'il est utilisé en association avec d'autres tables ...

Zolfaghari
la source
1

Avez-vous oublié de rejoindre certaines tables? Sinon, vous devrez probablement utiliser certains alias.

Tadej
la source
1

Je luttais également avec cette erreur et je me suis retrouvé avec la même stratégie que la réponse. J'inclus ma réponse juste pour confirmer qu'il s'agit d'une stratégie qui devrait fonctionner.

Voici un exemple où je fais d'abord une jointure interne entre deux tables que je connais a obtenu des données, puis deux jointures externes gauche sur des tables qui pourraient avoir des lignes correspondantes qui peuvent être vides. Vous mélangez les jointures internes et les jointures externes pour obtenir des résultats avec les données sur les tables au lieu de faire la syntaxe par défaut séparée par des virgules entre les tables et de manquer des lignes dans la jointure souhaitée.

use somedatabase
go 

select o.operationid, o.operatingdate, p.pasid, p.name as patientname, o.operationalunitid, f.name as operasjonsprogram,  o.theaterid as stueid, t.name as stuenavn, o.status as operasjonsstatus from operation o 
inner join patient p on o.operationid = p.operationid 
left outer join freshorganizationalunit f on f.freshorganizationalunitid = o.operationalunitid
left outer join theater t on t.theaterid = o.theaterid
where (p.Name like '%Male[0-9]%' or p.Name like '%KFemale [0-9]%')

Premièrement: effectuez les jointures internes entre les tables auxquelles vous vous attendez à ce que les données correspondent. Deuxième partie: Continuez avec les jointures externes pour essayer de récupérer des données dans d'autres tables, mais cela ne filtrera pas votre jeu de résultats si la jointure externe de la table n'a pas de données correspondantes ou ne correspond pas à la condition que vous avez définie dans le prédicat / condition on.

Tore Aurstad
la source
0

Cette erreur peut également être provoquée par le simple fait de manquer une virgule ,entre les noms de colonne dans l'instruction SELECT.

par exemple:

SELECT MyCol1, MyCol2 MyCol3 FROM SomeTable;
Andrew
la source