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;
PhamMinh
źródło
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.

Andriy M.
źródło
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
Boby
źródło
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;
Alexander Zaldostanov
źródło
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.

Pavel M.
źródło
3

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

Hashim Akhtar
źródło
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

xbmono
źródło
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)
SauerTrout
źródło
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.
Bogartz
źródło
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 ).

CPHPython
źródło
1

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

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

To powinno działać

Suman Kumar
źródło
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
źródło
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 ...

Zolfaghari
źródło
1

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

Tadej
źródło
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.

Tore Aurstad
źródło
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;
Andrzej
źródło