Durchsuchen mehrere Felder mehrere Werte

Kissling

Benutzer
Beiträge
15
Hallo Zusammen,

leider liefert mein Selekt eine Fehlermeldung :-(
Was mache ich falsch?
Ich möchte in einer Tabelle in mehreren Feldern nach einer Liste von inhalten suchen.

Hier mein Code:
SQL:
Declare @Produkt nvarchar(50)
Set @Produkt = 'SPIRIT,AVANTi    1.Liz. *'

SELECT ID,CompanyID,RECORDID,PROGRAM1,PROGRAM2,PROGRAM3,PROGRAM4,PROGRAM5,PROGRAM6,PROGRAM7,PROGRAM8,PROGRAM9,PROGRAM10
FROM   [cRM_Solution_cosmolink_faktura_ES].[dbo].[Contacts]
WHERE
PROGRAM1  in (@Produkt) or
PROGRAM2  in (@Produkt) or
PROGRAM3  in (@Produkt) or
PROGRAM4  in (@Produkt) or
PROGRAM5  in (@Produkt) or
PROGRAM6  in (@Produkt) or
PROGRAM7  in (@Produkt) or
PROGRAM8  in (@Produkt) or
PROGRAM9  in (@Produkt) or
PROGRAM10 in (@Produkt);

Leider liefert die Abfrage keine Ergebnisse.
Wenn ich aber nur nach
Set @Produkt = 'SPIRIT'
oder nach
Set @Produkt = 'AVANTi 1.Liz. *'
suche bekomme ich die korrekten Ergebnisse.

Ich brauche aber die Ergebnisse beider Abfragen in einer Ergebnisliste


Kann mir bitt jemand sagen wo ich den Fehler mache?
Vielen Dank
 
Zuletzt bearbeitet:
Werbung:
Die meisten DB können für ein "..where <Ausdruck> in <andererAusdruck>.. " nicht über Paramterierung von <andererAusdruck> verarbeiten.

leider liefert mein Selekt eine Fehlermeldung :-(
Was mache ich falsch?
Die mehr oder weniger konkrete Antwort auf Deine Frage steht in der Fehlermeldung, die Du hier leider nicht zeigst.

Du kannst Dir einfach angewöhnen, jegliche Form von Programmierfragen mit konkreten Fehlermeldungen zu versehen. Besonders, wenn sie nicht auf Anhieb "erkennbar" sind. Das bedeutet, z.B. in Logfiles zu schauen, Logfiles der DB, des Appservers, des Clientprogramms.

Ich nutze MSSQL schon lange nicht mehr aktiv und ich mag es nicht, daher kann ich Dir weder die Fehlermeldung aus dem Stand nennen, noch eine MS SQL spezifische Lösung.
 
Hallo Dabadepdu,

ich habe inzwischen herrausbekomme dass der Fehler in der Variable ligt die ich zur abfrage baue

Set @Produkt = 'SPIRIT','AVANTi 1.Liz. *' ist falsch

Wenn ich das so mache geht es:
Code:
Declare @Produkt nvarchar(50)


SELECT ID,CompanyID,RECORDID,PROGRAM1,PROGRAM2,PROGRAM3,PROGRAM4,PROGRAM5,PROGRAM6,PROGRAM7,PROGRAM8,PROGRAM9,PROGRAM10
FROM   [cRM_Solution_cosmolink_faktura_ES].[dbo].[Contacts]
WHERE
PROGRAM1  in ('SPIRIT','AVANTi    1.Liz. *') or
PROGRAM2  in ('SPIRIT','AVANTi    1.Liz. *') or
PROGRAM3  in ('SPIRIT','AVANTi    1.Liz. *') or
PROGRAM4  in ('SPIRIT','AVANTi    1.Liz. *') or
PROGRAM5  in ('SPIRIT','AVANTi    1.Liz. *') or
PROGRAM6  in ('SPIRIT','AVANTi    1.Liz. *') or
PROGRAM7  in ('SPIRIT','AVANTi    1.Liz. *') or
PROGRAM8  in ('SPIRIT','AVANTi    1.Liz. *') or
PROGRAM9  in ('SPIRIT','AVANTi    1.Liz. *') or
PROGRAM10 in ('SPIRIT','AVANTi    1.Liz. *');

Die frage ist also:
Wie baue ich das was hinter Set @Produkt = hingehört richtig zusammen ?

Zusatz ich mache das so weil ich eine Liste von über 800 Suchbegriffen durch die Felder abarbeite muss
Vielen Dank
 
habe inzwischen herrausbekomme dass der Fehler in der Variable ligt die ich zur abfrage baue
Ja, das ist klar.
Du hast den konkreten Fehler, "den Du bekommst" immer noch nicht gepostet.

Wie gesagt, ich kenne den konkreten Fehler nicht, auch nicht aktuelle MS SQL Versionen. Da kann ich Dir nicht weiter helfen.
Wenn Du Deinen Variableninhalt mit dem funktionierenden Statement vergleichst, kannst Du ja schon ablesen, dass ein String etwas anderes ist, als eine Reihe von Komma separierten Strings.
 
Ups.

die Fehlermendung ist:
Meldung 102, Ebene 15, Status 1, Zeile 2
Falsche Syntax in der Nähe von ','.

Set @Produkt = 'SPIRIT' + ',' + 'AVANTi 1.Liz. *' geht übrigens auch nicht.
Damit habe ich keine Fehlermeldung mehr, aber die Liste der Ergebnisse ist leer.
 
Code:
postgres=# select * from kissling ;
  f1   |  f2   |  f3   
-------+-------+-------
 foo   | bar   | batz
 bla   | bla   | bla
 test1 | test2 | test3
(3 rows)

postgres=# with suche as (select 'foo' as x union all select 'test2') select kissling.* from kissling cross join suche where f1 in (suche.x) or f2 in (suche.x);
  f1   |  f2   |  f3   
-------+-------+-------
 foo   | bar   | batz
 test1 | test2 | test3
(2 rows)

postgres=#

10 durchnummerierte Spalten sind ein starkes Indiz für kapottes Tabellendesign.
 
Gut, Gegenprobe für den Kommafehler: Entferne alle Elemente bis auf eines, Variable ist dann ohne Komma.
Das geht?

Die meisten DB können für ein "..where <Ausdruck> in <andererAusdruck>.. " nicht über Paramterierung von <andererAusdruck> verarbeiten.
Wahrscheinlich gilt das was ich allgemein geschrieben habe auch für MSSQL.

Du musst einen Workaround finden, die Parameterliste an den Server zu übergeben.
Z.B. durch dynamische Parameterierung aller Einzelwerte oder durch eine Temptable, die session spezifisch alle Abfragekriterien bekommt.
 
JA. Es ist nicht mein Design.
Ich muss die Datenbank aufräumen!
Aufgabe: Mach aus über 800 ( ja, über 800) verschedenen Schreibweisen eines Artikels eine Schreibweise!
 
Wenn ich
Set @Produkt = 'SPIRIT'
verwende ist die Ergebnisliste korrekt!

Aber
Wenn ich
Set @Produkt = 'SPIRIT' + ',' + 'AVANTi 1.Liz. *'
verwende, erhalte ich keine Ergebnisse.
 
Wenn ich
..
verwende ist die Ergebnisliste korrekt!

Aber
Wenn ich..
Ok, das ist nur eine Prüfung, ob Dein Statement im Prinzip tut, was es soll. Der belanglose "Kommafehler" ist halt der Unfähigkeit eines DB Systems geschuldet, das höhrere Ziel Deines Statements und Deiner Umsetzungsversuche zu erahnen.

Und jetzt zitiere ich mich wieder: Es geht nicht so wie Du es machen willst und Du musst Dir einen Workaround suchen:
Du musst einen Workaround finden, die Parameterliste an den Server zu übergeben.
Z.B. durch dynamische Parametrierung aller Einzelwerte oder durch eine Temptable, die session spezifisch alle Abfragekriterien bekommt.
Die allereinfachste Lösung ist hier, das SQL Statement selbst aus Stringstücken zusammenzusetzen, die die gewünschten Abfrageparameter beinhalten. Und zwar nicht über Parametrierung, sondern als reinen SQL String. Dieses Vorgehen wird gewöhnlich nicht verwendet, weil es anfällig ist für SQL Injection. Dies kann man u.U. durch andere Maßnahmen eindämmen oder es ist sowieso nur ein theoretisches Problem, weil niemand über welches Interface auch immer, die Injection Bereiche anfassen kann.

Für eine konkrete Lösung musst Du Dir überlegen, wo Du ansetzen willst. Rein auf DB Seite und relativ allgemeingültig wäre die Nutzung von Temptables gefüllt mir den Suchwerten möglich.
Du kannst das Statement im Client als String zusammenbauen, wie oben beschrieben oder im Client eine dynamische Parametrierung programmieren. Diese Lösungen sind dann abhängig von einer Client Programmiersprache.
Etwas Ähnliches ginge sicher auch über eine SP in MSSQL, als reine SQL Geschichte.

Es gibt hier auch MS SQL / T SQL Experten, die Dir da vielleicht weiterhelfen können. Am besten Du überlegst Dir selbst mal, welcher Ansatz für Dich sinnvoll und praktikabel ist. Eine Überlegung wäre z.B. auch, etwas mehr Handarbeit und ein paar Wiederholungen / Skripting einzusetzen, dann wärst du wahrscheinlich schon fertig. 800 Werte zu ändern ist aus SQL Perspektive kein Schrecken, auch nicht, wenn es an tausenden Stellen verwendet wird. Dafür ist SQL da.
Letzer Ansatz dazu: Mach Dir eine Hilfstabelle, die alle alten und neuen (Ersatz)-Werte als Paare oder Tupel enthält und baue damit ein Update Statement. Das könnte ziemlich schnell gehen.
 
Deine Variable ist genau ein Wert. Du kannst definitiv nicht mehrere Werte in eine Variable schreiben (= eine Zeichenkette) und dann erwarten das SQL daraus wieder eine Werteliste bei der Verarbeitung macht. SQL sucht dann nach genau der einen Zeichenkette die deine Werteliste darstellt.

Der etwas unelegantere, aber immer funktionierende Ansatz bei sowas ist dynamisches SQL. Du baust deinen ganzen Code als Variable zusammen und führst ihn mit EXEC() aus. Beispiel in deinem Fall:
Code:
Declare @Produkt nvarchar(50)
Set @Produkt = 'SPIRIT,AVANTi    1.Liz. *'

DECLARE @sql NVARCHAR(4000) = '
SELECT ID,CompanyID,RECORDID,PROGRAM1,PROGRAM2,PROGRAM3,PROGRAM4,PROGRAM5,PROGRAM6,PROGRAM7,PROGRAM8,PROGRAM9,PROGRAM10
FROM   [cRM_Solution_cosmolink_faktura_ES].[dbo].[Contacts]
WHERE
PROGRAM1  in (' + @Produkt + ') or
PROGRAM2  in (' + @Produkt + ') or
PROGRAM3  in (' + @Produkt + ') or
PROGRAM4  in (' + @Produkt + ') or
PROGRAM5  in (' + @Produkt + ') or
PROGRAM6  in (' + @Produkt + ') or
PROGRAM7  in (' + @Produkt + ') or
PROGRAM8  in (' + @Produkt + ') or
PROGRAM9  in (' + @Produkt + ') or
PROGRAM10 in (' + @Produkt + ');';

EXEC(@sql);
 
Werbung:
Hallo Kissling,

ein einfacher Parameter ist immer nur ein Skalarer Wert, wie schon erklärt wurde.
Aber mir fallen zur Lösung gleich vier verschiedene Ansätze ein, je nachdem wie Komplex man das gestalten möchte.

Die einfachste Lösung mit deinem Konstrukt über eine Komma-Separierte Liste in einem String funktioniert nur über einen Textvergleich.
Diese Lösung funktioniert dann auf allen Versionen des SQL-Servers (sogar nach auf 2005, bei 2000 bin ich mir nicht sicher).

Diese Lösung sähe dann so aus:

Code:
Declare @Produkt nvarchar(50)
Set @Produkt = 'SPIRIT,AVANTi    1.Liz. *,'

SELECT ID,CompanyID,RECORDID,PROGRAM1,PROGRAM2,PROGRAM3,PROGRAM4,PROGRAM5,PROGRAM6,PROGRAM7,PROGRAM8,PROGRAM9,PROGRAM10
FROM   [cRM_Solution_cosmolink_faktura_ES].[dbo].[Contacts]
WHERE
CHARINDEX(PROGRAM1+',', @Produkt) > 0 OR
CHARINDEX(PROGRAM2+',', @Produkt) > 0 OR
CHARINDEX(PROGRAM3+',', @Produkt) > 0 OR
CHARINDEX(PROGRAM4+',', @Produkt) > 0 OR
CHARINDEX(PROGRAM5+',', @Produkt) > 0 OR
CHARINDEX(PROGRAM6+',', @Produkt) > 0 OR
CHARINDEX(PROGRAM7+',', @Produkt) > 0 OR
CHARINDEX(PROGRAM8+',', @Produkt) > 0 OR
CHARINDEX(PROGRAM9+',', @Produkt) > 0 OR
CHARINDEX(PROGRAM10+',', @Produkt) > 0

Wichtig bei dieser Lösung ist der abschließende Separator am Ende des Listen-Parameters @Programm.

Eine weitere Lösung, die ebenfalls auf allen Versionen funktioniert ist die Verwendung einer Tabelle für die Vergleich-Patterns.
Ich habe das mal mit einer deklarierten Tabelle als Beispiel aufgebaut, aber es kann ja auch eine temporäre oder sogar eine normale Tabelle für diese Vergleiche verwendet werden:

Code:
DECLARE @Programm TABLE
(
    CheckString varchar(255)
)

INSERT INTO @Programm (CheckString)
VALUES
('SPIRIT'),
('AVANTi 1.Liz. *')

SELECT DISTINCT
c.ID,
c.CompanyID,
c.RECORDID,
c.PROGRAM1,
c.PROGRAM2,
c.PROGRAM3,
c.PROGRAM4,
c.PROGRAM5,
c.PROGRAM6,
c.PROGRAM7,
c.PROGRAM8,
c.PROGRAM9,
c.PROGRAM10

FROM   [cRM_Solution_cosmolink_faktura_ES].[dbo].[Contacts] c

INNER JOIN @Programm p
    ON    c.PROGRAM1 = p.CheckString
    OR    c.PROGRAM2 = p.CheckString
    OR    c.PROGRAM3 = p.CheckString
    OR    c.PROGRAM4 = p.CheckString
    OR    c.PROGRAM5 = p.CheckString
    OR    c.PROGRAM6 = p.CheckString
    OR    c.PROGRAM7 = p.CheckString
    OR    c.PROGRAM8 = p.CheckString
    OR    c.PROGRAM9 = p.CheckString
    OR    c.PROGRAM10 = p.CheckString

Hier ist das DISTINCT in der Abfrage wichtig, da durch die OR-Vergleiche auch Duplikate entstehen können, wenn die Suchbegriffe in verschiedenen Vergleichs-Spalten einer Zeile auftauchen. Da aber die Werte ja nur aus der Haupt-Tabelle und nicht aus der verknüpften Tabelle ermittelt werden, reicht ein DISTINCT hier aus.

Aber beide Lösungen sind unter Umständen nicht sonderlich performant, je nachdem wie groß deine Datenmenge ist - das bitte berücksichtigen.


Bei den neueren SQL-Server-Versionen kann man auch mit STRING_SPLIT arbeiten, was ebenfalls als Rückgabe eine Tabelle erzeugt. Das arbeitet vom Prinzip her aber nicht anders als die deklarierte Tabelle.

Viele Grüße,
Tommi
 
Zurück
Oben