PDA

Vollständige Version anzeigen : LEFT bzw RIGHT im WHERE Teil


Durro
26.10.2011, 14:44
Aloha Codebastler-Gemeinde,



ich habe ein kleines Problem mit einem meiner SQL Strings.

Zur Übersicht: Ich verwende ACCESS 2003 und greife in einem Formular auf eine Tabelle tblMAEinteilung zu, deren Primärschlüssel id wie folgt aufgebaut ist:

DATUM_IDMA_IDProjekt

also zum Beispiel:

2011_07_21_002_001

Nun möchte ich nur diejenigen MAs als RowSource in eine Checkbox cboMA einfügen, die auch an einem bestimmten Datum einem bestimmten Projekt zugeordnet sind.
Also bei denen beispielsweise gilt:
tblEinteilung.id, left(tblEinteilung.id, 10) Like 2011_07_21
und
tblEinteilung.id, right(tblEinteilung.id, 3) Like 001

Soweit steige ich ja noch durch.

Um die Werte vergleichen zu können, habe ich die "Sollwerte" in zwei Strings, projectstring und datestring gespeichert.

Mein Code sieht nun so aus: (MsgBoxes sind nur zum Testen, die Strings sind "gefüllt")

Private Sub cboMA_Enter()
MsgBox ("Enter (beim Hingehen)")
MsgBox (datestring)
MsgBox (projectstring)

cboMA.RowSource = "SELECT DISTINCT tblMAEinteilung.idMa, tblMA.Name FROM tblMAEinteilung, tblMA WHERE tblMAEinteilung.idProject LIKE '" & projectstring & "' AND tblMAEinteilung.id LEFT(tblMAEinteilung.id, 10) LIKE " & datestring


Ich habe bereits über die MsgBoxes geprüft, ob die strings gefüllt sind.
Bei der Ausführung des Codes erhalte ich aber die Fehlermeldung:

"Syntaxfehler (fehlender Operator) in Abfrageausdruck:
'tblMAEinteilung.idProjekt LIKE '1' AND tblMAEinteilung.id LEFT(tblMAEinteilung.id, 10) LIKE 2011_07_21'"

Was übersehe ich?
Wäre für Hilfe sehr dankbar!


Grüße,
Durro

Louisleon
26.10.2011, 15:11
Hallo Durro,

Like erwartet ein Wildcard (Joker etc.) zum Vergleich!
In deinem Fall sollte aber der direkte Vergleich (=) ausreichend sein!

Also statt "Like" ein "=" !

Gruß

LL

Atrus2711
26.10.2011, 15:26
Hi,

wie sagt der Elektriker: "da dimmt was nicht" :)

cboMA.RowSource = "SELECT DISTINCT tblMAEinteilung.idMa, tblMA.Name " _
& "FROM tblMAEinteilung, tblMA " _
& "WHERE tblMAEinteilung.idProject LIKE '" & projectstring & "' AND " _
& "tblMAEinteilung.id LEFT(tblMAEinteilung.id, 10) LIKE " & datestring
Der markierte Teil ist durch die danachfolgende Left-Konstruktion überflüssig geworden. Nimm den raus.

Nebenbei:

Bedingtes Kreuzprodukt dürfte einen ungünstigen Ausführungsplan geben -> langsam!
LIKE nutzt keine Indizes, wenn die Platzhalter nicht ausschließlich am Ende stehen
LIKE ist nur nötig, wenn wirklich nach Mustern gesucht wird. Wo eine Gleichheitssuche ausreicht, ist die schneller.
ist Datestring mit Hochkommas und Platzhaltern versehen?

ebs17
26.10.2011, 15:40
LEFT(tblMAEinteilung.id, 10)
Berechnungen auf ein Tabellenfeld unterbinden auch eine Indexnutzung.

Das Problem beginnt hier:
Primärschlüssel id wie folgt aufgebaut ist:
DATUM_IDMA_IDProjekt
2011_07_21_002_001
Wenn man atomare Werte in getrennten Feldern abspeichert, braucht man dann in der Abfrage keine Textverarbeitung, um diese Einzelinhalte verwenden zu können.
Eine Alternative wäre ein zusammengesetzter eindeutiger Index auf diese drei Felder (wobei ein Datum ein Datum sein sollte und kein Datumsstring) und ein Autowertfeld als PK.

"Ordentliche" Strukturen erlauben es, das "Codebasteln" auf die Dinge zu verschieben, die dann wirklich Probleme sind.

Durro
27.10.2011, 08:56
@all:

Vielen Dank für's gute Feedback! Ich mache mich gleich mal an die Umsetzung... :)

@ebs:

Mein Problem ist folgendes:
Ich möchte in der Tabelle tblMAEinteilung die Einteilung unserer Mitarbeiter zu bestimmten Projekten festhalten. Das können sehr viele Daten werden, da wir ca. 90 MAs haben die täglich unterschiedlichen Projekten zugeteilt sein können.

Ich könnte natürlich schlichtweg einen AutoID Wert, ein Feld für idMA, eines für idProjekt und zwei Felder "von" und "bis" verwenden. Das war mein erster Entwurf.

Wenn ich dann aber einen neuen Datensatz anlege, muss ich alle anderen DS prüfen ob der eine Mitarbeiter zwischen den beiden Dati "von" und "bis" schon einem Projekt zugeteilt ist. Also, wenn ich es richtig verstanden habe, muss ich in allen DS die die idMA haben berechnen ob mein neues Datum irgendwann zwischen den bereits existenten Dati liegt. Da die Tabelle schnell recht groß wird dachte ich, dass diese Berechnung wahrscheinlich recht viel Zeit braucht.
Daher wollte ich gleich einen entsprechenden Primärschlüssel bauen, der mir diese Berechnung abnimmt - und erstelle jetzt lieber beim Einteilung der MA für jeden Arbeitstag einen DS.

