2016-06-22 12 views
3

Ich habe zwei Tabellen; sie sind durch Beziehung Detail auf einem Spaltennamen über Delphi ADO LinkMehrdeutiger Spaltenname in Sql-Ausdruck

1. Tabelle Reihe von Daten und eine fileref als Schlüssel 1, trat 2. Tabelle hat Zeilen von Daten und einen fileref als Schlüssel 2

1. Tabelle hat andere Informationen, sondern einen fileref Wert, 2. Tabelle viele fileref Werte, sondern verschiedene Konten

Tabelle 1 gelten: id, fileref, 1, 2, 3, 4, 5, KONTNR, 7, 8, 9, usw., etc ...

Tabelle 2: id, fileferec, accno 2

Hoffnung

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

Oben ist die Abfrage, wo ich die mehrdeutigen Fehler

die Idee ist, dass wenn ich nicht finden, die KONTNR ist Tabelle 1 muss es in Tabelle versuchen und finden dies macht Sinn und was wierd ist, dass, wenn ich die Abfrage in MSSMS die Abfrage gibt Ergebnisse ohne Fehler

+2

Änderung es sich um eine SELECT *, b * –

+0

@RichBenner nicht funktioniert m8 – Troz

+0

ich als Antwort nur geschrieben haben, werfen Sie einen Blick und sehen, wenn es es löst. –

Antwort

5

Sie müssen Ihre Spalten erklären, so etwas;

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

Wenn Sie nur einige deklarieren möchten, tun Sie dies;

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

Ihr Problem ist, dass Sie Felder verwenden wie id, fileref und accno mehr als einmal (aus jeder Tabelle) und die Namen werden kollidierende. Wenn Sie die Namen in Ihrer Tabelle ändern, die nur 3 Datensätze enthält, können Sie mit dem Verlassen der Tabelle fortfahren.

+0

Dies löste mein Problem, ich benannte die Felder auf der zweiten Tabelle und lief mit dieser Abfrage: SELECT a. *, b. * FROM vtindex ein JOIN vi_accnot b ON b.vifileref = a.FileRef WHERE (a.AccNo like ' '%' + edit1.text + '%' ') oder (b.viaccno wie' '%' + edit1.Text + '%' ') – Troz

+0

so infact jeder geholfen, die Richtung, auf die ich die Antwort bekam, also danke allen – Troz

+0

nur um seinen Bezug zu "Wenn Sie die Namen auf Ihrem Tisch ändern, die nur 3 Datensätze hat, dann können Sie weg mit dem Verlassen der Tabelle ein wie es ist." war die Antwort im Klicken auf ... – Troz

2

Geben Sie einfach ersetzen * mit expliziten Spaltennamen und eindeutige Aliase für jede der Spalten definieren. Dies wird den Mehrdeutigkeitsfehler lösen. Es folgt ein Beispiel:

Aktualisiert:

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

Als @Joe C auch kommentiert, denken wir, Sie brauchen nicht FileRef und b.Id Spalten innerhalb vi_accno an den Ausgang zu schicken, wenn unsere Annahme richtig ist, dann Sie können sie von Ihrem Select entfernen und wie folgt vereinfachen:

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

yikes das ist eine Menge von Spaltenreferenzen, gibt es nicht einen einfacheren Weg – Troz

+0

Es gibt kostenlose Tools, die dies einfacher machen. Für SSMS verwende ich manchmal Apex Sql Complete, um automatisch die Auswahlliste zu erstellen. –

+0

@Troz können Sie Tools von Drittanbietern wie 'Apex' oder 'RedGate SQL Toolbelt' verwenden. Oder Sie können Ihre Abfrage auswählen, dann mit der rechten Maustaste darauf klicken und 'Abfrage im Editor bearbeiten' auswählen.Mit diesen Optionen können Sie die Spalten und ihre Aliase verwalten. –

1

Try this,

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

Dies wird den gleichen Fehler wie accno existiert in a und b. –

+0

Kopieren Sie einfach den Fehler und fügen Sie ihn hier ein. – DineshDB

+0

dies funktioniert nicht "das Spaltenpräfix" a 'stimmt nicht mit einem Tabellennamen oder Aliasnamen in der Abfrage " – Troz

2

