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

SO'da benzer hatalar gördüm, ancak sorunum için bir çözüm bulamadım. Şöyle bir SQL sorgum 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 çalıştırdığımda hata sonucu şu oluyor: Çok parçalı tanımlayıcı "a.maxa" bağlanamadı. Neden?
Not: 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;
Çözüm

Örtük birleştirmeler ile açık birleştirmeleri karıştırıyorsunuz. Buna izin verilir, ancak bunu nasıl doğru şekilde yapacağınızın farkında olmanız gerekir.

Mesele şu ki, açık birleştirmeler (JOIN anahtar sözcüğü kullanılarak uygulananlar) örtük olanlara (birleştirme koşulunun WHERE cümlesinde belirtildiği 'virgül' birleştirmeleri) göre önceliklidir.

İşte sorgunuzun ana hatları:

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

Muhtemelen bu şekilde davranmasını bekliyorsunuz:

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

yani, a ve b tablolarının birleşimi dkcd tablosu ile birleştirilir. Aslında, olan şey şudur

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

Yani, zaten anlamış olabileceğiniz gibi, dkcd özellikle b ile ve sadece b ile birleştirilir, daha sonra birleştirme sonucu a ile birleştirilir ve WHERE cümlesi ile daha fazla filtrelenir. Bu durumda, ON cümlesinde a ya yapılan herhangi bir referans geçersizdir, a o noktada bilinmemektedir. Hata mesajını almanızın nedeni budur.

Yerinizde olsaydım, muhtemelen bu sorguyu yeniden yazmayı denerdim ve olası bir çözüm şöyle 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 a ve b tabloları birleştirilir, ardından sonuç dkcd ile birleştirilir. Temel olarak, bu sizinkiyle aynı sorgudur, yalnızca birleştirmelerden biri için farklı bir sözdizimi kullanılır, bu da büyük bir fark yaratır: dkcd'nin birleştirme koşulundaki a.maxa referansı artık kesinlikle geçerlidir.

Aaron Bertrand'ın doğru bir şekilde belirttiği gibi, SORDER BY cümlesinde maxa ifadesini belirli bir takma adla, muhtemelen a ile nitelendirmelisiniz.

Yorumlar (9)

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

örneğin yazarsanız:

select dbo.prd.name
from dbo.product prd

hatasını alırsınız.

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

select prd.name
from dbo.product prd
Yorumlar (1)

SQL'de yeniyim, ancak aldığım bir kursta bu sorunla karşılaştım ve sorguyu projeye özel olarak atamanın çok parçalı hatayı ortadan kaldırmaya yardımcı olduğunu gördüm. Örneğin, oluşturduğum proje CTU SQL Projesiydi, bu yüzden betiğime aşağıdaki gibi ilk satır olarak USE [CTU SQL Projesi] ile başladığımdan emin oldum.

USE [CTU SQL Project]
SELECT Advisors.First_Name, Advisors.Last_Name...and so on.
Yorumlar (2)