MS SQL: Fulltext search

Plaats reactie
Gebruikersavatar
meon
Administrator
Administrator
Berichten: 16609
Lid geworden op: 18 feb 2003, 22:02
Twitter: meon
Locatie: Bree
Uitgedeelde bedankjes: 564 keer
Bedankt: 759 keer
Contacteer:

Eigenlijk bestaat m'n vraag uit 2 delen.
Situatie is: ik heb een webapplicatie, geschreven in PHP die via ODBC gebruik maakt van een MS SQL-database.
Ik heb in 1 bepaalde tabel 1 text-field waar ik heleboel data in pleur. Omdat die data uit een heleboel tekens kan bestaan (gemixt HTML, dingen met aanhalingstekens, ..., geen binaire data) BASE64-encode ik deze data alvorens in die tabel weg te schrijven (BASE64 bestaat uit enkel letters en cijfers waardoor een query niet stuk loopt op een bepaald teken).

Nu zijn m'n vragen:
1) Wat moet ik escapen of op andere wijze encoderen zodat ik zonder problemen de tekst kan opslaan zonder dat ik deze in z'n geheel moet BASE64-encoden?

2) Doel is namelijk te kunnen gaan zoeken op substrings. Dat kan via de LIKE-operator, maar ik neem aan dat in MS SQL ook Fulltext-searches mogelijk zijn. Wat moet ik hier voor doen aan server-kant en hoe zien die queries er uit? Ik ken de MySQL-syntax wel (MATCH AGAINST), maar 't lijkt me sterk moest dat in MS SQL ook zo zijn. Klopt het ook dat MSDE2000 of SQL Server Express geen Fulltext hebben? Dat zou bummer zijn voor m'n development-omgeving namelijk :).

//edit: Als voorbeeldje zo'n string die ik zou willen kunnen opslaan:

Code: Selecteer alles

