# SQL Querry über mehrere Spalten



## multiholle (28. Apr 2009)

Ich möchte in meiner Datenbank über eine Anfrage einen Datensatz an anhand diesen Strings finden: "ärzte best of westerland". Die Datenbank besitzt die Spalten "Künstler", "Album", "Titel", ...

Das Problem ist, das ich nicht eine Spalte nach dem String fragen kann. Der Datensatz muss in irgend einer Spalte "ärzte" in einer anderen, oder der gleichen "best" enthalten und so weiter.

Wie formuliere ich dafür eine korrekte SQL anfrage? Hier mein Ansatz:
[highlight="Java"]
	public Vector<MP3File> getSongs(String query) {
		try {
			query = "%" + query.replaceAll(" ", "%") + "%";
			System.out.println(query);
			Vector<MP3File> songs = new Vector<MP3File>();
			stmtSearchSong.clearParameters();
			stmtSearchSong.setString(1, query);
			stmtSearchSong.setString(2, query);
			stmtSearchSong.setString(3, query);
			stmtSearchSong.execute();
			ResultSet results = stmtSearchSong.getResultSet();
			while (results.next()) {
				MP3File newSong = new MP3File(results.getString("ARTIST"),
						   					  results.getString("ALBUM"),
						   					  results.getString("TRACK"),
						   					  results.getString("TITLE"),
						   					  results.getString("DATE"),
						   					  results.getString("PATH")); 
				songs.add(newSong);
			}
			return songs;
		}
		catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}

	private final String strSearchSong =
		"SELECT * FROM MEDIA " +
		"WHERE UPPER(ALBUM) LIKE UPPER(?) " +
		"OR UPPER(ARTIST) LIKE UPPER(?) " +
		"OR UPPER(TITLE) LIKE UPPER(?) ";
[/highlight]


----------



## SlaterB (28. Apr 2009)

die Felder in der DB solltest du zu einem String konkatenieren,
aber die LIKE-Anfragen müssen wohl immer noch einzeln stattfinden
WHERE (sumString Like ?) or (sumString Like ?) or ..

das Upper für die Suchstrings kannst du dir im SQL sparen und die Parameter gleich passend übergeben, % musst eh drankleben

den SumString möglichst nur einmal definieren, kennst du eine View? damit ginge das vielleicht

SELECT id FROM
(SELECT id, UPPER(a+b+c+d) as sumString FROM MEDIA)
WHERE (sumString Like ?) or (sumString Like ?) or ..

oder ähnlich, wie man Strings zusammenfügt und Views bildet ist evtl. DB-abhängig


----------



## sparrow (28. Apr 2009)

Spontaner Einfall:

Mach eine "Suchspalte" in der du den Inhalt der zu durchsuchenden Spalten nochmals schreibst. Dann kannst du in eienr Abfrage diese Spalte prüfen.

Künstler: Die Ärzte
Album: Irgendwas mit Hamstern
Titel: Osterland
Suchspalte: Die Ärzte Irgendwas mit Hamstern Osterland

Wenn du jetzt nach Ärzte und Osterland suchen würdest:


```
SELECT * FROM table 
WHERE suchspalte LIKE "%Ärzte%" 
AND suchspalte LIKE "%Osterland%";
```


----------



## multiholle (28. Apr 2009)

@sparrow
das wäre eine idee, ist aber leider nicht so schön in der umsetzung. da ich so ziemlich alle spalten durchsuchen will, müsste ich die daten doppelt halten. das gefällt mir nicht.

@SlaterB
was meinst du mit "view"? ich nutze die embedded derby datenbank. wie mach ich das da?


----------



## sparrow (28. Apr 2009)

Die Lösung von SlaterB ist von der Art her mit meiner identisch.

Stell dir ein View wie eine "gespeicherte Abfrage" der Datenbank vor.
In der Sicht definierst du dann entsprechend die Abfrage die dir für jeden Datensatz alle durchsuchbaren Felder in einem Feld zusammen fasst und durchsuchst dann eben diese Datensätze mit LIKE.

Sicht (Datenbank) ? Wikipedia

Unabhängig davon müsstest (als View oder direkt in der Abfrage) alle Spalten die du durchsuchen willst in eine zusammenführen.

Gruß
Sparrow


----------



## multiholle (29. Apr 2009)

Wenn ich mir eine View definiere, dann habe ich eine "Suchspalte" in der alle Spalten in einer bestimmten Reihenfolge aufgeführt werden. Das Problem ist, dass die Suchanfrage nicht in dieser Reihenfolge gestellt werden muss.

"ärzte bäst of westerland"
"westerland ärzte best of"
"best of ärzte westerland"

Dann müsste ich für jede Kombination eine eigene "Suchspalte" definieren :/ Oder gibt es eine einfachere Lösung? Kann man der Datenbank evtl. eine Art Algorithmus übergeben, mit dem die Anfrage ausgewertet wird?


----------



## SlaterB (29. Apr 2009)

anfangs hieß es 'in irgend einer Spalte "ärzte", in einer anderen, oder der gleichen "best"'
von Reihenfolge keine Rede,

