Çok parçalı tanımlayıcı bağlanamadı


196

SO'da benzer hatalar gördüm, ancak sorunum için bir çözüm bulamıyorum. Bir SQL sorgusu var:

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;

Bu sorguyu yürüttüğümde, hata sonucu: "a.maxa" çok parçalı tanımlayıcısı bağlanamadı. Neden?
P / s: Sorguyu 2 ayrı sorguya bölersem, tamam çalışır.

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;

ve

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

Does phuongxatablo sütunu dahil maxa?
Michael Petrotta

1
Maxa

Evet var. Sorguyu 2 alt sorguya ayırırsam, tamam çalışır
PhamMinh

Yanlış veritabanında yürütüyormuşsunuz gibi geliyor. Sorgunun başına "USE [veritabanı adı]" deyimi ekleyin ve hatayı alıp almadığınızı görün.
brian

1
Hayır, yukarıda söylemiştim, eğer sorguyu 2 ayrı sorguya bölersem, okey çalıştırır.
PhamMinh

Yanıtlar:


226

Örtülü birleşimleri, kesin birleşimlerle karıştırıyorsunuz. Buna izin verilir, ancak bunu nasıl doğru bir şekilde yapacağınızın farkında olmanız gerekir.

Mesele şu ki, açık birleştirmeler ( JOINanahtar kelime kullanılarak uygulananlar ) örtük olanlara göre öncelik kazanır ('virgül' birleşim, WHEREyan tümce tümcesinde belirtilir ).

İşte sorgunuzun bir özeti:

SELECT
  
FROM a, b LEFT JOIN dkcd ON 
WHERE 

Muhtemelen böyle davranmasını bekliyorsunuz:

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

bu, tablo birleşimidir ave btablo ile birleştirilir dkcd. Aslında olan şu ki

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

yani, daha önce de bildiğiniz gibi, dkcdözellikle karşı bve sadece birleştirilir b, o zaman birleştirme sonucu birleştirilir ave WHEREmadde ile daha fazla filtrelenir . Bu durumda, abu ONmaddede yapılan atıf geçersizdir a. Bu yüzden hata mesajını alıyorsunuz.

Ben olsaydım, muhtemelen bu sorguyu yeniden yazmaya çalışıyordum ve olası bir çözüm olabilir:

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

Burada önce tablolar birleştirilir ave bsonra sonuç birleştirilir dkcd. Referans: Temel olarak, bu sizinkilerle aynı sorgu sadece büyük bir fark yaratıyor katılır biri için farklı bir sözdizimi kullanarak, olduğu a.maxaiçinde dkcd's koşulu artık kesinlikle geçerlidir katılmak.

@Aaron Bertrand doğru belirttiği gibi, muhtemelen hak etmelidir maxamuhtemelen belirli bir takma adı ile ade, ORDER BYmaddede.


ORDER BY maxa hala belirsiz, değil mi? Ayrıca, tarih olarak '1 Eylül 2011'e dikkat ederim, farklı dil / bölgesel ayarlarla çalışmaz.
Aaron Bertrand

@Aaron: Kabul et ORDER BY maxa, teşekkürler. Tarihlere gelince, OP'nin onları çevrelerinde bu şekilde belirlemeyi seçtiğine inanıyorum.
Andriy M

"açık birleşimler ... örtük olanlardan öncelikli" - bunun için bir alıntı yapabilir misiniz, lütfen? örneğin bu SQL Standartlarında tanımlanmış mı yoksa bir ürün özelliği mi? Teşekkürler.
oneday6

1
@onedaywhen: Korkarım bu şu ana kadar benim tarafımdaki bir gözlemden başka bir şey değil. İlk önce burada katılmaların önceliği hakkında konuşmamamdan biraz rahatladım , ancak bunun dışında her türlü resmi onayı kendim bulmaktan memnuniyet duyarım.
Andriy M

1
Benim durumumda, sql oluşturmak için dizeleri birleştirdiğimde boşluk koymayı unutuyordum, bu yüzden 'FROM dbo.table_a' + 'INNER JOIN dbo.table_b b' 'FROM dbo.table_a aINNER JOIN dbo.table_b b' oldu, ve kafam karıştı ve bana bu hata mesajını verdi. Detaylar, detaylar, detaylar.
Guy Schalnat

40

Bazen bu hata, şemanızı (dbo) sorgunuzda yanlış bir şekilde kullandığınızda oluşur.

örneğin yazarsanız:

select dbo.prd.name
from dbo.product prd

hatayı alırsınız.

Bu durumlarda bunu şu şekilde değiştirin:

select prd.name
from dbo.product prd

1
Bu oldukça can sıkıcı bir durum ve bunu anlaması çok uzun sürdü. Teşekkürler. En sinir bozucu kısmı bazen bu konuda naggs ama diğer zamanlarda normal geçer
DanteTheSmith

12

Yanıt adı verdiyseniz, bunu gerçek adla değiştirin

Örneğin

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;

bunu olarak değiştir

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

