Voor een zoekfunctie in mijn database loop ik tegen het probleem aan dat ik eigenlijk in 1 zoekopdracht, op meerdere gegevens wil zoeken. Primair is de zoektocht van gegevens uit 1 tabel op een andere tabel en in feite kan dat via joins. Probleem is echter dat de gegevens waar ik op wil zoeken niet allemaal in de database staan.

Het gaat erom dat de gebruiker eigen gegevens in de database heeft staan en die moeten gematcht worden met gegevens die door het systeem al zijn gedefinieerd. Het gaat overigens om vliegtuig registraties, om het misschien iets beter begrijpbaar te maken. Omdat de gebruiker zijn eigen fomaat kan hanteren kan het zijn dat bepaalde gegevens, ook al zouden ze gelijk moeten zijn, dat toch niet zijn. Voorbeeld: Een Belgische F-16 staat in het systeem als FA-01, maar de gebruiker kan ook FA 01, FA01 of FA-1 invullen, dit moet allemaal tot een match leiden met FA-01. Om dat te doen is er een extra tabel met een 'opgeschoonde' waarde voor de systeem gegevens. Daar zal deze registratie als FA1 instaan wat is bepaald via een regex en andere regels.

Het probleem is nu dat ik de gebruiker laat zoeken op zijn eigen data in de database, maar voor de zoektocht start zal ik eerst van alle door de gebruiker ingevoerde gegevens de opgeschoonde waarde moeten bepalen. Die staat niet in de database, die bepaal ik dus op het moment dat het nodig is. Waarop ik dan zoek is het ID en de zojuist bepaalde opgeschoonde waarde. Zoek ik op 1 record dan is dat geen probleem (versimpeld):


SELECT DISTINCT aa.plane_id, aa.registration
FROM (
  (SELECT a.plane_id, m.registration, 
   FROM planes a
   INNER JOIN planes m ON (
     (m.registration = a.registration OR m.registration = 'FA1')
     AND m.plane_id <> a.plane_id
   )
   WHERE (m.country_id = a.country_id OR a.country_id = 0)
     AND a.plane_id = 1)
  UNION 
  (SELECT a.plane_id, mp.registration, 
   FROM planes a
   INNER JOIN registration_search ms ON (
     (ms.search_value = a.registration OR ms.search_value = 'FA1')
     AND ms.plane_id <> a.plane_id
   )
   INNER JOIN planes mp ON ms.plane_id = mp.plane_id

   WHERE (mp.country_id = a.country_id OR a.country_id = 0)
     AND a.plane_id = 1)
) aa
ORDER BY aa.plane_id, aa.registration;

De waarde 'FA1' is dus de opgeschoonde waarde, en in dit voorbeeld hoort dat bij het record met id 1.
Wil ik nu echter op id 1 en id 2 zoeken dan kan dat niet meer op deze manier, tenzij ik nog twee SELECTs maak via de UNION. Ik wil echter op 100 records tegelijk kunnen zoeken, wat tot 200 SELECTs zou leiden....

Vraag is voor mij, wat kan wel. Een temporary table komt in me op, omdat ik dan alle berekende waardes in een tabel heb staan en dan werkt het vrij eenvoudig via joins. Dan kan ik op zoveel records zoeken als ik wil. Mijn kennis van temporary tables is echter beperkt en ik weet dus niet wat daar de voorwaarden en nadelen van zijn. Hoe zit het bijvoorbeeld met naamgeving (om te voorkomen dat er twee users tegelijk zoeken en elkaar in de weg zitten), hoe zit het met performance, etc. Iemand die daar iets op kan zeggen, bij voorkeur in combinatie met het voorbeeld? Eventuele andere oplossingen zijn overigens ook zeer welkom!
Je hebt gelijk, ik zag die tweede join voorwaarde over het hoofd.

Erwin H op 12/05/2014 19:39:30


- in de tabel registration_search staan de opgeschoonde waardes van alleen de officiele records. Dus voor het record met 'FA-01' zal er een search waarde 'FA1' zijn. Als dus een gebruiker nu 'FA 01' intikt en zoekt naar een match dan zal die opgeschoonde waarde van 'FA 01' (wat 'FA1' is) matchen met het officiele record en zo kan de correcte link gelegd worden.



   INNER JOIN registration_search ms ON (
     (ms.search_value = a.registration OR ms.search_value = 'FA1')
     AND ms.plane_id <> a.plane_id
   )
   INNER JOIN planes mp ON ms.plane_id = mp.plane_id


Hoe staat dan uit jou voorbeeld plane_id 3 in registration_search?
plane_id 1 en 3 staan er niet in. Dat zijn door gebruikers aangemaakte records en die worden dus niet opgevoerd in de search tabel omdat ze niet gevonden hoeven te worden.

En voor de goede orde, ik heb inmiddels in een test omgeving de situatie met twee temporary tables draaien. Het werkt dus inmiddels wel, maar ik blijf me afvragen of het de beste oplossing is....
Zonder een klein beetje denormaliseren is er geen betere oplossing.

Je zou eventueel in SQL nog een functie kunnen maken voor het opschonen van de data, maar dat levert volgens mij ook weinig voordeel op.
Het opschonen van de data in SQL is, denk ik, geen optie, gezien de complexiteit ervan. Denormaliseren zou inderdaad wel een optie zijn, maar dat wil ik niet. Dus.... dan moet ik het zo houden. Op het moment ben ik ermee aan het testen en het werkt in de test omgeving prima, zonder merkbare vertraging. Uiteraard is in de test omgeving de database wel wat kleiner, dus we zullen gaan zien hoe het in het echt gaat werken....

In elk geval weer eens met wat nieuws wezen stoeien, dat is altijd al meteen een voordeel :-)

Dank voor je hulp!
Is het dan zo erg om een record voor elk vliegtuig bij te houden met de opgeschoonde waarde?
Nee, op zich niet. Het is mijn keuze om dat niet te doen. Een keuze tussen:
1) extra (berekende) gegevens opslaan die niet of nauwelijks nodig zijn, maar als het nodig is dan wel iets sneller de zoekopdracht vervullen
2) minder data opslag, maar een wat complexere zoekopdracht

Ik kies voor 2, maar ik wil niet zeggen dat keuze 1 dus fout of slecht is. Het is mijn inschatting dat hoewel de zoekopdracht nu wat complexer is, het me uiteindelijk rekenkracht en opslag scheelt, omdat ik nu ietwat minder complexe inserts en updates hoef uit te voeren. Maar of het echt quantificeerbaar is is zeer de vraag.

Reageren