du sollst doch eh jedes Wort einzeln suchen, was spielt da die Reihenfolge der zusammengefügten Spalten für eine Rolle?


----------



## multiholle (29. Apr 2009)

Ok, da habe ich mit etwas unklar ausgedrückt. Wenn ich jedes Wort einzeln afrage, bekomme ich aber nicht ein Ergebnis, welches alle Wörter enthält.


----------



## SlaterB (29. Apr 2009)

man kann die Einzelabfragen mit ODER oder mit UND verknüpfen..,
oder du musst die Frage noch genauer stellen, z.B. ein Beispiel


----------



## multiholle (29. Apr 2009)

Folgende Datenbank:

```
Artist		Album				Title
-------------------------------------------------
Adam Green	Friends Of Mine			Hard To Be A Girl
Burial 		Untrue				Archangel
Cartridge	Fractures			1925
```
Wenn ich jetzt den Song von Adam Green haben will sollen folgende Suchanfragen das gleiche Ergebnis liefern:

```
green friends hard girl
hard girl adam
hard to be friends adam
friends of mine adam green girl
...
```

Wie mache ich das am besten?


----------



## SlaterB (29. Apr 2009)

wie in Antwort 1 und 2 vorgeschlagen abgesehen von AND statt OR
oder aus welchem Grunde sollten die Vorschläge nicht genügen?

am allerbesten wäre evtl. eine spezielles Framewort für sowas,
Apache Lucene - Overview
keine Ahnung ob das einbaubar ist und auf mehrere Spalten gleichzeitig suchen kann und nach allen Begriffen usw


----------



## sparrow (29. Apr 2009)

Ich weiß nicht mit welcher Datenbank du arbeitest aber hier mal ein Beispiel mit PostgreSQL.
Mit der Reihenfolge der Wörter in der Spalte hat das ganze nichts zu tun:


```
postgres=# SELECT * FROM musik;
      band       |   album   |       title       
-----------------+-----------+-------------------
 Die Ärzte       | Best of   | Osterland
 Die Hoten Tosen | Open Gang | Ausverkauft
 Depeche Mode    | Violator  | Enjoy the Silence
(3 Zeilen)

Zeit: 0,568 ms
postgres=# SELECT band, album, title, band || ' ' || album || ' ' || title AS suchspalte FROM musik;
      band       |   album   |       title       |               suchspalte                
-----------------+-----------+-------------------+-----------------------------------------
 Die Ärzte       | Best of   | Osterland         | Die Ärzte Best of Osterland
 Die Hoten Tosen | Open Gang | Ausverkauft       | Die Hoten Tosen Open Gang Ausverkauft
 Depeche Mode    | Violator  | Enjoy the Silence | Depeche Mode Violator Enjoy the Silence
(3 Zeilen)

Zeit: 0,642 ms
postgres=# CREATE VIEW musik_view AS SELECT band, album, title, band || ' ' || album || ' ' || title AS suchspalte FROM musik;
CREATE VIEW
Zeit: 3,418 ms
postgres=# SELECT * FROM musik_view;
      band       |   album   |       title       |               suchspalte                
-----------------+-----------+-------------------+-----------------------------------------
 Die Ärzte       | Best of   | Osterland         | Die Ärzte Best of Osterland
 Die Hoten Tosen | Open Gang | Ausverkauft       | Die Hoten Tosen Open Gang Ausverkauft
 Depeche Mode    | Violator  | Enjoy the Silence | Depeche Mode Violator Enjoy the Silence
(3 Zeilen)

Zeit: 1,223 ms
postgres=# SELECT * FROM musik_view WHERE suchspalte LIKE '%Osterland%' AND suchspalte LIKE '%Ärzte%';
   band    |  album  |   title   |         suchspalte          
-----------+---------+-----------+-----------------------------
 Die Ärzte | Best of | Osterland | Die Ärzte Best of Osterland
(1 Zeile)

Zeit: 1,352 ms
postgres=# SELECT * FROM musik_view WHERE suchspalte LIKE '%Osterland%' AND suchspalte LIKE '%Depeche%';
 band | album | title | suchspalte 
------+-------+-------+------------
(0 Zeilen)

Zeit: 0,821 ms
postgres=# SELECT * FROM musik_view WHERE suchspalte LIKE '%Die%';
      band       |   album   |    title    |              suchspalte               
-----------------+-----------+-------------+---------------------------------------
 Die Ärzte       | Best of   | Osterland   | Die Ärzte Best of Osterland
 Die Hoten Tosen | Open Gang | Ausverkauft | Die Hoten Tosen Open Gang Ausverkauft
(2 Zeilen)

Zeit: 0,790 ms
postgres=#
```

Der Teil _band || ' ' || album || ' ' || title AS suchspalte_ fügt den Inhalt der Spalten Band, Album und Titel zusammen, jeweils mit einem Leerzeichen dazwischen. Das geht bei PostgreSQL auf jeden Fall so, wie es bei anderen Datenbanken ist weiss icht nicht. Vielleicht gibt es da eine Concat-Version.

Ich hoffe das war verständlich 

Sparrow


----------



## multiholle (29. Apr 2009)

danke!. sehr schön übersichtlich. ich denke ich bekomme das hin


----------

