Многокомпонентный идентификатор не может быть связан


197

Я видел похожие ошибки на 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». Зачем?
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;

Имеет ли phuongxaвключать в таблицу столбец maxa?
Майкл Петротта

1
Что произойдет, если вы добавите группу по maxa, tong - сразу после 5 сентября 2011 г.
user710502

Да, это так. Если я разделю запрос на 2 подзапроса, он будет работать нормально
PhamMinh

Похоже, вы выполняете на неправильной базе данных. Добавьте оператор «USE [database name]» в начало запроса и посмотрите, по-прежнему ли вы получаете ошибку.
Брайан

1
Нет, я уже говорил выше, если я разделю запрос на 2 отдельных запроса, он запустится.
PhamMinh

Ответы:


226

Вы смешиваете неявные объединения с явными объединениями. Это разрешено, но вы должны знать, как это сделать правильно.

Дело в том, что явные объединения (те, которые реализованы с использованием 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условии соединения теперь абсолютно действительна.

Как правильно заметил @Аарон Бертран, вам, вероятно, следует указать maxaконкретный псевдоним, возможно a, в ORDER BYпредложении.


ЗАКАЗАТЬ МАКСУ все еще неоднозначно, нет? Также я буду осторожен с датой 1 сентября 2011 года, она не будет работать с другими языковыми / региональными настройками.
Аарон Бертран

@ Аарон: Согласитесь ORDER BY maxa, спасибо. Что касается дат, я полагаю, что именно так ФП решила указать их в своей среде.
Андрей М

«явные объединения ... имеют приоритет над неявными» - не могли бы вы привести цитату для этого, пожалуйста? Например, это определено в стандартах SQL или это особенность продукта? Спасибо.
1

1
@onedaywhen: Боюсь, это пока что не более чем наблюдение с моей стороны. Меня несколько радует тот факт, что я не первый, кто говорит о приоритетности соединений здесь, но кроме этого, я был бы рад найти какое-либо официальное подтверждение сам.
Андрей М

1
В моем случае я забыл ставить пробелы, когда объединял строки для построения sql, поэтому «FROM dbo.table_a a» + «INNER JOIN dbo.table_b b» стал «FROM dbo.table_a aINNER JOIN dbo.table_b b», и он запутался и дал мне это сообщение об ошибке. Детали, детали, подробности.
Гай Шалнат

40

Иногда эта ошибка возникает при неправильном использовании схемы (dbo) в запросе.

например, если вы напишите:

select dbo.prd.name
from dbo.product prd

вы получите ошибку.

В этих ситуациях измените его на:

select prd.name
from dbo.product prd

1
Это довольно раздражает и заняло у меня слишком много времени, чтобы понять это. Thanx. Больше всего раздражает то, что иногда это раздражает, но иногда это проходит
нормально

12

если вы дали псевдоним, измените его на фактическое

например

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;

изменить это на

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

1
Также, если вы создаете строку sql, следите за отсутствием пробелов в конце строки. Он преобразовал мой псевдоним M в MINNER, когда присоединился к следующей строке INNER JOIN ниже. SQL profiler, показывающий выполненную строку, помог решить мою проблему. (Здесь прокомментировано, как оно связано с проблемой псевдонима против фактического имени)
Simon

wow @Simon спасибо, я даже не думал об этом и стучал головой о стену, пытаясь выяснить, почему мой запрос не работал, мне не хватало пробела в конце одного из возвратов строки!
buradd

9

Я боролся с тем же сообщением об ошибке в SQL SERVER, так как у меня было несколько объединений, изменение порядка объединений решило это для меня.


3

В моем случае проблема оказалась в псевдониме, который я дал таблице. «oa» кажется неприемлемым для SQL Server.


2

У меня была такая же ошибка от JDBC. Все проверил, и мой запрос был в порядке. Оказалось, в предложении где у меня есть аргумент:

where s.some_column = ?

И значение аргумента, который я передавал, был нулевым. Это также дает ту же ошибку, которая вводит в заблуждение, потому что при поиске в Интернете вы обнаружите, что что-то не так со структурой запроса, но это не в моем случае. Просто думал, что кто-то может столкнуться с той же проблемой


2

Для меня сработало изменение предложения WHERE в подзапрос SELECT.

ИЗ:

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

TO:

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

1

Я новичок в SQL, но столкнулся с этой проблемой в ходе обучения и обнаружил, что назначение запроса проекту помогло устранить ошибку, состоящую из нескольких частей. Например, проект, который я создал, был CTU SQL Project, поэтому я убедился, что начал свой сценарий с USE [CTU SQL Project] в качестве моей первой строки, как показано ниже.

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

1
Когда вы говорите «проект», я предполагаю, что вы имеете в виду базу данных, а не проекцию. Оператор использования просто меняет базу данных, к которой вы выполняете запрос
Charleh

Да, проект Charleh как в базе данных у меня работал. Я не был уверен, что я делал неправильно с моей базой данных, но указание «использования» и конкретной базы данных для области действия устранило мою ошибку.
Богарц

1

Если эта ошибка возникает в UPDATE, дважды проверьте JOINтаблицу со столбцом / полем, которое вызывает ошибку.

В моем случае это было связано с отсутствием JOINсамого, который генерировал ту же ошибку из-за неизвестного поля (как указал Андрей ).


1

Вместо этого вы можете попробовать объединить таблицы, как,

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

Это должно работать


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;

Используйте имена таблиц вместо использования псевдонимов, если возникает проблема, связанная с несколькими частями.
SVaidya

1

Моя ошибка заключалась в использовании поля, которого не было в таблице.

table1.field1 => не существует

table2.field1 => правильно

Исправьте свое имя таблицы.

моя ошибка произошла из-за использования WITH

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

при использовании в соединении с другими таблицами ...


1

Вы забыли присоединиться к некоторым столам? Если нет, то вам, вероятно, нужно использовать псевдонимы.


1

Я также боролся с этой ошибкой и в итоге использовал ту же стратегию, что и ответ. Я включил свой ответ, чтобы подтвердить, что это стратегия, которая должна работать.

Вот пример, где я делаю сначала одно внутреннее соединение двух таблиц, которые, как я знаю, получили данные, а затем два левых внешних объединения таблиц, которые могут иметь соответствующие строки, которые могут быть пустыми. Вы смешиваете внутренние и внешние объединения, чтобы получить результаты с данными по таблицам, вместо того, чтобы использовать синтаксис по умолчанию, разделенный запятыми, между таблицами и пропустить строки в желаемом соединении.

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

Во-первых: выполните внутренние объединения между таблицами, которые, как вы ожидаете, будут соответствовать данным. Вторая часть: Продолжите с внешними объединениями, чтобы попытаться получить данные в других таблицах, но это не отфильтрует ваш результирующий набор, если внешнее объединение таблицы не получило соответствующих данных или не соответствует условию, которое вы установили в предикате / условии on.


0

Эта ошибка также может быть вызвана отсутствием запятой , между именами столбцов в операторе SELECT.

например:

SELECT MyCol1, MyCol2 MyCol3 FROM SomeTable;
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.