Nie można powiązać identyfikatora wieloczęściowego


196

Widziałem podobne błędy na SO, ale nie znalazłem rozwiązania mojego problemu. Mam zapytanie SQL, takie jak:

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;

Gdy wykonuję to zapytanie, wynikiem błędu jest: Nie można powiązać wieloczęściowego identyfikatora „a.maxa”. Czemu?
P / s: jeśli podzielę zapytanie na 2 pojedyncze zapytania, będzie działać poprawnie.

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;

i

SELECT  maxa ,
        COUNT(*) AS tong
FROM    khaosat
WHERE   CONVERT(DATETIME, ngaylap, 103) BETWEEN 'Sep 1 2011'
                                        AND     'Sep 5 2011'
GROUP BY maxa;

Czy phuongxatabela zawiera kolumnę maxa?
— Michael Petrotta,

1
Co się stanie, jeśli dodasz grupę według maxa, tong - zaraz po 5 września 2011 r.
— 710502

Tak, ma. Jeśli podzielę kwerendę na 2 podzapytanie, będzie działać
— poprawnie

Wygląda na to, że wykonujesz nieprawidłową bazę danych. Dodaj instrukcję „USE [nazwa bazy danych]” na początku zapytania i sprawdź, czy błąd nadal występuje.
— brian

1
Nie, powiedziałem powyżej, jeśli podzielę zapytanie na 2 pojedyncze, uruchomi się dobrze.
— PhamMinh,

Odpowiedzi:


226

Mieszasz sprzężenia niejawne z połączeniami jawnymi. Jest to dozwolone, ale musisz wiedzieć, jak to zrobić poprawnie.

Chodzi o to, JOINże sprzężenia jawne (te, które są implementowane za pomocą słowa kluczowego) mają pierwszeństwo przed niejawnymi (sprzężenia przecinkowe, w których warunek łączenia jest określony w WHEREklauzuli).

Oto zarys twojego zapytania:

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

Prawdopodobnie spodziewasz się, że zachowa się tak:

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

to znaczy kombinacja tabel ai bjest łączona z tabelą dkcd. W rzeczywistości to, co się dzieje

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

to znaczy, jak już zapewne zrozumiałeś, dkcdjest łączony specjalnie przeciw bi tylko bwtedy wynik połączenia jest łączony z klauzulą ai dalej filtrowany WHERE. W tym przypadku wszelkie odniesienia do aw ONklauzula jest nieważna, anie jest znany w tym punkcie. Dlatego pojawia się komunikat o błędzie.

Gdybym był tobą, prawdopodobnie spróbowałbym przepisać to zapytanie, a jednym z możliwych rozwiązań może być:

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

Tutaj tabele ai bsą najpierw łączone, a następnie wynik jest łączony dkcd. Zasadniczo jest to ta sama kwerenda, co twoje, tylko przy użyciu innej składni dla jednego z połączeń, co robi wielką różnicę: odwołanie a.maxaw dkcdwarunku łączenia jest teraz absolutnie poprawne.

Jak słusznie zauważył @Aaron Bertrand, prawdopodobnie powinieneś zakwalifikować się maxaz określonym aliasem, prawdopodobnie aw ORDER BYklauzuli.


ORDER BY maxa jest nadal niejednoznaczny, nie? Również uważam na datę 1 września 2011 r., Nie będzie działać z różnymi ustawieniami języka / regionu.
— Aaron Bertrand,

@Aaron: Zgadzam się ORDER BY maxa, dzięki. Jeśli chodzi o daty, uważam, że właśnie w ten sposób PO zdecydował się określić je w swoim otoczeniu.
— Andriy M

„połączenia jawne ... mają pierwszeństwo przed domniemanymi” - czy możesz podać uzasadnienie? np. czy jest to zdefiniowane w standardach SQL, czy jest to funkcja produktu? Dzięki.
— poniedziałek,

1
@onedaywhen: Obawiam się, że jest to jak dotąd obserwacja z mojej strony. Z ulgą odczuwam nieco fakt, że nie mówię tu o pierwszeństwie dołączeń, ale poza tym chętnie znajdę jakiekolwiek oficjalne potwierdzenie.
— Andriy M

1
W moim przypadku zapomniałem wstawić spacje, kiedy połączyłem łańcuchy, aby zbudować sql, więc 'FROM dbo.table_a a' + 'INNER JOIN dbo.table_b b' stał się 'FROM dbo.table_a aINNER JOIN dbo.table_b b', i się pomylił i dał mi ten komunikat o błędzie. Szczegóły, szczegóły, szczegóły.
— Guy Schalnat

40

Czasami ten błąd występuje, gdy używasz swojego schematu (dbo) w zapytaniu w niewłaściwy sposób.

na przykład jeśli napiszesz:

select dbo.prd.name
from dbo.product prd

dostaniesz błąd.

W takich sytuacjach zmień to na:

select prd.name
from dbo.product prd

1
To jest dość denerwujące i zajęło mi zbyt wiele czasu, aby to rozgryźć. Dzięki Najbardziej irytujące jest to, że czasem dręczy o tym, ale innym razem przechodzi normalnie
— DanteTheSmith

12

jeśli podałeś imię alies, zmień je na prawdziwe