1
Ayrıca sql dizesini oluşturuyorsanız, satırın sonundaki boşlukların eksikliğine dikkat edin. Takma adımı M, aşağıdaki sonraki INNER JOIN hattına katıldığında MINNER'e dönüştürdü. Dize gösteren SQL profiler sorunumu çözmeye yardımcı oldu. (Burada takma ad v gerçek ad sorunu ile ilgili olduğu için yorumlanmıştır)
Simon

wow @Simon teşekkür ederim Ben bile bu konuda düşünmüyordu ve neden benim sorgu çalışma değildi anlamaya çalışırken kafama duvara vurarak, ben dize taşıma dönüşlerinden birinin sonunda bir boşluk eksikti!
buradd

9

SQL SERVER'de aynı hata mesajı ile mücadele ediyordum, çünkü birden fazla birleşim vardı , birleşmelerin sırasını değiştirmek benim için çözdü.


3

Benim durumumda, masaya verdiğim takma ad olduğu ortaya çıktı. "oa" SQL Server için kabul edilebilir görünmüyor.


2

JDBC'den de aynı hatayı alıyordum. Her şeyi kontrol ve benim sorgu iyiydi. Ortaya çıktı ki, nerede bir argümanım var:

where s.some_column = ?

Ve geçtiğim argümanın değeri null. Bu aynı zamanda yanıltıcı olan aynı hatayı verir, çünkü internette arama yaptığınızda sorgu yapısı ile ilgili bir sorun var ama benim durumumda değil. Birisinin aynı sorunla karşılaşabileceğini düşündüm


2

Benim için işe yarayan, WHERE yan tümcemi SELECT alt sorgusuna dönüştürmekti

DAN:

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

TO:

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

1

SQL'de yeniyim, ancak bu derste aldığım bir derste karşılaştım ve sorguyu projeye atamanın özellikle çok parçalı hatayı ortadan kaldırmaya yardımcı olduğunu buldum. Örneğin oluşturduğum proje CTU SQL Project'ti, bu yüzden senaryomu USE [CTU SQL Project] ile aşağıdaki gibi ilk satırım olarak başlattığımdan emin oldum.

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

1
"Proje" dediğinizde, projeksiyon değil demek istediğiniz veritabanı olduğunu varsayıyorum.
Use deyimi

Evet, Charleh projesinde çalıştığım veritabanında olduğu gibi. Veritabanımla neyi yanlış yaptığımdan emin değildim, ancak "kullanım" ve kapsam için belirli bir veritabanı belirtmek hatamı ortadan kaldırdı.
Bogartz

1

Bu hata bir durumunda meydana gelirse , hataya neden olan sütun / alanın bulunduğu tabloyu tekrar UPDATEkontrol edin JOIN.

Benim durumumda JOIN, bunun nedeni, Andriy'nin işaret ettiği gibi, bilinmeyen bir alan nedeniyle aynı hatayı oluşturan kendinin eksikliğinden kaynaklanıyordu .


1

Bunun yerine aşağıdaki gibi tablolara katılmayı deneyebilirsiniz,

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

Bu çalışmalı


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;

Çok parçalı ilişkili sorun ortaya çıkarsa, takma ad kullanmak yerine tablo adlarını kullanın.
SVaidya

1

Benim hatam tabloda olmayan bir alan kullanmak oldu.

table1.field1 => mevcut değil

table2.field1 => doğru

Tablo Adınızı düzeltin.

hatası nedeniyle WITH kullanıldı

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

diğer tablolarla birleştirildiğinde kullanıldığında ...


1

Bazı masalara katılmayı unuttunuz mu? Değilse, muhtemelen bazı takma adlar kullanmanız gerekir.


1

Ben de bu hatayla uğraşıyordum ve cevap ile aynı stratejiyi buldum. Sadece bunun işe yaraması gereken bir strateji olduğunu doğrulamak için cevabımı dahil ediyorum.

İşte veri var biliyorum iki tablo arasında ilk bir iç birleştirme yaptığım bir örnek ve sonra boş olabilir karşılık gelen satırları olabilir tablolarda iki sol dış birleşimler. Tablolar arasında varsayılan virgülle ayrılmış sözdizimi yapmak ve istediğiniz birleşimdeki satırları kaçırmak yerine, tablolardaki verilerle sonuç almak için iç birleşimleri ve dış birleşimleri karıştırırsınız.

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

İlk olarak: Veri eşleşmesini beklediğiniz tablolar arasındaki iç birleşimleri yapın. İkinci bölüm: Diğer tablolardaki verileri almaya çalışmak için dış birleşimlere devam edin, ancak tablo dış birleşiminin karşılık gelen verileri yoksa veya açık / koşulda ayarladığınız koşulla eşleşmediği takdirde sonuç kümenizi filtrelemez.


0

Bu hata ,, SELECT deyimindeki sütun adları arasında virgül bulunmamasından da kaynaklanabilir .

Örneğin:

SELECT MyCol1, MyCol2 MyCol3 FROM SomeTable;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.