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


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.