Pengidentifikasi multi-bagian tidak dapat diikat


196

Saya telah melihat kesalahan serupa pada SO, tetapi saya tidak menemukan solusi untuk masalah saya. Saya punya pertanyaan SQL seperti:

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;

Ketika saya menjalankan kueri ini, hasil kesalahan adalah: Pengidentifikasi multi-bagian "a.maxa" tidak dapat diikat. Mengapa?
P / s: jika saya membagi kueri menjadi 2 permintaan individu, itu berjalan ok.

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;

dan

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

Apakah phuongxatabel termasuk kolom maxa?
Michael Petrotta

1
Apa yang terjadi jika Anda menambahkan grup dengan maxa, tong - tepat setelah 5 September 2011.
user710502

Ya, sudah. Jika saya membagi kueri menjadi 2 subquery, itu berjalan ok
PhamMinh

Sepertinya Anda mengeksekusi di database yang salah. Tambahkan pernyataan "USE [nama database]" ke awal permintaan dan lihat apakah Anda masih mendapatkan kesalahan.
brian

1
Tidak, saya katakan di atas, jika saya membagi kueri menjadi 2 permintaan individu, itu berjalan okey.
PhamMinh

Jawaban:


226

Anda mencampur gabungan implisit dengan gabungan eksplisit. Itu diperbolehkan, tetapi Anda harus mengetahui cara melakukannya dengan benar.

Masalahnya adalah, gabungan eksplisit (yang diimplementasikan menggunakan JOINkata kunci) diutamakan daripada yang tersirat ('koma' bergabung, di mana kondisi gabungan ditentukan dalam WHEREklausa).

Inilah garis besar kueri Anda:

SELECT
  
FROM a, b LEFT JOIN dkcd ON 
WHERE 

Anda mungkin mengharapkannya berperilaku seperti ini:

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

yaitu, kombinasi tabel adan bdigabungkan dengan tabel dkcd. Sebenarnya, yang terjadi adalah

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

yaitu, seperti yang mungkin sudah Anda pahami, dkcd digabungkan secara khusus melawan bdan hanya b, maka hasil gabungan digabungkan dengan adan disaring lebih lanjut dengan WHEREklausa. Dalam hal ini, referensi apa pun apada ONklausa tidak valid, atidak diketahui pada saat itu. Itu sebabnya Anda mendapatkan pesan kesalahan.

Jika saya jadi Anda, saya mungkin akan mencoba untuk menulis ulang pertanyaan ini, dan salah satu solusi yang mungkin adalah:

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

Di sini tabel adan bdigabungkan terlebih dahulu, kemudian hasilnya digabungkan ke dkcd. Pada dasarnya, ini adalah permintaan yang sama dengan Anda, hanya menggunakan sintaks yang berbeda untuk salah satu yang bergabung, yang membuat perbedaan besar: referensi a.maxadalam dkcdkondisi bergabungnya sekarang benar-benar valid.

Seperti @Aaron Bertrand telah mencatat dengan benar, Anda mungkin harus memenuhi syarat maxadengan alias tertentu, mungkin a, diORDER BY klausa.


ORDER BY maxa masih ambigu, bukan? Saya juga akan berhati-hati dengan 'Sep 1 2011' sebagai tanggal, tidak akan berfungsi dengan pengaturan bahasa / regional yang berbeda.
Aaron Bertrand

@ Harun: Setuju tentang ORDER BY maxa, terima kasih. Mengenai tanggalnya, saya percaya itulah cara OP memilih untuk menentukannya di lingkungan mereka.
Andriy M

"bergabung secara eksplisit ... diutamakan daripada yang tersirat" - dapatkah Anda memberikan kutipan untuk ini? misalnya apakah itu didefinisikan dalam Standar SQL atau apakah itu fitur produk? Terima kasih.
onedaywhen

1
@onedaywhen: Saya khawatir ini tidak lebih dari pengamatan di pihak saya sejauh ini. Saya agak lega dengan kenyataan bahwa saya tidak pertama berbicara tentang prioritas bergabung di sini, tetapi selain itu, saya akan senang menemukan konfirmasi resmi apa pun sendiri.
Andriy M

1
Dalam kasus saya, saya lupa meletakkan spasi ketika saya menggabungkan string untuk membangun sql, jadi 'FROM dbo.table_a a' + 'INNER JOIN dbo.table_b b' menjadi 'FROM dbo.table_a aINNER JOIN dbo.table_b b', dan itu menjadi bingung dan memberi saya pesan kesalahan ini. Detail, detail, detail.
Guy Schalnat

40

Terkadang kesalahan ini terjadi ketika Anda menggunakan skema (dbo) dalam kueri dengan cara yang salah.

misalnya jika Anda menulis:

select dbo.prd.name
from dbo.product prd

Anda akan mendapatkan kesalahan.

Dalam situasi ini ubahlah menjadi:

select prd.name
from dbo.product prd

1
Ini sangat mengganggu dan butuh waktu terlalu lama untuk mengetahuinya. Terima kasih. Bagian yang paling menjengkelkan adalah kadang-kadang mengomel tentang hal ini tetapi di lain waktu hal itu berlalu dengan
normal

12

jika Anda telah memberikan nama alies, ubahlah itu menjadi nama sebenarnya

