Mã định danh đa phần không thể bị ràng buộc


196

Tôi đã thấy các lỗi tương tự trên SO, nhưng tôi không tìm thấy giải pháp cho vấn đề của mình. Tôi có một truy vấn SQL như:

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;

Khi tôi thực hiện truy vấn này, kết quả lỗi là: Không thể ràng buộc định danh nhiều phần "a.maxa". Tại sao?
P / s: nếu tôi chia truy vấn thành 2 truy vấn riêng lẻ, nó sẽ chạy ổn.

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;

Liệu phuongxabảng bao gồm một cột maxa?
Michael Petrotta

1
Điều gì xảy ra nếu bạn thêm nhóm theo maxa, tong - ngay sau ngày 5 tháng 9 năm 2011
user710502

Đúng nó có. Nếu tôi chia truy vấn thành 2 truy vấn con, nó sẽ chạy ổn
PhạmMinh

Âm thanh như bạn đang thực hiện trên cơ sở dữ liệu sai. Thêm câu lệnh "USE [tên cơ sở dữ liệu]" vào đầu truy vấn và xem bạn có còn gặp lỗi không.
brian

1
Không, tôi đã nói ở trên, nếu tôi chia truy vấn thành 2 truy vấn riêng lẻ, nó sẽ chạy okey.
PhạmMinh

Câu trả lời:


226

Bạn đang trộn các phép nối ngầm với các phép nối rõ ràng. Điều đó được cho phép, nhưng bạn cần lưu ý làm thế nào để làm điều đó đúng.

Vấn đề là, các phép nối rõ ràng (các phép nối được triển khai bằng JOINtừ khóa) được ưu tiên hơn các phép nối ẩn (phép nối 'dấu phẩy', trong đó điều kiện nối được chỉ định trong WHEREmệnh đề).

Đây là một phác thảo về truy vấn của bạn:

SELECT
  
FROM a, b LEFT JOIN dkcd ON 
WHERE 

Bạn có thể đang mong đợi nó hoạt động như thế này:

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

đó là sự kết hợp của các bảng abđược nối với bảng dkcd. Trong thực tế, những gì đang xảy ra là

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

nghĩa là, như bạn có thể đã hiểu, dkcdđược tham gia cụ thể bvà chỉ b, sau đó kết quả của phép nối được kết hợp với avà được lọc thêm với WHEREmệnh đề. Trong trường hợp này, bất kỳ tham chiếu nào atrong ONmệnh đề đều không hợp lệ, akhông xác định được tại thời điểm đó. Đó là lý do tại sao bạn nhận được thông báo lỗi.

Nếu tôi là bạn, có lẽ tôi sẽ cố gắng viết lại truy vấn này và một giải pháp khả thi có thể là:

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

Ở đây các bảng abđược nối trước, sau đó kết quả được nối tới dkcd. Về cơ bản, đây là cùng một truy vấn của bạn, chỉ sử dụng một cú pháp khác nhau cho một trong các phép nối, điều này tạo ra sự khác biệt lớn: tham chiếu a.maxatrong dkcdđiều kiện nối của bây giờ hoàn toàn hợp lệ.

Như @Aaron Bertrand đã lưu ý chính xác, có lẽ bạn nên đủ điều kiện maxavới một bí danh cụ thể, có thể a, trongORDER BY mệnh đề.


ĐẶT HÀNG B maxNG maxa vẫn còn mơ hồ, phải không? Ngoài ra, tôi nên cẩn thận với 'ngày 1 tháng 9 năm 2011', sẽ không hoạt động với các cài đặt ngôn ngữ / khu vực khác nhau.
Aaron Bertrand

@Aaron: Đồng ý về ORDER BY maxa, cảm ơn. Về ngày tháng, tôi tin rằng đó là cách OP đã chọn để chỉ định chúng trong môi trường của họ.
Andriy M

"Tham gia rõ ràng ... được ưu tiên hơn những người tiềm ẩn" - bạn có thể cung cấp một trích dẫn cho việc này không? ví dụ như được xác định trong Tiêu chuẩn SQL hay nó là một tính năng của sản phẩm? Cảm ơn.
onedaywhen

1
@encedaywhen: Tôi sợ điều này không hơn gì một quan sát về phía tôi cho đến nay. Tôi cảm thấy nhẹ nhõm vì thực tế rằng tôi không phải là người đầu tiên nói về sự ưu tiên của việc tham gia ở đây, nhưng ngoài điều đó, tôi sẽ rất vui khi tìm thấy bất kỳ loại xác nhận chính thức nào.
Andriy M

1
Trong trường hợp của tôi, tôi đã quên đặt khoảng trắng khi tôi nối các chuỗi để xây dựng sql, vì vậy 'TỪ dbo.table_a a' + 'INNER THAM GIA dbo.table_b b' đã trở thành 'TỪ dbo.table_a aINNER THAM GIA dbo.table_b b', và nó đã bị nhầm lẫn và đưa cho tôi thông báo lỗi này. Chi tiết, chi tiết, chi tiết.
Guy Schalnat

40

Đôi khi lỗi này xảy ra khi bạn sử dụng lược đồ (dbo) trong truy vấn của bạn một cách sai.

ví dụ nếu bạn viết:

select dbo.prd.name
from dbo.product prd

bạn sẽ nhận được lỗi.

Trong tình huống này, thay đổi nó thành:

select prd.name
from dbo.product prd

1
Điều này khá khó chịu và khiến tôi mất quá nhiều thời gian để tìm ra nó. Thanx. Phần khó chịu nhất đôi khi là cằn nhằn về điều này nhưng lần khác nó lại vượt qua bình thường
DanteTheSmith

12

nếu bạn đã cho tên đồng minh thay đổi tên đó thành tên thật