a:8:{s:9:"user_data";a:9:{s:11:"user_domain";s:14:"STRIPPED";s:7:"user_nt";s:6:"Linda";s:7:"user_id";
s:2:"13";s:4:"help";i:0;s:4:"lcid";i:1043;s:4:"font";s:3:"off";s:9:"user_mail";s:31:"[email protected]";
s:16:"user_displayname";s:12:"Linda";s:4:"auth";a:2:{i:0;s:5:"LOGIN";i:1;s:5:"OALVG";}}s:12:"APP_FORMTYPE";
s:5:"inlog";s:6:"frm_NT";a:9:{s:8:"formtype";s:3:"new";s:4:"date";s:10:"16-04-2008";s:4:"name";s:7:"BLA";
s:9:"givenname";s:6:"Maaike";s:10:"costcentre";s:8:"BIOMASSA";s:10:"employment";s:4:"Vast";s:8:"fromdate";
s:10:"01-05-2008";s:6:"todate";s:0:"";s:8:"frm_v_NT";s:3:"0.2";}s:8:"username";s:22:"Maaike (Nieuw)";
s:11:"frm_Windows";a:10:{s:10:"department";s:9:"Recycling";s:5:"title";s:13:"Officemanager";
s:14:"officelocation";s:3:"VLH";s:15:"Taal-instelling";s:2:"NL";s:12:"emailcentral";s:2:"No";s:8:"internet";
s:4:"Full";s:10:"sharepoint";s:3:"Yes";s:3:"owa";s:3:"Yes";s:7:"remarks";s:0:"";s:13:"frm_v_Windows";
s:3:"0.2";}s:9:"frm_share";a:10:{s:7:"share-1";s:19:"FILE\Biomass";s:14:"share-1-access";s:2:"RW";
s:7:"share-2";s:31:"FILE\B&V_Management_info";s:14:"share-2-access";s:2:"RW";s:7:"share-3";
s:22:"FILE\Processing";s:14:"share-3-access";s:2:"RW";s:7:"share-4";s:0:"";s:7:"share-5";s:0:"";
s:7:"remarks";s:0:"";s:11:"frm_v_share";s:3:"0.1";}s:12:"frm_Exact-NL";a:5:{s:9:"exactglob";
s:3:"Yes";s:8:"ms-query";s:2:"No";s:17:"administration-nr";s:0:"";s:7:"remarks";s:84:"Exact rechten 
aangevraagd door HRM - welke niet duidelijk - meer informatie gevraagd";s:14:"frm_v_Exact-NL";
s:3:"0.1";}s:8:"finalize";a:19:{s:7:"remarks";s:78:"<p>Exact rechten - wachten tot meer info</p>
<p>leidinggevende : Toon Beeks</p>";s:9:"submit-by";s:21:"STRIPPED\LindaC";s:21:"submit-by_displayName";
s:12:"Linda";s:14:"submit-by_mail";s:31:"[email protected]";s:15:"submit-by_title";s:33:"Manager 
Assistent/Ict Coordinator";s:36:"submit-by_physicalDeliveryOfficeName";s:10:"Soerendonk";
s:17:"submit-by_company";s:5:"Groep";s:18:"approved-by_domain";s:28:"0##STRIPPED.corp.local";
s:11:"approved-by";s:10:"Toon";s:17:"approved-by_title";s:16:"Manager Biowaste";
s:38:"approved-by_physicalDeliveryOfficeName";s:17:"Eindhoven";s:19:"approved-by_company";
s:5:"Groep";s:16:"approved-by_mail";s:29:"[email protected]";s:19:"approved-by2_domain";
s:28:"0##STRIPPED.corp.local";s:12:"approved-by2";s:0:"";s:18:"approved-by2_title";s:0:"";
s:39:"approved-by2_physicalDeliveryOfficeName";s:0:"";s:20:"approved-by2_company";s:0:"";
s:17:"approved-by2_mail";s:0:"";}}
//edit2: voor de leesbaarheid hier wat linebreaks in gezet, maar in principe is dit 1 lange string op 1 regel. De slimmerikken hier herkennen PHP-geserialiseerde data. Het had ook JSON of XML kunnen zijn, maar dit werkt best wel fijn ;).
ubremoved_539
Deel van't meubilair
Deel van't meubilair
Berichten: 29849
Lid geworden op: 28 okt 2003, 09:17
Uitgedeelde bedankjes: 446 keer
Bedankt: 1985 keer

meon schreef:1) Wat moet ik escapen of op andere wijze encoderen zodat ik zonder problemen de tekst kan opslaan zonder dat ik deze in z'n geheel moet BASE64-encoden?
Niets (aangezien het geen binaire data kan zijn zoals je aangeeft).
Gebruikersavatar
meon
Administrator
Administrator
Berichten: 16609
Lid geworden op: 18 feb 2003, 22:02
Twitter: meon
Locatie: Bree
Uitgedeelde bedankjes: 564 keer
Bedankt: 759 keer
Contacteer:

Mja, maar hoe moet er dan een insert statement uit zien? Ik zal op z'n minst de " moeten escapen om het als 1 string door te geven, alleen weet ik niet hoe?
crapiecorn
Elite Poster
Elite Poster
Berichten: 2149
Lid geworden op: 01 feb 2003, 11:58
Uitgedeelde bedankjes: 44 keer
Bedankt: 12 keer

In DB2 kan je normaal single qoutes voor je query gebruiken en dan gewone in je string
insert into bla values(' "iets" ') , weet niet als dit ook bij mssql werkt.

edit : ook even in mysql getest, werkt ook.
BungaMan
Elite Poster
Elite Poster
Berichten: 1485
Lid geworden op: 16 nov 2005, 09:05

Dat escapen hangt toch enkel af van uw gebruikte coding taal? Tenzij ge een insert statement gaat vormen.
Please help, looking for a way to get rich and fast
Gebruikersavatar
meon
Administrator
Administrator
Berichten: 16609
Lid geworden op: 18 feb 2003, 22:02
Twitter: meon
Locatie: Bree
Uitgedeelde bedankjes: 564 keer
Bedankt: 759 keer
Contacteer:

