Το πολυμερές αναγνωριστικό δεν μπόρεσε να δεσμευτεί

Έχω δει παρόμοια σφάλματα στο SO, αλλά δεν βρίσκω λύση για το πρόβλημά μου. Έχω ένα ερώτημα SQL όπως:

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;

Όταν εκτελώ αυτό το ερώτημα, το αποτέλεσμα του σφάλματος είναι το εξής: Το πολυμερές αναγνωριστικό "a.maxa" δεν μπόρεσε να δεσμευτεί. Γιατί; <br&gt, P/s: αν χωρίσω το ερώτημα σε 2 μεμονωμένα ερωτήματα, εκτελείται εντάξει.

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;

και

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

Ανακατεύετε τις σιωπηρές συνδέσεις με τις ρητές συνδέσεις. Αυτό επιτρέπεται, αλλά πρέπει να γνωρίζετε πώς να το κάνετε σωστά.

Το θέμα είναι ότι οι ρητές συνδέσεις (αυτές που υλοποιούνται με τη χρήση της λέξης κλειδί JOIN) έχουν προτεραιότητα έναντι των σιωπηρών (οι συνδέσεις με 'κόμμα', όπου η συνθήκη σύνδεσης καθορίζεται στη ρήτρα WHERE).

Ακολουθεί ένα περίγραμμα του ερωτήματός σας:

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

Πιθανώς περιμένετε να συμπεριφερθεί ως εξής:

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

δηλαδή, ο συνδυασμός των πινάκων a και b συνδέεται με τον πίνακα dkcd. Στην πραγματικότητα, αυτό που συμβαίνει είναι

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

δηλαδή, όπως ίσως έχετε ήδη καταλάβει, ο πίνακας dkcd συνδέεται ειδικά με τον πίνακα b και μόνο με τον πίνακα b, και στη συνέχεια το αποτέλεσμα της σύνδεσης συνδυάζεται με τον πίνακα a και φιλτράρεται περαιτέρω με τη ρήτρα WHERE. Σε αυτή την περίπτωση, οποιαδήποτε αναφορά στο a στη ρήτρα ON είναι άκυρη, το a είναι άγνωστο σε αυτό το σημείο. Αυτός είναι ο λόγος για τον οποίο λαμβάνετε το μήνυμα σφάλματος.

Αν ήμουν στη θέση σας, θα προσπαθούσα μάλλον να ξαναγράψω αυτό το ερώτημα, και μια πιθανή λύση θα μπορούσε να είναι:

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

Εδώ οι πίνακες a και b ενώνονται πρώτα, και στη συνέχεια το αποτέλεσμα συνδέεται με τον dkcd. Βασικά, αυτό είναι το ίδιο ερώτημα με το δικό σας, μόνο που χρησιμοποιείται διαφορετική σύνταξη για μία από τις συνδέσεις, η οποία κάνει μεγάλη διαφορά: η αναφορά a.maxa στη συνθήκη σύνδεσης του dkcd's είναι τώρα απολύτως έγκυρη.

Όπως σωστά σημείωσε ο @Aaron Bertrand, θα πρέπει πιθανώς να προσδιορίσετε το maxa με ένα συγκεκριμένο ψευδώνυμο, πιθανώς το a, στη ρήτρα ORDER BY.

Σχόλια (9)

Μερικές φορές αυτό το σφάλμα εμφανίζεται όταν χρησιμοποιείτε το σχήμα σας (dbo) στο ερώτημά σας με λάθος τρόπο.

Για παράδειγμα, αν γράψετε:

select dbo.prd.name
from dbo.product prd

θα λάβετε το σφάλμα.

Σε αυτές τις περιπτώσεις αλλάξτε το σε:

select prd.name
from dbo.product prd
Σχόλια (1)

Είμαι νέος στην SQL, αλλά αντιμετώπισα αυτό το ζήτημα σε ένα μάθημα που παρακολουθούσα και διαπίστωσα ότι η ανάθεση του ερωτήματος στο έργο βοήθησε ειδικά στην εξάλειψη του σφάλματος πολλαπλών μερών. Για παράδειγμα, το έργο που δημιούργησα ήταν το CTU SQL Project, οπότε φρόντισα να ξεκινήσω το σενάριό μου με USE [CTU SQL Project] ως πρώτη γραμμή, όπως παρακάτω.

USE [CTU SQL Project]
SELECT Advisors.First_Name, Advisors.Last_Name...and so on.
Σχόλια (2)