na przykład

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;

zmień to na

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

1
Również jeśli budujesz ciąg sql, uważaj na brak spacji na końcu wiersza. Przekształcił mój alias M w MINNER, gdy dołączył do następnej linii INNER JOIN poniżej. Profil SQL pokazujący wykonany ciąg pomógł rozwiązać mój problem. (Skomentowano tutaj, ponieważ dotyczy aliasu v faktycznego imienia i nazwiska)
— Simon

wow @ Simon dziękuję, nawet o tym nie myślałem i waliłem głową w ścianę, próbując dowiedzieć się, dlaczego moje zapytanie nie działa, brakowało mi spacji na końcu jednego ze zwrotów karetki!
— buradd

9

Zmagałem się z tym samym komunikatem o błędzie w SQL SERVER, ponieważ miałem wiele złączeń, zmiana kolejności złączeń rozwiązała to dla mnie.


3

W moim przypadku problemem okazał się pseudonim, który nadałem tabeli. „oa” wydaje się nie do przyjęcia dla SQL Server.


2

Miałem ten sam błąd z JDBC. Sprawdziłem wszystko i moje zapytanie było w porządku. Okazało się, w którym punkcie mam argument:

where s.some_column = ?

A wartość argumentu, który przekazałem, była zerowa. Daje to również ten sam błąd, który wprowadza w błąd, ponieważ podczas przeszukiwania Internetu okazuje się, że coś jest nie tak ze strukturą zapytań, ale w moim przypadku tak nie jest. Pomyślałem, że ktoś może zmierzyć się z tym samym problemem


2

Dla mnie zadziałała zmiana mojej klauzuli WHERE na podkwerendę SELECT

Z:

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

DO:

    DELETE FROM CommentTag WHERE [dbo].CommentTag.NoteId = (SELECT NoteId FROM FetchedTagTransferData)

1

Jestem nowy w SQL, ale natknąłem się na ten problem na kursie, który przeprowadziłem i stwierdziłem, że przypisanie zapytania do projektu pomogło w wyeliminowaniu błędu wieloczęściowego. Na przykład projekt, który utworzyłem, to CTU SQL Project, więc upewniłem się, że rozpocząłem swój skrypt od USE [CTU SQL Project] jako mojej pierwszej linii, jak poniżej.

USE [CTU SQL Project]
SELECT Advisors.First_Name, Advisors.Last_Name...and so on.

1
Kiedy mówisz „projekt”, zakładam, że masz na myśli bazę danych, a nie projekcję. Instrukcja use po prostu zmienia bazę danych, do której
— przesuwasz

Tak, projekt Charleh jak w bazie danych, nad którą pracowałem. Nie byłem pewien, co robiłem źle z moją bazą danych, ale stwierdzenie „użyj” i konkretnej bazy danych do zasięgu wyeliminowało mój błąd.
— Bogartz

1

Jeśli ten błąd wystąpi UPDATE, sprawdź dwukrotnie JOINtabelę z kolumną / polem, które powoduje błąd.

W moim przypadku wynikało to z braku JOINsamego siebie, który generował ten sam błąd z powodu nieznanego pola (jak zauważył Andriy ).


1

Zamiast tego możesz spróbować dołączyć do tabel takich jak:

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

To powinno działać


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;

Użyj samych nazw tabel zamiast używać aliasu, jeśli pojawi się problem związany z wieloma częściami.
— SVaidya

1

Mój błąd polegał na użyciu pola, które nie istniało w tabeli.

table1.field1 => nie istnieje

table2.field1 => jest poprawny

Popraw swoją nazwę tabeli.

mój błąd wystąpił z powodu użycia Z

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

w połączeniu z innymi tabelami ...


1

Zapomniałeś dołączyć do niektórych stolików? Jeśli nie, prawdopodobnie musisz użyć niektórych aliasów.


1

Walczyłem również z tym błędem i skończyłem z tą samą strategią co odpowiedź. Podaję swoją odpowiedź, aby potwierdzić, że jest to strategia, która powinna zadziałać.

Oto przykład, w którym najpierw wykonuję jedno wewnętrzne połączenie między dwiema tabelami, o których wiem, że dostałem dane, a następnie dwa lewe zewnętrzne sprzężenia w tabelach, które mogą mieć odpowiednie wiersze, które mogą być puste. Łączymy połączenia wewnętrzne i połączenia zewnętrzne, aby uzyskać wyniki z danymi w różnych tabelach, zamiast wykonywać domyślną składnię oddzieloną przecinkami między tabelami i pominąć wiersze w żądanym złączeniu.

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]%')

Po pierwsze: wykonaj wewnętrzne łączenia między tabelami, które mają mieć pasujące dane. Druga część: Kontynuuj z łączeniami zewnętrznymi, aby spróbować pobrać dane z innych tabel, ale to nie odfiltruje zestawu wyników, jeśli łączenie zewnętrzne tabeli nie ma odpowiednich danych lub nie odpowiada warunkom skonfigurowanym w predykacie / warunku.


0

Ten błąd może być również spowodowany brakiem przecinka ,między nazwami kolumn w instrukcji SELECT.

na przykład:

SELECT MyCol1, MyCol2 MyCol3 FROM SomeTable;
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.