Неоднозначное имя столбца в выражении Sql

У меня есть две таблицы; они объединены подробными сведениями об имени столбца через Delphi ado link

1-я таблица содержит набор данных и fileref в качестве ключа 1, 2-я таблица содержит строки данных и fileref в качестве ключа 2

1-я таблица содержит другую информацию, но одно значение fileref, 2-я таблица содержит много значений fileref, но разные учетные записи

Таблица 1: id, fileref, 1, 2, 3, 4, 5, accno, 7, 8, 9 и т. Д. И т. Д.

таблица 2: id, fileref, accno

  SELECT * FROM vtindex a
  JOIN vi_accno b
  ON b.fileref = a.FileRef
  WHERE (a.AccNo like '%123456789%') or (b.accno like '%123456789%')

Выше запрос, где я получаю неоднозначную ошибку

идея состоит в том, что если я не нахожу таблицу доступа к таблице 1, она должна попытаться найти ее в таблице 2

надеюсь, что это имеет смысл, и что странно, что если я запускаю запрос внутри MSSMS, запрос возвращает результаты без ошибок

5 ответов

Решение

Вы должны будете объявить свои столбцы, что-то вроде этого;

SELECT
     a.ID A_ID
    ,a.fileref A_fileref
    ,a.Field1 A_Field1
    ,a.Field2 A_Field2
    ,a.accno A_Accno
    ,b.id B_ID
    ,b.fileref B_fileref
    ,b.accno B_accno
FROM vtindex a
JOIN vi_accno b
    ON a.fileref = b.fileref
WHERE a.AccNo like '%123456789%'
    OR b.accno like '%123456789%'

Если вы хотите объявить только некоторые из них, сделайте это;

SELECT
     a.*
    ,b.id B_ID
    ,b.fileref B_fileref
    ,b.accno B_accno
FROM vtindex a
JOIN vi_accno b
    ON a.fileref = b.fileref
WHERE a.AccNo like '%123456789%'
    OR b.accno like '%123456789%'

Ваша проблема в том, что вы используете такие поля, как id, fileref а также accno более одного раза (из каждой таблицы) и имена конфликтуют. Если вы измените имена в своей таблице, в которой есть только 3 записи, вы можете оставить таблицу как есть.

Просто попробуйте заменить * с явными именами столбцов и определения уникальных псевдонимов для каждого из столбцов. Это решит ошибку неоднозначности. Ниже приведен пример:

Обновлено:

SELECT a.*,b.Id as b_Id, b.Fileref as b_Fileref, b.accno as b_accno FROM vtindex a
JOIN vi_accno b
ON b.fileref = a.FileRef
WHERE (a.AccNo like '%123456789%') or (b.accno like '%123456789%')

Как @Joe C прокомментировал тоже, мы думаем, что вам не нужно отправлять FileRef а также b.Id колонны внутри vi_accno к выводу, если наше предположение верно, то вы можете удалить их из вашего выбора и упростить его следующим образом:

SELECT a.*, b.accno as b_accno FROM vtindex a
JOIN vi_accno b
ON b.fileref = a.FileRef
WHERE (a.AccNo like '%123456789%') or (b.accno like '%123456789%')

У вас есть одинаковое имя столбца в обеих таблицах, поэтому использование * вытягивает оба, и имена конфликтуют. В SSMS вам разрешено делать это, поскольку вы только просматриваете результаты на экране, но как только вы отправляете данные в место назначения, которое ожидает, что имена столбцов будут уникальными, вы получите ошибку. Вам нужно будет явно указать имена нужных вам столбцов в списке выбора.

Кроме того, основываясь на вашем вопросе, я думаю, вы захотите использовать coalesce (b.accno, a.accno). Это будет использовать accno от A, только если accno равно нулю в B.

РЕДАКТИРОВАТЬ: Основываясь на комментариях, я считаю, что здесь конкретный синтаксис, который я имел в виду. Обратите внимание, как coalesce решает проблему псевдонимов столбцов, имея только одно поле с нужным именем.

SELECT ID, FileRef, cnum, Month, Type, Typei, 
       PropDesc, Coalesce(a.accno, b.accno) AccNo, person, client, idno,        
       Consultant, Memo, qclose, vtdate 
    FROM vtindex a
    Join vi_accno b ON b.fileref = a.FileRef
    WHERE (a.AccNo like '%123456789%') or (b.accno like '%123456789%')

Попробуй это,

SELECT a.*,b.* FROM vtindex a
    JOIN vi_accno b
    ON b.fileref = a.FileRef
    WHERE (a.AccNo like '%123456789%') or (b.accno like '%123456789%')

Я догадываюсь, что ваша проблема возникает не столько из Sql, который вы пытаетесь использовать, а из-за того, как вы пытаетесь его построить, используя совершенно ненужный и подверженный ошибкам SQL.Add().

Приведенный ниже код выполняется правильно и без каких-либо жалоб или ошибок в D7 для 2 таблиц в базе данных Sql Server 2014.

procedure TForm1.FormCreate(Sender: TObject);
var
  S : String;
begin
  // WARNING: Do not use this Sql in a live application
  // There is a risk of Sql-Injection because  the Sql includes the
  // contents of Edit1.Text.  Use a parameterised query instead!
  S := 'select a.*, b.*'#13#10;
  S := S + 'from TableA a join TableB b'#13#10;  // the #13#10 can be replaced by a single space, 
  //  if you prefer
  S := S + 'on a.fileref = b.fileref'#13#10;
  S := S + 'where (a.accno like ''%' + Edit1.Text + '%'')'#13#10;
  S := S + 'or (b.accno like ''%' + Edit1.Text + '%'')'#13#10;

  AdoQuery1.SQL.Text := S;
  AdoQuery1.Open;
end;

Обратите внимание на использование одинарных кавычек, без двойных кавычек.

ВАЖНО Построение Sql непосредственно из содержимого элементов управления TEdit делает ваше приложение ответственным за Sql Injection ( https://en.wikipedia.org/wiki/SQL_injection). Вы должны использовать параметризованный Sql вместо этого. Тем не менее, сказав, что подпрограмма в AdoDB.Pas, которая анализирует Sql для создания параметров, TAdoCommand.ParseSql, похоже, не работает в D7-Delphi Seattle, потому что кажется неспособной распознать параметр, встроенный в конструкцию `LIKE', которая включает в себя строковое выражение. Обходным путем может быть определение сохраненного процесса на сервере, который выполняет SQL с параметрами, предоставляемыми во время выполнения из приложения.

Итак, я предполагаю, что, поскольку вы используете SQL.Add(), на самом деле вы не создаете Sql, как вы думаете. Я подозреваю, что ошибка, которую вы получаете, на самом деле пытается сказать вам, что Edit1.Text является неоднозначным - в зависимости от вашего точного фактического Sql, возможно, синтаксический анализатор Sql думает, что Edit1.Text - это имя столбца.

Sql DDL для таблицы A и таблицы B:

CREATE TABLE [dbo].[TableA](
    [ID] [int] NOT NULL,
    [FileRef] [int] NULL,
    [AccNo] [varchar](32) NULL,
PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

CREATE TABLE [dbo].[TableB](
    [ID] [int] NOT NULL,
    [FileRef] [int] NULL,
    [AccNo] [varchar](32) NULL,
PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
Другие вопросы по тегам