Sql表达式中的不明确的列名称

时间:2016-06-22 12:33:49

标签: sql sql-server delphi ado

我有两张桌子;它们通过Delphi ado链接

通过列名称的关系细节加入

第一个表有一堆数据,一个fileref作为键1, 第二个表有数据行,fileref为键2

第一个表有其他信息,但有一个fileref值, 第二个表包含许多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%')

上面是我得到模棱两可的错误的查询

这个想法是,如果我没有找到accno是表1,它必须尝试在表2中找到它

希望这是有道理的,如果我在MSSMS中运行查询,查询返回结果没有错误

5 个答案:

答案 0 :(得分: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%'

您的问题是您不止一次使用idfilerefaccno等字段(来自每个表格)并且名称发生冲突。如果您更改表格中只有3条记录的名称,那么您可以将表格保留为原样。

答案 1 :(得分:2)

尝试使用显式列名替换*,并为每个列定义唯一的别名。这将解决模糊错误。以下是一个例子:

<强>更新

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所述,我们认为您不需要将FileRefb.Id列发送到输出中,如果我们的假设正确,那么您可以从您的选择中删除它们并简化它,如下所示:

vi_accno

答案 2 :(得分:2)

两个表中都有相同的列名,因此使用*拉两者并且名称冲突。在SSMS中,您可以这样做,因为您只在屏幕上查看结果,但只要您将数据发送到期望列名称唯一的目标,您就会收到错误。您必须在选择列表中明确命名所需的列。

另外,根据你的问题,我相信你会想要使用coalesce(b.accno,a.accno)。如果在B中accno为空,这将使用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%')

答案 3 :(得分:1)

试试这个,

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

答案 4 :(得分:1)

我有一种预感,你的问题不是来自你试图使用的Sql,而是你尝试构建它的方式,使用完全不必要且容易出错的SQL.Add()。< / p>

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

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 Injectionhttps://en.wikipedia.org/wiki/SQL_injection)。您应该使用参数化的Sql。然而, 话虽如此,AdoDB.Pas中解析Sql创建参数的例程,TAdoCommand.ParseSql 似乎在D7-Delphi Seattle中被打破,因为它似乎无法识别嵌入在` LIKE'构造涉及字符串表达式。解决这个问题的方法可能是在服务器上定义一个Stored Proc,它使用在运行时从应用程序提供的参数来执行SQL。

所以,我的猜测是因为你使用的是SQL.Add(),实际上你并没有构建你认为自己的Sql。我怀疑你得到的错误实际上是试图告诉你Edit1.Text是不明确的 - 取决于你的确切实际Sql,可能是Sql解析器认为Edit1.Text是列的名称。

TableA和TableB的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]