mja, en wat als er dan single quotes voorkomen...
ik moet gewoon failsave alle vorm van tekst kunnen opslaan. Nu lukt me dat door te encoden, maar dan kan ik geen inhoudelijke queries uitvoeren... Die fulltext vind ik dan al minder belangrijk.
Momenteel heb ik een zoekfunctie op allerlei andere parameters die gebruik maakt van andere velden, maar inhoudelijk zoeken kan ik niet, wegens die encoding. Of ik zou elk record moeten gaan ophalen, decoden, zoeken ... da's niet erg efficiënt lijkt me :)

Ja, momenteel is het een insert statement, maar als je een suggestie geeft hoe ik het anders moet/kan oplossing; dan graag! :)
crapiecorn
Elite Poster
Elite Poster
Berichten: 2149
Lid geworden op: 01 feb 2003, 11:58
Uitgedeelde bedankjes: 44 keer
Bedankt: 12 keer

Waarom wil je eingelijk dataformatting doen in dataformatting ?
Gebruikersavatar
meon
Administrator
Administrator
Berichten: 16609
Lid geworden op: 18 feb 2003, 22:02
Twitter: meon
Locatie: Bree
Uitgedeelde bedankjes: 564 keer
Bedankt: 759 keer
Contacteer:

?
Heel die string kan ik in 1 keer terug inladen met de php-functie unserialize(), en dan zit heel die data terug in 1 multidimensionele array ...
't heeft geen zin om die data genormaliseerd op te slaan, die informatie is toch nooit nodig buiten dat éne record waarin het zich bevindt.
crapiecorn
Elite Poster
Elite Poster
Berichten: 2149
Lid geworden op: 01 feb 2003, 11:58
Uitgedeelde bedankjes: 44 keer
Bedankt: 12 keer

Ik bedoel waarom die geformat in een database opslaan, als ge de database zelf hiervoor kan gebruiken.
ubremoved_539
Deel van't meubilair
Deel van't meubilair
Berichten: 29849
Lid geworden op: 28 okt 2003, 09:17
Uitgedeelde bedankjes: 446 keer
Bedankt: 1985 keer

meon schreef:Mja, maar hoe moet er dan een insert statement uit zien? Ik zal op z'n minst de " moeten escapen om het als 1 string door te geven, alleen weet ik niet hoe?
Dergelijk probleem heb je enkel indien je zelf het statement gaat samenstellen als een string wat af te raden is omdat dit net enorm vatbaar is voor SQL injection problemen.

De aangewezen is methode is gebruik te maken van parameter markers en het statement te preparen. In het onderstaande Java voorbeeld kan je zien hoe dit werkt, en of de variable mystring nu enkele of dubbele quotes bevat maakt niets uit (en het is al evenmin vatbaar voor SQL injection).

Code: Selecteer alles

String sql = "INSERT INTO mytable(mycol) values(?)";
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setString(1, mystring);
pstmt.executeUpdate();
Gebruikersavatar
meon
Administrator
Administrator
Berichten: 16609
Lid geworden op: 18 feb 2003, 22:02
Twitter: meon
Locatie: Bree
Uitgedeelde bedankjes: 564 keer
Bedankt: 759 keer
Contacteer:

Wegens niet op voorhand dimensioneerbare input. Zoals ik zeg: de info die daar in staat kan bijna niet genormaliseerd opgeslagen worden.
@r2504... aha. Ik was een dergelijk principe wel al tegen gekomen, maar dat leek me enkel toegevoegde waarde te hebben als je meerdere commando's achter mekaar zou afvuren. Ik ga eens kijken wat ik daar mee kan doen. SQL injection lijkt me al redelijk moeilijk; zeker als ik zoals nu de boel BASE64 voor ik het opsla :-).
Maar inderdaad, als ik het plain ga opslaan komt dat probleem ook weer kijken...
ubremoved_539
Deel van't meubilair
Deel van't meubilair
Berichten: 29849
Lid geworden op: 28 okt 2003, 09:17
Uitgedeelde bedankjes: 446 keer
Bedankt: 1985 keer

