22. februar 2004 - 17:07Der er
55 kommentarer og 1 løsning
Mystisk problem med næsten ens INSERTs - nogle virker, andre ikke
Jeg har et script som laver nogle INSERTs med filoplysninger Tager jeg f.eks. filer på min harddisk ser INSERT sådan ud: insert into filer (navn, storrelse, storrelseangivelse, type, sti) values ('DR.CFG', 2.87, 'KB', 'CFG-fil', '\\Deathr')
Og tager jeg filer fra mit CD-ROM drev ser det sådan ud: insert into filer (navn, storrelse, storrelseangivelse, type, sti) values ('ENTSRV1.TXT', 39.88, 'KB', 'Tekstdokument', '\\DOCS')
Som man kan se, er der ikke stor. Ikke desto mindre fejler den sidste(fra CD-ROMen) med denne fejl: Microsoft OLE DB Provider for ODBC Drivers (0x80040E09) [TCX][MyODBC]You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1
Er der nogen der kan forklarer mig hvad problemet er? For jeg fatter det simpelthen ikke. :( Og forøvrigt er det ligegyldigt om jeg laver 1,10,100 eller 1000 INSERTs af gangen - resultatet er altid det samme.
Prøv lige at lade dit script skrive sine inserts til en tekstfil fremfor at fyre dem af. Så kan du checke dem i hånden og se om det blot er en scriptfejl at nogle fejler..
Nix, de her kommer fint ind: ('Kopi af RALLYTekstdokumentTekstdokument.PIF', 2.78, 'KB', 'Genvej til MS-DOS-program', '\\Deathr'), ('Kopi af RALLYTekstdokumentTekstdokument.txt', 13, 'B', 'Tekstdokument', '\\Deathr')
Også har jeg lavet det sådan at den sættes til et bestemt tal, f.eks. 100, så den sidste del blever lavet 100 gange - det virker som sagt fint på min ene disk, men ikke andre steder. Og det hjælper ikke at sætte tallet til 1.
Ok, min ide byggede på, at i nogle script sprog er der grænser for hvor lange strenge kan være, men det er der ikke rigtig i vbs, så det er ikke det.
Umiddelbart giver dit problem ikke mening; hvad disk du scanner for at opbygge dine inserts er databasen jo totalt ligeglad med - for den er det bare nogle data.
Har du ikke mulighed for at se hvad din MySQL database reelt set modtager fra klienten?
Og lige et forsøg, prøv at tilføje følgende funktion til dit script
function Fix(name) Fix = "'" & Replace(name,"'","") & " '" end function
Hvis jeg bruger din kode, virker det overhovet ikke.
Men "gamle" kode kan jeg få til at virker på nogle af mine mapper. F.eks. en med store filer(+600 mb) og i denne mappe (G:\download\doc) som få små filer, men ikke i G:\ddrev som indeholder mange filer+mapper af forskellig størrelse. Koden fejler dog altid på den første fil. hvilket er den underste undermappe(hvis man kan kalde det det) som her er: '\\ddrev\\dmivejr3\\Data'.
Hele INSERTen: insert into filer (navn, storrelse, storrelseangivelse, type, sti) values ('rad00000.bmp', 4.63, 'KB', 'ACDSee BMP Image', '\\ddrev\\dmivejr3\\Data')
Ja, jeg kopierede din kode ind og udkommenterede min egen. INSERTen ud taget fra skærmen og bliver udskrevet således: Response.write "sql " & sql & "<br>"
Spørg bare hvis der er noget du ikke forstår, så vil jeg (prøve at) forklare koden. :)
<% cdid = Request.QueryString("id") genindekser = Request.QueryString("genindekser") Server.ScriptTimeout = 50000 Const adOpenKeyset = 1 Const adLockOptimistic = 3 Set Conn = Server.CreateObject("ADODB.Connection") Conn.Open "DRIVER={MySQL}; server=localhost; database=database; uid=administrator; pwd=;" if genindekser = "true" then if cdid = "" then response.write "Fejl. CD kunne ikke indekseres. Intet CD id. Prøv igen." response.end else sql = "delete * from filer where cdid="&cdid Conn.execute(sql) end if else if genindekser = "false" then rootpath = "G:\ddrev" level = 0 Response.Write "Directory: " & rootpath & "<BR><BR>" antalfiler = 0 antalmapper = 0 sqltest = 0 sql = "insert into filer (navn, storrelse, storrelseangivelse, type, sti) values"
sub getPath(strPath,level) Set fsObj = CreateObject("Scripting.FileSystemObject") Set MainFolder = fsObj.GetFolder(strPath) Set Files = MainFolder.Files Set Folders = MainFolder.subfolders
For Each Folder in Folders call getPath(strPath & "\" & folder.name,level+1) next
For Each File in Files sqltest = sqltest + 1 nysize = 0 nysize = file.Size i = 0 '0=bytes ; 1=kbytes ; 2=Mbytes ; 3 = Gbytes
do while nysize > 1024 and i < 3 nysize = nysize / 1024 i=i+1 loop arr = split(nysize, ",") nysize = FormatNumber(arr(0),0,0,0,-1) if Ubound(arr)>=1 then nysize = nysize & "." & (left(arr(1), 2)) end if 'Sæt enten KB,MB eller GB Select case i case 0 nysizeangiv = "B" case 1 nysizeangiv = "KB" case 2 nysizeangiv = "MB" case 3 nysizeangiv = "GB" end select
sti = len(file.parentfolder) arr = split(file.parentfolder, "\") stien = "" if Ubound(arr)>=1 then for i = 0 to UBOUND( arr ) next for j = 1 to (i-1) stien = stien & "\\" & arr(j) next end if
set fsObj = Nothing set MainFolder = Nothing end sub
call getPath(rootpath,level) sql = left(sql, (len(sql) -1)) Response.write "størrelsen af sql: " & len(sql) & "<br>" & "sql " & sql Conn.execute(sql) sql = "UPDATE cder SET indeksering=0" Conn.execute(sql) else 'if genindekser = false then response.write "Fejl. CD kunne ikke indekseres. Prøv igen." response.end end if end if function Fix(name) Fix = "'" & Replace(name,"'","") & " '" end function %>
Ok, jeg kan se hvorfor min fix ikke fungerede. Du har ikke tilføjet et , efter strengen når du opbygger et bulk statement.
Dernæst, er lidt træt så muligvis er det i skoven, men lav lige din
sql = left(sql, (len(sql) -1))
om til
sql = left(trim(sql), (len(trim(sql)) -1))
og den her sti = len(file.parentfolder) arr = split(file.parentfolder, "\") stien = "" if Ubound(arr)>=1 then for i = 0 to UBOUND( arr ) next for j = 1 to (i-1) stien = stien & "\\" & arr(j) next end if
kan laves om til
sti = replace(file.parentfolder,"\","\\")
Slutteligt, du har vist byttet om på to linjer her ved 1 statement; sql = "insert into filer (navn, storrelse, storrelseangivelse, type, sti) values" Conn.execute(sql)
do while nysize > 1024 and i < 3 nysize = nysize / 1024 i=i+1 loop arr = split(nysize, ",") nysize = FormatNumber(arr(0),0,0,0,-1) if Ubound(arr)>=1 then nysize = nysize & "." & (left(arr(1), 2)) end if if nysize = NULL or nysize = "" then nysize = 0 i = 0 end if
Jeg kunne forstille mig at det har noget at gøre med denne linie: nysize = FormatNumber(arr(0),0,0,0,-1)
Ved du noget hvor lang tid mysql er om at slette f.eks. 16000 poster på 1.4 Ghz med 512 ram? Jeg synes det tager urimelig lang tid, dvs mere end 5 minutter. Og bare jeg prøver at opdatere 1 eller 2 poster i Mysql-Front i samme tabel, tager det også enormt lang tid.
arne_v -> Se min kommentar af 23/02-2004 10:55:28: "Det var dit sidste forslag, der var fejlen."
Som var: Kommentar: trer 23/02-2004 01:30:20 "Slutteligt, du har vist byttet om på to linjer her ved 1 statement; sql = "insert into filer (navn, storrelse, storrelseangivelse, type, sti) values" Conn.execute(sql)"
Problemet var at der var byttet rundt på disse to linier: Conn.execute(sql) sql = "insert into filer (navn, storrelse, storrelseangivelse, type, sti, cdid) values"
arne_v> I scriptet var der byttet om på nogle linjer så det SQL der blev vist på skærmen ikke var det samme som blev sendt til databasen. MySQL modtog derfor kun et halvt INSERT statement - og det brokkede den sig over.
chrisrj> Mht indeks; Ja, man skal oprette det selv, men primærnøglen (en constraint) er på næsten alle databaser i dag automatisk lavet som et indeks.
Indeks gør at det er hurtigere at finde rækker, men sløver ned ved simple indsættelser og bulk-sletninger da indekset skal opdateres. Derfor spurgte jeg om indeks (der er en ok artikel om indeks på MySQL i artikel sektionen).
MySQL benytter filer som tabeller hvis jeg husker ret. Den er derfor meget følsom for fragmentation af disse filer. Prøv at defragmentere din disk.
trer -> det gør jeg nok også på et tidspunkt, men da jeg tjekkede med Diskeeper var der ingen af mysql filerne der var fragmenteret. "MySQL benytter filer som tabeller hvis jeg husker ret" Jeps.
arne_v -> fordi der ikke var så mange at den del af kode blev udført, men kun den sidste del: if sqltest = 999 then ... ... ... end if next set fsObj = Nothing set MainFolder = Nothing end sub
call getPath(rootpath,level)sql = left(trim(sql), (len(trim(sql)) -1)) Response.write "størrelsen af sql: " & len(sql) & " Antal filer: " & sqltest & "<br>" Conn.execute(sql) sql = "UPDATE cder SET indeksering=0 where id ="&cdid Conn.execute(sql)
Nem & hurtig måde at checke det på; Tryk CTRL-SHIFT-ESC for at starte taskmanager. Se på fanen Processes og tilføj kolonnen PF Delta. Hold øje med hvad der sker på den når du indsætter / sletter rækker.
Den bør blive stående på 0 - ellers swapper din maskine til disk.
Jeg forøbrigt lige lagt mærke til at alle posterne eksistere 2 gange - altså er lagt ind 2 gange.
Det pudsige er, at filernes id(filid) er precist antallet filer større. Altså hvis der er f.eks. 30 filer på CDen, vil med IDerne xxx01 og xxx31 være identiske.
Jeg har nu gennemtjekket koden, og jeg KAN ikke finde nogen fejl. Kan du?
<HTML> <HEAD></HEAD> <BODY> <FONT SIZE="2" FACE="Courier"> <% cdid = Request.QueryString("id") genindekser = Request.QueryString("genindekser") Server.ScriptTimeout = 50000 Const adOpenKeyset = 1 Const adLockOptimistic = 3 Set Conn = Server.CreateObject("ADODB.Connection") Conn.Open "DRIVER={MySQL}; server=localhost; database=database; uid=administrator; pwd=;" if genindekser = "true" then 'Skal CD genindekseres? if cdid = "" then 'Hvis CD skal genindekseres skal vi bruge et CDid response.write "Fejl. CD kunne ikke indekseres. Intet CD id. Prøv igen." response.end else sql = "delete * from filer where cdid="&cdid Conn.execute(sql) end if else if genindekser = "false" then 'Skal CD indekseres? rootpath = "f:\" 'Her finder vi filerne level = 0 'Vi starter i 'rootpath' Response.Write "Directory: " & rootpath & "<BR><BR>" antalfiler = 0 antalmapper = 0 sqltest = 0 ' Vi opbygger starten på sql sætningen sql = "insert into filer (navn, storrelse, storrelseangivelse, type, sti, cdid) values"
sub getPath(strPath,level) '"arbejdshesten" :) response.write "<b>Kald til sub</b><br>" Set fsObj = CreateObject("Scripting.FileSystemObject") Set MainFolder = fsObj.GetFolder(strPath) Set Files = MainFolder.Files Set Folders = MainFolder.subfolders
For Each Folder in Folders 'vi finder alle mapper der skal gennemsøges for filer response.write "ny mappe: <b>" & folder.name & "</b><br>" call getPath(strPath & "\" & folder.name,level+1) 'rekursivt kald next response.write "ikke flere undermapper<br>" For Each File in Files 'her arbejder vi med de enkelte filer response.write "ny fil: <b>" & file.name & "</b><br>" sqltest = sqltest + 1 'her tæller vi antallet af filer op nysize = 0 nysize = file.Size 'put filstørrelsen(i bytes) over i en variabel i = 0 '0=bytes ; 1=kbytes ; 2=Mbytes ; 3 = Gbytes
do while nysize > 1024 and i < 3 'her gør vi filstørrelsen læsevenlig response.write "retter filstørrelse<br>" nysize = nysize / 1024 ', dog ikke mere end til gigabytes i=i+1 loop arr = split(nysize, ",") nysize = FormatNumber(arr(0),0,0,0,-2) if Ubound(arr)>=1 then response.write "der er komma<br>" nysize = nysize & "," & (left(arr(1), 2)) end if if nysize = NULL or nysize = "" then 'her sikre vi os at der ER en filstørrelse response.write "filstørrelse er 0<br>" nysize = 0 i = 0 end if 'Sæt enten KB,MB eller GB Select case i case 0 nysizeangiv = "B" response.write "filstørrelse er byte<br>" case 1 nysizeangiv = "KB" response.write "filstørrelse er kilobyte<br>" case 2 nysizeangiv = "MB" response.write "filstørrelse er megabyte<br>" case 3 nysizeangiv = "GB" response.write "filstørrelse er gigabyte<br>" end select 'her formatere vi stien til databasen sti = file.parentfolder sti = right(trim(sti), (len(trim(sti)) -2)) 'her fjerner vi drevnavnet, f.eks. i: stien = replace(sti,"\","\\")
if sqltest = 10 then 'her skal vi ind når vi har samlet 999 filer 'her sætter vi den sidste fil på sql sætningen sql = sql & " (" & Fix(file.name) & ", " & Fix(nysize) & ", " & Fix(nysizeangiv) & ", " & Fix(file.Type) & ", " & Fix(stien) & ", " & cdid & ")" 'her vises størrelsen af sql sætningen og antallet af filer(minus 1) der skrives til databasen Response.write "størrelsen af sql: " & len(sql) & " Antal filer: " & sqltest & "<br>" response.write "<b>så executer vi sql</b> " & sql & "<br>" 'Conn.execute(sql) 'her smider vi dem i databasen 'her begynder vi ny sql sætning sql = "insert into filer (navn, storrelse, storrelseangivelse, type, sti, cdid) values" sqltest = 0 'husk at sætte antallet af filer tilabge til 0 response.write "<b>frisk sql:</b> " & sql & "<br>" 'response.end else 'hvis vi endnu ikke er nået op på 999 filer, skal vi bare tilføje filen til sql sætningen response.write "så laver vi sqlsætning:<br>" sql = sql & " (" & Fix(file.name) & ", " & Fix(nysize) & ", " & Fix(nysizeangiv) & ", " & Fix(file.Type) & ", " & Fix(stien) & ", " & cdid & ")," response.write "sql er nu: " & sql & "<br>" end if response.write "<b>færdig med fil i forløkke</b><br><br>" next
set fsObj = Nothing set MainFolder = Nothing response.write "<b>færdig med filerne i mappen</b><br><br>" end sub
response.write "så starter vi<br>" call getPath(rootpath,level) 'her kalder vi "arbejdshesten"
'her sikre vi os at der ikke er flere filer der skal lægges i databasen if not sql = "insert into filer (navn, storrelse, storrelseangivelse, type, sti, cdid) values" then response.write "sql mangler at execute<br>" sql = left(trim(sql), (len(trim(sql)) -1)) 'her fjerner vi det sidste komma 'her vises størrelsen af sql sætningen og antallet af filer(minus 1) der skrives til databasen Response.write "størrelsen af sql: " & len(sql) & " Antal filer: " & sqltest & "<br>" 'Conn.execute(sql) 'her smider vi dem i databasen response.write "<b>sql er executed:</b> " & sql & "<br>" end if 'her sætte vi CDen til at være indekseret sqle = "UPDATE cder SET indeksering=0 where id ="&cdid 'Conn.execute(sqle) response.write "<b>sidste sql er executed:</b> " & sqle else 'if genindekser = false then response.write "Fejl. CD kunne ikke indekseres. Prøv igen." response.end end if end if function Fix(name) 'hjælpe funktion til tekstfelterne i databasen response.write "vi fixer..." & name & " " Fix = "'" & Replace(name,"'","") & "'" response.write "fixet..." & Fix & "<br>" end function %> </FONT> </BODY> </HTML>
Sig til hvis du vil prøve koden, så smider jeg lige et link.
Jeg får nok først tid at kigge på koden i weekenden - vil stort set ikke være online de næste par dage.
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.