sebagai contoh

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;

ubah itu menjadi

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

1
Juga jika Anda membangun string sql, waspadai kurangnya spasi tambahan di akhir baris. Itu mengkonversi alias M saya menjadi MINNER ketika bergabung dengan INNER JOIN line berikutnya di bawah ini. Profiler SQL yang menampilkan string yang dieksekusi membantu menyelesaikan masalah saya. (Dikomentari di sini karena terkait dengan masalah nama sebenarnya alias v)
Simon

wow @Simon terima kasih aku bahkan tidak memikirkan ini dan membenturkan kepalaku ke dinding mencoba untuk mencari tahu mengapa kueri ku tidak berfungsi, aku kehilangan ruang di ujung salah satu kereta pengembalinya!
buradd

9

Saya berjuang dengan pesan kesalahan yang sama di SQL SERVER, karena saya memiliki banyak gabungan, mengubah urutan gabungan memecahkannya untuk saya.


3

Dalam kasus saya masalahnya ternyata adalah nama alias yang saya berikan ke meja. "oa" tampaknya tidak dapat diterima untuk SQL Server.


2

Saya mengalami kesalahan yang sama dari JDBC. Memeriksa semuanya dan permintaan saya baik-baik saja. Ternyata, di mana klausa saya punya argumen:

where s.some_column = ?

Dan nilai argumen yang saya sampaikan adalah nol. Ini juga memberikan kesalahan yang sama yang menyesatkan karena ketika Anda mencari di internet Anda berakhir bahwa ada sesuatu yang salah dengan struktur permintaan tetapi tidak dalam kasus saya. Hanya berpikir seseorang mungkin menghadapi masalah yang sama


2

Apa yang berhasil bagi saya adalah mengubah klausa WHERE saya menjadi subquery SELECT

DARI:

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

UNTUK:

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

1

Saya baru mengenal SQL, tetapi menemukan masalah ini dalam kursus yang saya ambil dan menemukan bahwa menetapkan kueri untuk proyek secara khusus membantu menghilangkan kesalahan multi-bagian. Sebagai contoh, proyek yang saya buat adalah CTU SQL Project jadi saya memastikan saya memulai skrip saya dengan USE [CTU SQL Project] sebagai baris pertama saya seperti di bawah ini.

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

1
Ketika Anda mengatakan "proyek", saya berasumsi maksud Anda basis data dan bukan proyeksi. Pernyataan penggunaan hanya mengubah basis data yang Anda gunakan untuk kueri
Charleh

Ya, proyek Charleh seperti dalam database saya bekerja. Saya tidak yakin apa yang saya lakukan salah dengan database saya, tetapi menyatakan "gunakan" dan database spesifik untuk lingkup menghilangkan kesalahan saya.
Bogartz

1

Jika kesalahan ini terjadi dalam UPDATE, periksa ulang JOINdi atas meja dengan kolom / bidang yang menyebabkan kesalahan.

Dalam kasus saya ini adalah karena kurangnya JOINitu sendiri, yang menghasilkan kesalahan yang sama karena bidang yang tidak diketahui (seperti yang Andriy tunjukkan ).


1

Sebagai gantinya Anda dapat mencoba bergabung dengan tabel seperti,

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

Ini seharusnya bekerja


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;

Gunakan nama tabel itu sendiri daripada menggunakan alias jika masalah terikat multi-bagian muncul.
SVaidya

1

Kesalahan saya adalah menggunakan bidang yang tidak ada dalam tabel.

table1.field1 => tidak ada

table2.field1 => benar

Perbaiki Nama Meja Anda.

kesalahan saya terjadi karena menggunakan DENGAN

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

saat digunakan bergabung dengan tabel lain ...


1

Apakah Anda lupa bergabung dengan beberapa tabel? Jika tidak maka Anda mungkin perlu menggunakan beberapa alias.


1

Saya juga berjuang dengan kesalahan ini dan berakhir dengan strategi yang sama dengan jawabannya. Saya memasukkan jawaban saya hanya untuk mengonfirmasi bahwa ini adalah strategi yang harus bekerja.

Berikut adalah contoh di mana saya melakukan pertama satu gabungan dalam antara dua tabel yang saya tahu punya data dan kemudian dua gabungan luar kiri pada tabel yang mungkin memiliki baris yang sesuai yang bisa kosong. Anda mencampur gabungan dalam dan gabungan luar untuk mendapatkan hasil dengan tabel lintas data alih-alih melakukan sintaks dipisahkan koma default antara tabel dan melewatkan baris di gabungan yang Anda inginkan.

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

Pertama: Lakukan penggabungan bagian dalam di antara tabel yang Anda harapkan memiliki data yang cocok. Bagian kedua: Lanjutkan dengan gabungan luar untuk mencoba mengambil data di tabel lain, tetapi ini tidak akan memfilter hasil yang Anda setel jika sambungan luar tabel ke tidak memiliki data yang sesuai atau cocok dengan kondisi yang Anda atur di predikat / kondisi on.


0

Kesalahan ini juga dapat disebabkan oleh tidak adanya koma di ,antara nama kolom dalam pernyataan SELECT.

misalnya:

SELECT MyCol1, MyCol2 MyCol3 FROM SomeTable;
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.