meon schreef:@r2504... aha. Ik was een dergelijk principe wel al tegen gekomen, maar dat leek me enkel toegevoegde waarde te hebben als je meerdere commando's achter mekaar zou afvuren.
Het is eigenlijk de enige correcte methode en heeft op zich niets te maken met meerdere commando's. In princiepe zou je nooit strings mogen uitvoeren als SQL commando !
meon schreef:SQL injection lijkt me al redelijk moeilijk; zeker als ik zoals nu de boel BASE64 voor ik het opsla :-).
Never underestimate...
gertd
Plus Member
Plus Member
Berichten: 125
Lid geworden op: 16 jan 2008, 11:20

effe een voorbeeldje in vba 'k heb nu geen tijd om het te porten naar php

Code: Selecteer alles

dim colums(5)
colums(1)= waarde1
colums(2) = waarde2
colums(3) = waarde3
colums(4) = waarde4
colums(5) = waarde5

'for all non numeric colums you can do this for numeric colums to but not needed
' replace all single quotes by two single quotes and start and end with dubble quote

colums(1) = chr(34) + replace(colums(1),"'","''") +ch(34)

sql = "insert into  mytable (colum1,colum2,colum3,colum4,colum5) values("
sql = sql & colums(1) & "," & colums(2) & "," & colums(3) & "," & colums(4) & "," & colums(5) & ")"

db.execute sql


als je de transformatie ook wil doen voor de numerieke kolommen kan ge dit nog in een lus schrijven

Code: Selecteer alles

i=0
while i < 5
     i=i+1
    colums(i) = chr(34) + replace(colums(i),"'","''") +ch(34)

wend
BungaMan
Elite Poster
Elite Poster
Berichten: 1485
Lid geworden op: 16 nov 2005, 09:05

Kijk is in de php manual dan voor mysql_escape_string of mysql_real_escape_string
Please help, looking for a way to get rich and fast
ubremoved_539
Deel van't meubilair
Deel van't meubilair
Berichten: 29849
Lid geworden op: 28 okt 2003, 09:17
Uitgedeelde bedankjes: 446 keer
Bedankt: 1985 keer

BungaMan schreef:Kijk is in de php manual dan voor mysql_escape_string of mysql_real_escape_string
Lijkt mij ook de correct oplossing voor php... voor zover ik kan zien kan php trouwens niet werken met parameter markers :cry:
Gebruikersavatar
meon
Administrator
Administrator
Berichten: 16609
Lid geworden op: 18 feb 2003, 22:02
Twitter: meon
Locatie: Bree
Uitgedeelde bedankjes: 564 keer
Bedankt: 759 keer
Contacteer:

BungaMan schreef:Kijk is in de php manual dan voor mysql_escape_string of mysql_real_escape_string
Helaas onbruikbaar in het geval MSSQL over ODBC eh ;)
Maar ik ga naar die preparing statements kijken, dat lijkt me de juiste weg om te bewandelen.
@r2504 met sprintf kan je toch %s enz gebruiken?
ubremoved_539
Deel van't meubilair
Deel van't meubilair
Berichten: 29849
Lid geworden op: 28 okt 2003, 09:17
Uitgedeelde bedankjes: 446 keer
Bedankt: 1985 keer

meon schreef:Helaas onbruikbaar in het geval MSSQL over ODBC eh ;)
Geen idee... gebruik eigenlijk geen php.
meon schreef:Maar ik ga naar die preparing statements kijken, dat lijkt me de juiste weg om te bewandelen.
Dit kon ik alvast vinden... maar is naar DB2 (geen idee in hoeverre de database driver transparant is met php) vanuit php...

Code: Selecteer alles

$insert_stmt = "INSERT INTO author (last_name, first_name, middle_initial) VALUES(?, ?, ?)";
$result = odbc_prepare($dbconn, $insert_stmt);
$param_array["last_name"] = $last_name;
$param_array["first_name"] = $first_name;
$param_array["middle_initial"] = $middle_initial;
odbc_execute($result, $param_array);
crapiecorn
Elite Poster
Elite Poster
Berichten: 2149
Lid geworden op: 01 feb 2003, 11:58
Uitgedeelde bedankjes: 44 keer
Bedankt: 12 keer

