Sql 表达式中的列名不明确

Ambiguous Column name in Sql expression

我有两个table;它们通过 Delphi ado link

通过列名称上的关系详细信息连接

1st table 有一堆数据和一个 fileref 作为键 1, 第二个 table 有数据行和一个文件引用作为键 2

1st table 除了一个 fileref 值外还有其他信息, 第二个 table 包含许多文件引用值但不同的帐户

Table 1: id, fileref, 1, 2, 3, 4, 5, accno, 7, 8, 9, 等等...

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

以上是我得到不明确错误的查询

我的想法是,如果我找不到 accno 是 table 1,它必须尝试在 table 2

中找到它

希望这是有道理的,奇怪的是,如果我 运行 MSSMS 中的查询查询 returns 结果没有错误

只需尝试用明确的列名替换 * 并为每个列定义唯一的别名。这将解决歧义错误。下面是一个例子:

更新:

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 也评论的那样,我们认为您不需要将 vi_accno 内的 FileRefb.Id 列发送到输出,如果我们的假设是正确的,然后您可以将它们从 Select 中删除并简化如下:

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

试试这个,

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

您在两个表中具有相同的列名,因此使用 * 提取两者并且名称冲突。在 SSMS 中,您可以这样做,因为您只能在屏幕上查看结果,但是一旦您将数据发送到期望列名唯一的目的地,您就会收到错误消息。您必须在 select 列表中明确命名您想要的列。

此外,根据您的问题,我相信您会想要使用 coalesce(b.accno, a.accno)。仅当 B 中的 accno 为 null 时,才会使用 A 中的 accno。

编辑:根据评论,我相信这里是我所指的特定语法。请注意 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.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%'

您的问题是您不止一次使用 idfilerefaccno 等字段(来自每个 table)并且名称冲突。如果您更改只有 3 条记录的 table 上的名称,那么您可以让 table 保持原样。

我有一种预感,你的问题不是由你尝试使用的 Sql 引起的,而是你尝试构建它的方式,使用完全不必要且容易出错的 SQL.Add().

下面的代码在 D7 中针对 Sql Server 2014 数据库中的 2 个表正确执行并且没有任何类型的投诉或错误。

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;

注意全文使用单引号,没有双引号。

重要 直接从 TEdit 控件的内容构造 Sql 会使您的应用程序受到 Sql Injection (https://en.wikipedia.org/wiki/SQL_injection) 的约束。您应该改用参数化 Sql 。然而, 话虽如此,AdoDB.Pas 中解析 Sql 以创建参数的例程,TAdoCommand.ParseSql 似乎 在 D7-[=36 中被破坏=] 西雅图,因为它似乎无法识别嵌入在涉及字符串表达式的“LIKE”构造中的参数。一种解决方法可能是在服务器上定义一个存储过程,该过程使用应用程序在 运行 时提供的参数执行 SQL。

因此,我的猜测是因为您使用的是 SQL.Add(),实际上您并没有构建您认为的 Sql。我怀疑你得到的错误实际上是想告诉你 Edit1.Text 是模棱两可的——取决于你的确切实际 Sql,可能 Sql 解析器认为 Edit1.Text是列名。

表 A 和表 B 的 Sql DDL:

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]