ví dụ

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;

thay đổi nó thành

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

1
Ngoài ra, nếu bạn đang xây dựng chuỗi sql, hãy coi chừng thiếu khoảng trống ở cuối dòng. Nó đã chuyển đổi bí danh M của tôi thành MINNER khi tham gia dòng INNER THAM GIA tiếp theo bên dưới. SQL profiler hiển thị chuỗi thực thi đã giúp giải quyết vấn đề của tôi. (Bình luận ở đây vì nó có liên quan đến vấn đề tên bí danh v)
Simon

wow @Simon cảm ơn bạn Tôi thậm chí không nghĩ về điều này và đập đầu vào tường cố gắng tìm ra lý do tại sao truy vấn của tôi không hoạt động, tôi đã bỏ lỡ một khoảng trống ở cuối một trong các chuỗi vận chuyển trở lại!
buradd

9

Tôi đã vật lộn với cùng một thông báo lỗi trong SQL SERVER, vì tôi có nhiều phép nối, việc thay đổi thứ tự của các phép nối đã giải quyết nó cho tôi.


3

Trong trường hợp của tôi, vấn đề hóa ra là tên bí danh mà tôi đã đặt cho bảng. "Oa" dường như không được chấp nhận đối với SQL Server.


2

Tôi đã có cùng một lỗi từ JDBC. Kiểm tra mọi thứ và truy vấn của tôi là tốt. Hóa ra, trong đó mệnh đề tôi có một đối số:

where s.some_column = ?

Và giá trị của đối số mà tôi đã truyền vào là null. Điều này cũng đưa ra cùng một lỗi gây hiểu lầm bởi vì khi bạn tìm kiếm trên internet, bạn sẽ thấy có gì đó không đúng với cấu trúc truy vấn nhưng không phải trong trường hợp của tôi. Chỉ cần nghĩ rằng ai đó có thể phải đối mặt với cùng một vấn đề


2

Điều làm việc cho tôi là thay đổi mệnh đề WHERE của tôi thành truy vấn con CHỌN

TỪ:

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

ĐẾN:

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

1

Tôi chưa quen với SQL, nhưng đã gặp phải vấn đề này trong một khóa học tôi đang tham gia và thấy rằng việc gán truy vấn cho dự án đặc biệt giúp loại bỏ lỗi đa phần. Ví dụ, dự án tôi đã tạo là CTU SQL Project vì vậy tôi chắc chắn rằng tôi đã bắt đầu tập lệnh của mình với USE [CTU SQL Project] như dòng đầu tiên của tôi như bên dưới.

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

1
Khi bạn nói "dự án", tôi giả sử bạn có nghĩa là cơ sở dữ liệu và không chiếu. Câu lệnh sử dụng chỉ đơn giản là thay đổi cơ sở dữ liệu mà bạn đang tìm kiếm truy vấn
Charleh

Có, dự án Charleh như trong cơ sở dữ liệu tôi đang làm việc. Tôi không chắc chắn những gì tôi đã làm sai với cơ sở dữ liệu của mình, nhưng nêu rõ "sử dụng" và cơ sở dữ liệu cụ thể để phạm vi loại bỏ lỗi của tôi.
Bogartz

1

Nếu lỗi này xảy ra trong một UPDATE, hãy kiểm tra kỹ JOINtrên bảng với cột / trường gây ra lỗi.

Trong trường hợp của tôi, điều này là do thiếu JOINchính nó, điều này tạo ra lỗi tương tự do một trường không xác định (như Andriy đã chỉ ra ).


1

Thay vào đó, bạn có thể thử tham gia các bảng như,

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

Điều này sẽ làm việc


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;

Sử dụng tên bảng thay vì sử dụng bí danh nếu vấn đề ràng buộc nhiều phần xuất hiện.
SVaidya

1

Lỗi của tôi là sử dụng một trường không tồn tại trong bảng.

bảng1.field1 => không tồn tại

bảng2.field1 => là chính xác

Đúng tên bảng của bạn.

lỗi của tôi xảy ra do sử dụng VỚI

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

khi được sử dụng để tham gia với các bảng khác ...


1

Bạn đã quên tham gia một số bảng? Nếu không thì có lẽ bạn cần sử dụng một số bí danh.


1

Tôi cũng đang vật lộn với lỗi này và kết thúc với chiến lược giống như câu trả lời. Tôi bao gồm câu trả lời của mình chỉ để xác nhận rằng đây là một chiến lược nên hoạt động.

Dưới đây là một ví dụ nơi tôi thực hiện một phép nối bên trong đầu tiên giữa hai bảng tôi biết có dữ liệu và sau đó hai phép nối ngoài bên trái trên các bảng có thể có các hàng tương ứng có thể trống. Bạn trộn các phép nối bên trong và các phép nối ngoài để có kết quả với dữ liệu qua các bảng thay vì thực hiện cú pháp được phân tách bằng dấu phẩy mặc định giữa các bảng và bỏ lỡ các hàng trong phép nối mong muốn của bạn.

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

Đầu tiên: Thực hiện các phép nối bên trong giữa các bảng mà bạn muốn có dữ liệu khớp. Phần thứ hai: Tiếp tục với các phép nối ngoài để cố truy xuất dữ liệu trong các bảng khác, nhưng điều này sẽ không lọc ra tập kết quả của bạn nếu nối ngoài bảng không có dữ liệu tương ứng hoặc khớp với điều kiện bạn thiết lập trong vị ngữ / điều kiện.


0

Lỗi này cũng có thể được gây ra bởi đơn giản là thiếu dấu phẩy , giữa các tên cột trong câu lệnh SELECT.

ví dụ:

SELECT MyCol1, MyCol2 MyCol3 FROM SomeTable;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.