Außerdem war ursprünglich einmal geplant, die DB regelmäßig mit Duplikaten zu aktualisieren, da wäre kein AutoID Wert passend gewesen... (Ist aber mittlerweile keine Anforderung mehr, insofern ist der Primärschlüssel evtl. tatsächlich zu unnötig kompliziert gestaltet...)

Ich habe also schon versucht, "ordentliche Strukturen" zu verwenden. Mir fehlt nur eben eine fundierte Ausbildung in meinem 'Zwangs-Hobby' Programmierung ;)

Hast Du eine bessere Alternative? Ich lerne gerne dazu...

gpswanderer
27.10.2011, 09:06
Hallo,
es ist überflüssig zu diesem Zweck einen Primärschlüssel zu verwenden. Die Daten gehören in getrennte Felder. Verwende dann den Autowert als Primärschlüssel, also so wie Du es schon hattest.
Statt des zusammengesetzten Primärschlüssels erstellst Du einen zusammengesetzten Index, der ebenso zuverlässig Doppelungen verhindert.

Durro
27.10.2011, 09:18
Hallo gpswanderer, danke für dein Feedback!

Aber abgesehen davon, dass ich dann ein Feld ID mit einem Autowert und ein Feld Index mit einem zusammengesetzten Wert habe ändert sich ja dann nichts für mich, oder?

Der Unterschied ist doch, dass ich im einen Fall für jeden Arbeitstag einen DS erstelle und im anderen lediglich für jeden "Block" an Arbeitstagen einen DS. Wenn ich im Zweiten Fall beispielsweise bei einem Zeitraum von 10 Tagen zwei Tage lang den MA "umbuche" oder freistelle muss einen DS ändern und einen zweiten erstellen, im ersten Fall nur zwei Felder löschen oder editieren...

Oder habe ich dich missverstanden?

Atrus2711
27.10.2011, 09:34
Hi,

wenn es zulässig ist, dass ein Mitarbeiter täglich an anderen Projekten arbeitet (auch wenn das selten ist) und du gleichzeitig die Eingabearbeit reduzieren willst, könnte man ja beides kombinieren:


eine Tabelle hält fest: wer arbeitet an welchem Tag wo. Diese Tabelle wäre manuell kaum zu pflegen, da pro Mitarbeiter 365 Sätze jährlich zu pflegen wären.
Die Pflege kann aber über Formulare vereinfacht werden. Wenn du Person, Projekt und Zeitraum (von.bis) angibst, können die Sätze in der Großtabelle angelegt oder ggf geändert werden. Man könnte dabei auch feststellen, welchem Projekt der Mitarbeiter für wie lange "weggenommen" wird. Eine reine Zeitraumtabelle ohne Einzeltage wird das aber nicht schaffen, weil die Sätze ja überlappen dürfen und dann nicht feststellbar wäre, welchem der (vielen) Projekte Herr Meier am 10.10.2011 denn nun zugewiesen war.

ebs17
27.10.2011, 11:37
Wenn ich im Zweiten Fall beispielsweise bei einem Zeitraum von 10 Tagen zwei Tage lang den MA "umbuche" oder freistelle muss einen DS ändern und einen zweiten erstellen, im ersten Fall nur zwei Felder löschen oder editieren...
Das stimmt, anweisungsmäßig hättest Du mit dem neuen Vorschlag an dieser Stelle etwas mehr Aufwand. Für einen Entwickler sollte es aber kein Kriterium erster Ordnung sein mit möglichst wenig Codezeilen etwas zum (Irgendwie)Funktionieren zu bringen. In der Ausführung der Anweisungen wirst Du zeitmäßig keinen Unterschied feststellen.

Du solltest aber auch im Auge haben, dass sehr oft auch ganze Tabellen abgefragt und verarbeitet werden, und auftretende Datenmengen können und werden dann schon spürbar Zeit dafür erfordern. Datenverarbeitung heißt vor allem Datenverarbeitung und nicht Dateneingabe, weil die Verarbeitung Schwerpunkt der Datenbankanwendung sein dürfte.

Mit einem Datensatz pro Block hast Du weniger Datensätze als bei tageweiser Aufführung. Das ist aber nicht so maßgeblich.
Mit Deinem in einen Wert zusammengesetzten Schlüssel hast Du dann Probleme, wenn Du Einzelinformationen daraus benötigst (wie oben in der Fragestellung), um zu Filtern, zu Gruppieren oder schlicht zu Sortieren. Bei solchen Aktionen ist eine Indexnutzung sehr hilfreich, vergleiche Performance in Abfragen (http://www.donkarl.com/Downloads/AEK/AEK8_Abfragen_Performance.zip) von Michael Zimmermann. Mit der Berechnung (Herauslösen der Information aus der Zusammensetzung) unterbindest Du eine Indexnutzung.

Der Unterschied in der benötigten Zeit für Indexnutzung und Nichtnutzung eines Index kann sich in einem Faktor zwischen 0 und durchaus 10.000 und mehr bewegen. Wenn dann das Neuabrufen einer Datenherkunft für ein Formular oder Kombifeld bei entsprechender Datenmenge 10 Sekunden braucht statt 1 Sekunde (wenn man nur von Faktor 10 ausgeht), dürfte das dem Anwender mächtig auffallen und ziemlich schnell stören.