我有两张桌子;它们通过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中运行查询,查询返回结果没有错误
答案 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%'
您的问题是您不止一次使用id
,fileref
和accno
等字段(来自每个表格)并且名称发生冲突。如果您更改表格中只有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
所述,我们认为您不需要将FileRef
和b.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 Injection
(https://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]