PDO en PEAR::DB hebben ook ondersteuning voor prepared statements. Vind ik persoonlijk iets mooier dan ODBC. Maar ik meen me te herinneren dat je hier niet zo een fan van bent ;-)
Gebruikersavatar
meon
Administrator
Administrator
Berichten: 16609
Lid geworden op: 18 feb 2003, 22:02
Twitter: meon
Locatie: Bree
Uitgedeelde bedankjes: 564 keer
Bedankt: 759 keer
Contacteer:

Ik heb het gewoon nooit aan de praat gekregen met MSSQL ...
Ook de native MSSQL-functies willen niet, ODBC deed het wel.

Da's iets dat me wel vaker opvalt bij PHP. Ik krijg geen native LDAP-functies (nuja) aan de praat, maar als ik het cia COM doe en via Windows een query uitvoer naar Active Directory krijg ik het wél uitgelezen.


Enfin ja, heb bovenstaande suggesties (nog) niet uitgetest, het is maar dat ik weet waar ik moet beginnen als ik de aanpassingen ga maken.

Nog iemand een idee hoe die Fulltext-search werkt?
BungaMan
Elite Poster
Elite Poster
Berichten: 1485
Lid geworden op: 16 nov 2005, 09:05

LIKE '%zoekcriteria%'

of bedoelt ge iets anders?
Please help, looking for a way to get rich and fast
Gebruikersavatar
meon
Administrator
Administrator
Berichten: 16609
Lid geworden op: 18 feb 2003, 22:02
Twitter: meon
Locatie: Bree
Uitgedeelde bedankjes: 564 keer
Bedankt: 759 keer
Contacteer:

"like" is gewoon een operator zoals "AND", dat weet ik wel. Fulltext meer een zoekfunctie à la Google: hoe vaker een bepaalde term voorkomt in het volledige blok, hoe belangrijker dat record wordt, je kan ook meerdere termen gebruiken vaak kunnen daar ook nog eens logische operatoren in zitten.
BungaMan
Elite Poster
Elite Poster
Berichten: 1485
Lid geworden op: 16 nov 2005, 09:05

je steekt ieder woord van de tekst in een aparte tabel en linkt ernaar met een tussentabel waar je de count in opslaagt. das extra werk bij het opslagen van de tekst maar om te zoeken kan je toch al een listing geven die gesorteerd is op het aantal keer een zoekterm voorkomt. dat is de simpelste oplossing die ik me zo direct kan inbeelden. het hangt af van wat het belangrijkste is voor uw programma.
Please help, looking for a way to get rich and fast
Gebruikersavatar
meon
Administrator
Administrator
Berichten: 16609
Lid geworden op: 18 feb 2003, 22:02
Twitter: meon
Locatie: Bree
Uitgedeelde bedankjes: 564 keer
Bedankt: 759 keer
Contacteer:

Ge gaat native functionaliteiten van MSSQL server negeren?
BungaMan
Elite Poster
Elite Poster
Berichten: 1485
Lid geworden op: 16 nov 2005, 09:05

laat maar zitten, ik zie dat mijn DB kennis een beetje achter begint te geraken :oops:
Please help, looking for a way to get rich and fast
ubremoved_539
Deel van't meubilair
Deel van't meubilair
Berichten: 29849
Lid geworden op: 28 okt 2003, 09:17
Uitgedeelde bedankjes: 446 keer
Bedankt: 1985 keer

meon schreef:Ge gaat native functionaliteiten van MSSQL server negeren?
Hier kan je er meer over lezen... http://msdn.microsoft.com/en-us/library/ms142547.aspx

Of als je meteen ook voorbeeldjes wil... http://www.developer.com/db/article.php/3446891
Plaats reactie

Terug naar “Development”