Sie haben den gleichen Spaltennamen in beiden Tabellen, also mit * zieht beide und die Namen Konflikt. In SSMS können Sie dies tun, da Sie nur die Ergebnisse auf dem Bildschirm anzeigen, aber sobald Sie die Daten an ein Ziel senden, das erwartet, dass Spaltennamen eindeutig sind, erhalten Sie einen Fehler. Sie müssen die gewünschten Spalten explizit in Ihrer Auswahlliste benennen.

Auch, basierend auf Ihrer Frage glaube ich, dass Sie Coalesce (b.accno, a.accno) verwenden möchten. Dies wird die accno von A nur verwenden, wenn accno N in B ist.

EDIT: Basierend auf Kommentaren glaube ich hier ist die spezifische Syntax, die ich bezog. Beachten Sie, wie Coalesce das Problem von Spaltenaliasen lösen kann, indem Sie nur ein Feld mit dem gewünschten Namen haben.

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

mehrdeutige Spalte Name ID, ich dann ID aus dem SQL entfernen, dann klagt es über mehrdeutige Spalte Name fileferec? lol – Troz

1

Ich habe eine Ahnung, dass Ihr Problem entsteht nicht so sehr von der SQL, die Sie versuchen zu verwenden, aber die Art, wie Sie versuchen, es zu konstruieren, mit der völlig unnötigen und fehleranfällige SQL.Add().

Der folgende Code wird korrekt und ohne Beanstandung oder Fehler in D7 gegen 2 Tabellen in einer Sql Server 2014-Datenbank ausgeführt.

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; 

Beachten Sie die Verwendung von einfachen Anführungszeichen, keine Anführungszeichen.

WICHTIG Constructing Sql direkt von den Inhalten TEdit Kontrollen macht die App haftet Sql Injection (https://en.wikipedia.org/wiki/SQL_injection). Sie sollten stattdessen parametrisierte Sql verwenden. Allerdings scheint , dass die Routine in AdoDB.Pas, die die SQL analysiert, um die Parameter zu erstellen, TAdoCommand.ParseSql scheint in D7-Delphi Seattle gebrochen werden, weil es unfähig scheint, einen Parameter in einem "LIKE" eingebettet zu erkennen Konstrukt, das einen String-Ausdruck beinhaltet. Eine Möglichkeit wäre es, einen Stored Proc auf dem Server zu definieren, der das SQL mit Parametern ausführt, die zur Laufzeit von der Anwendung geliefert werden.

Also, meine Vermutung ist, dass, weil Sie SQL.Add() verwenden, tatsächlich Sie nicht die Sql konstruieren, die Sie denken, dass Sie sind. Ich vermute, dass der Fehler, den Sie erhalten, tatsächlich versucht, Ihnen zu sagen ist, dass Edit1.Text mehrdeutig ist - abhängig von Ihrer genauen tatsächlichen SQL, möglicherweise der Sql-Parser denkt Edit1.Text ist der Name einer Spalte.

Die SQL-DDL für TableA und TableB:..

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] 
+0

Nichts falsch mit SQL.Add, wo ist das OP sagen, dass er das tut ?. Auf der anderen Seite erstellen Sie niemals SQL, wenn Sie nicht müssen. Ihr Codebeispiel ist anfällig für SQL-Injection, passen Sie es bitte an (die Leute werden Ihre Antwort lesen und kopieren/einfügen, ohne nachzudenken). Immer (und ich meine IMMER) Parameter verwenden ... – whosrdaddy

+0

@whosrdaddy: Ich werde die Antwort in einem mo anpassen. Inzwischen wo? In einem Kommentar des OP zur Antwort von DineshDB "exakter Code: form3.adoquery1.SQL.Add ('SELECT a. *, B. * FROM vtindex a'); form3.adoquery1.SQL.Add ('JOIN vi_accno b '); form3.adoquery1.SQL.Add (' ON a.fileref = b.FileRef '); form3.adoquery1.SQL.Add (' WHERE (a.AccNo wie ''% '+ edit1.text +'% '') oder (b.accno wie ''% '+ edit1.Text +'% ''); " – MartynA

+0

@whosrdaddy: Übrigens stimme ich zu, dass es im Prinzip * nichts falsches mit SQL.Add() gibt, so scheint es Ungewöhnlich häufig in SO qs mit fehlerhafter SQL zu tun. – MartynA