webForumDet fria alternativet

Lägga till data i databas

ASPur ASP

23 svar · 638 visningar · startad av devotion

Medlem sedan jan. 20013 582 inlägg
Frågan#1

Hej!
Följande kod lägger till information från en prislista i txt-format i en databastabell (Tack @nders :) )

<%@LANGUAGE="VBSCRIPT" CODEPAGE="1252"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Untitled Document</title>

<%
dim objConn
dim objRS
dim strLine
dim iEnumber
dim strCategorySolar
dim strUnit
dim curPriceSolar

Set objConn = Server.CreateObject("ADODB.Connection")
ObjConn.ConnectionString = "DSN=Prislista"
ObjConn.Open

Set objRS = Server.CreateObject("ADODB.Recordset")
objRS.Open "tblPricelist", objConn, 3, 2

set objFSO = Server.CreateObject("Scripting.Filesystemobject")
set objFile = objFSO.OpenTextFile (Server.MapPath("\prislistor\solarpris.txt"))
while not objFile.atendofstream

    strLine = objFile.ReadLine

    iEnumber = Mid(strLine, 6, 7)
	strArticlename = Mid(strLine, 18, 41)
	strCategory = Mid(strLine, 59, 4)
	strUnit = Mid(strLine, 64, 4)
	curPrice = Mid(strLine, 67, 10)

objRs.AddNew
objRS("eNumber") = iEnumber
objRS("articleName") = strArticlename
objRS("articleCategorySolar") = strCategorySolar
objRS("articleUnit") = strUnit
objRS("articlePriceSolar") = curPriceSolar
objRS.Update
objRS.MoveNext

wend

objFile.close
set objFile = nothing
set objFSO = nothing
objRS.Close
Set objRS = Nothing
objConn.Close
Set objConn = Nothing

%>
</head>

<body>
Prislistan har lagrats i databasen! 
</body>
</html>

Jättebra!!!

MEN!!

Nu har vi som sagt flera sådana prislistor från olika leverantörer.

Nästa steg är att lägga till nästa prislista till tabellen....

Vilkoren är då; Finns artikeln (eNumber) ska endast priset och kategorin läggas till, finns artikeln inte skall all information läggas till. Det som är unikt för varje leverantör är pris och kategori

Tillägas kan ju att varje prislista har ca 60 000 artiklar...

Leverantörerna heter Solar och Storel

Struktur på databastabellen:

eNumber
articleName
articleCategorySolar
articleCategoryStorel
articleUnit
articlePriceSolar
articlePriceStorel

Hur gör jag detta på bästa sätt?

Fattar att jag måste söka igenom eNumber och göra något villkor med detta. Typ detta:

strSQL = "SELECT eNumber FROM tblPricelist WHERE  (här vet jag inte vad jag ska skriva)
objRS.Open strSQL, objConn, 3, 3
If objRS.EOF Then
objRS.AddNew
objRS("eNumber")=iEnumber
objRS("articleName")=strArticlename
objRS("articleUnit")=strUnit
objRS("articleCategoryStorel")=strCategoryStorel
objRS("articlePriceStorel")=curPriceStorel
objRS.Update

Else

objRS("articleCategoryStorel")=strCategoryStorel
objRS("articlePriceStorel")=curPriceStorel
objRS.Update
End If

Men hur går det med snabbheten eftersom varje eNumber måste kollas?

Mvh

Medlem sedan jan. 20013 582 inlägg
#2

Har kompletterat frågan lite...

Mvh

Medlem sedan jan. 20013 582 inlägg
#3

Hej!
Har nu följande kod:


<%@LANGUAGE="VBSCRIPT" CODEPAGE="1252"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Untitled Document</title>

<%
dim objConn
dim objRS
dim strLine
dim iEnumber
dim strCategory
dim strUnit
dim curPrice
dim strSQL

strSQL = "SELECT * FROM tblPricelist WHERE eNumber = '" & iEnumber & "'"

set objFSO = Server.CreateObject("Scripting.Filesystemobject")
set objFile = objFSO.OpenTextFile (Server.MapPath("\prislistor\storelpris.txt"))

while not objFile.atendofstream

    strLine = objFile.ReadLine

    iEnumber = Trim(Mid(strLine, 1, 8))
	strArticlename = Trim(Mid(strLine, 9, 30))
	strCategoryStorel = Trim(Mid(strLine, 42, 4))
	strUnit = Trim(Mid(strLine, 39, 3))
	curPriceStorel = Trim(Mid(strLine, 46, 7))

Set objConn = Server.CreateObject("ADODB.Connection")
ObjConn.ConnectionString = "DSN=Prislista"
ObjConn.Open

Set objRS = Server.CreateObject("ADODB.Recordset")

strSQL = "SELECT * FROM tblPricelist WHERE eNumber = '" & iEnumber & "'"

objRS.Open strSQL, objConn, 3, 2

If objRS.EOF Then
objRs.AddNew
objRS("eNumber") = iEnumber
objRS("articleName") = strArticlename
objRS("articleCategoryStorel") = strCategoryStorel
objRS("articleUnit") = strUnit
objRS("articlePriceStorel") = curPriceStorel
objRS.Update
objRS.MoveNext

Else
objRS("articleCategoryStorel") = strCategoryStorel
objRS("articlePriceStorel") = curPriceStorel
objRS.Update

End if
wend

objFile.close
set objFile = nothing
set objFSO = nothing
objRS.Close
Set objRS = Nothing
objConn.Close
Set objConn = Nothing

%>
</head>

<body>
Prislistan har lagrats i databasen! 
</body>
</html>

....vilken fungerar!!!!

Men eftersom varje rad måste läsas igenom går det långsamt (60 000 rader)

Finns det andra sätt att göra det på som är snabbare??

Eller hur gör jag en "väntesida" som visas medan datan infogas i databasen??

Mvh

Medlem sedan dec. 20003 563 inlägg
#4

Är eNumber sorterat i txt-filen? I sådana fall går vissa optimeringar att göra.

Den absolut största vinsten du kan göra är att skära ner på antalet databasanrop du gör.
Jämförelsevis kan vi säga att köra if-satser som är hämtat till minnet tar 1 minut, då tar alla databasanrop för samma funktion många timmar. ;)

Alltså: Hämta hem allt, redigera, ladda upp allt
istället för: (Hämta en post, kontrollera, redigera, ladda upp en post) * 60 000

Medlem sedan jan. 20013 582 inlägg
#5

eNumber är sorterat stigande

Jo, jag mistänker att det tar tid att göra så som jag gjort.

Men jag har kört fast nu.

Jag förstår vad du menar i ord men hur ser det ut kodmässigt???

mvh

Medlem sedan jan. 20013 582 inlägg
#6

Ingen som kan hjälpa???

...@nders....?? :r

Mvh

Medlem sedan dec. 20003 563 inlägg
#7

Hämta hem alla produkter en gång och lägg dem i en array m.h.a. getrows().
Eftersom de redan är sorterade kan du för varje rad i textfilen stega i arrayen utan att missa några poster.
Om du hittar en post i arrayen med samma id som i textfilen så checkar du med nedanstående metod (*).
Skulle du hitta ett id högre än det från textfilen, betyder det att id:t inte finns och du får då skapa en annan metod (**) som lägger till den i databasen, istället för att redigera.

För varje rad i textfilen kontrollerar du gentemot informationen i arrayen.
Hittar samma id:
(*) Kontrollera att den aktuella datan är lika. Finns skilnader generear du en UPDATE-fråga, som du lägger t.ex. i en kö.
Annars struntar du i denna post då den uppenbarligen är aktuell.

Hittar inte samma:
(**) Skapa en INSERT som du lägger i en kö, möjligtvis samma.

Sedan kör du genom den kö du skapat tidigare sekventiellt och exekverar alla dina SQL-frågor.

Hur du utformar köer, SQL-fråge-generator och jämförelser är helt upp till hur du känner dig. ;)

Börja gärna testa dig fram så hjälper vi gärna till.

Medlem sedan jan. 20013 582 inlägg
#8

Oj, oj, oj.....

Mycket nytt för mig; köer, arrayer, getrows, sekventiellt.... :)

Får läsa på mer....

Mvh

Medlem sedan dec. 20003 563 inlägg
#9

Nja. Så farligt är det nog inte.

Köer är mest ett begrepp utan teknisk definerad ram.
En kö kan vara allt från en array, länkad lista, träd eller varför inte en graf. Datastruktur spelar ingen roll bara den fyller sin funktion av att vara en kö. En kö där du kan lägga till eller ta bort "objekt", egentligen vad som helst.

Sekventiellt har inte heller det så mycket med programmering att göra. Det är ett svenskt ord som skulle kunna översättas som "efter varrandra". Motsatsen till paralellt "sida vid sida".

Getrows är en metod i asp som hämtar hem all info från ett recordset (Eller kanske snarare från DBMS? Osäker på definition) och lägger den snyggt i en array, vilket gör att man direkt kan stänga databaskopplingen. Till motsats att använda sig av och redigera ett RecordSet där databaskopplingen är öppen ända tills man stänger det. Går att läsa sig till på msdn eller någon annan asp-sida. Finns många exempel här om du söker.

Arrayer däremot är en nästan fundamental datastruktur inom programmering. Du kan läsa lite här t.ex.

Medlem sedan juni 200032 969 inlägg
#10

Bara en liten snabbis:

cyprys skrev:

Getrows är en metod i asp som hämtar hem all info från ett recordset (Eller kanske snarare från DBMS? Osäker på definition)

GetRows() är en metod som tillhör recordsetobjektet. Så, resultatet blir en tvådimensionell array med samma innehåll som recordsetet. Jag har arbetat ganska mycket med getrows-arrayer och kan säga att det i stort sett alltid är hemskt att arbeta med. Det man eventuellt vinner i prestanda förlorar man i överskådlighet, i synnerhet när man arbetar i flerlagersapplikationer där man inte hämtar data på "samma ställe" som man skriver ut det. Jämför överskådligheten i följande exempel:

strSQL = "SELECT item, description, price, fld1, fld2, fld3 FROM tbl"
set objRS = objConn.Execute(strSQL)
While not objRS.EOF
     Response.write "<tr><td>" & objRS("item") & "</td><td>" & objRS("fld3") & "</td><td>" & objRS("description") & "</td><td>" & objRS("fld1") & "</td><td>" & objRS("price") & "</td></tr>"
     objRS.MoveNext
Wend
strSQL = "SELECT item, description, price, fld1, fld2, fld3 FROM tbl"
set objRS = objConn.Execute(strSQL)
if not objRS.EOF then
     varRS = objRS.GetRows()
     for i = 0 to ubound(varRS, 2)
          Response.write "<tr><td>" & varRS(0, i) & "</td><td>" & varRS(5, i) & "</td><td>" & varRS(1, i) & "</td><td>" & varRS(3, i) & "</td><td>" & varRS(2, i) & "</td></tr>"
     Next
End if

I stora kodstycken med långa selectlistor: horribelt. Dessutom är man väldigt beroende av fältens placering i SELECT-listan. Om recordsetet byggs upp av en SQL-fråga där man använder * istället för att specificera alla fält, då ska man vara försiktig om man blir tvungen att lägga till ett fält i tabellen. Än roligare blir det om det dessutom är en join, och man lägger till fält i den "vänstra" tabellen, då alla fält automatiskt skjuts ett steg till höger, och din GetRows()-kod blir fel.

Jag använder (när jag har möjligheten att välja) endast getrows-arrayer för att lagra mer eller mindre statisk data i sessions- eller application-objekt, eftersom det inte är någon höjdare att lagra recordsets i dessa. Exempel kan vara en kategoristruktur för en webshop eller fraser för en meny med flera språk.

Det blev en aning off topic, och jag säger inte att GetRows() inte är rätt för det här ändamålet (det kan det mycket väl vara), bara att man skall idka en aning försiktighet.

Edit: Det blev ingen snabbis, var ju tvungen att förklara lite. :)

Mvh

Medlem sedan jan. 20013 582 inlägg
#11

Ok, börjar förstå vad getrows och arrayer är....

MEN!!!! :x

Nu börjar det bli motstridigt... :)

Jag har gjort en kod som fungerar men som jag inser blir långsam.

Finns det något sätt att göra samma sak som den kod jag gjort fast snabbare???

Tack alla som engagerar sig!!! :birp

Mvh

Medlem sedan juni 200032 969 inlägg
#12

Vad menar du med långsam? Hur lång tid tar det? Hur ofta kommer du köra scriptet?

Om du visar koden kanske vi kan se något som du kan förbättra. :)

Medlem sedan jan. 20013 582 inlägg
#13

Koden finns här ovan med tidsnummer : 2004-11-27 13:14

Medlem sedan jan. 20013 582 inlägg
#14

Det är i o f s inte så ofta som scriptet ska köras. Kommer prislistor ca var 3:e månad.

Medlem sedan juni 200032 969 inlägg
#15

Okay.

Möjligen kan scriptet gå snabbare om du istället för AddNew-metoden använder en INSERT-fråga för varje post.

Och; om scriptet tar så lång tid på sig så scripttimeouten riskerar att inträffa, kan du alltid sätta upp timeouten så scriptet kan köras längre tid.

Mvh

Medlem sedan jan. 20013 582 inlägg
#16

Är detta det bästa sättet??? Ska jag inte använda getrows??

Hur skulle koden se ut med en insert-fråga för varje post??

Nu ligger ju denn akod inom loopen. Är det rätt???

Set objConn = Server.CreateObject("ADODB.Connection")
ObjConn.ConnectionString = "DSN=Prislista"
ObjConn.Open

Set objRS = Server.CreateObject("ADODB.Recordset")

strSQL = "SELECT * FROM tblPricelist WHERE eNumber = '" & iEnumber & "'"

objRS.Open strSQL, objConn, 3, 2

Mvh

Medlem sedan jan. 20013 582 inlägg
#17

Nu tar det ca 20 - 30 sekunder att gå igenom 50 artiklar och lägga till 50 nya....

Hmmm

Kan tänka mig vilken tid det tar att gå igenom 60 000 :o

Mvh

Medlem sedan juni 200032 969 inlägg
#18

Jag tror inte du kommer tjäna något på GetRows() i det här fallet, eftersom alla SELECTs du gör är så små, bara en enda post. Jag har förkortat och förenklat koden en aning, samt ändrat till INSERT resp. UPDATE-frågor för insättandet och uppdaterandet. Jag har också lagt till lite replace runt det som ska in till databasen, så det inte blir fel om det ligger en apostrof någonstans. Jag har utgått ifrån att fälten articleUnit och articlePriceStorel är numeriska i tabellen.

<%@LANGUAGE="VBSCRIPT" CODEPAGE="1252"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Untitled Document</title>

<%
dim objConn, objRS, strLine, iEnumber, strCategory, strUnit, curPrice, strSQL

set objFSO = Server.CreateObject("Scripting.Filesystemobject")
set objFile = objFSO.OpenTextFile (Server.MapPath("\prislistor\storelpris.txt"))

Set objConn = Server.CreateObject("ADODB.Connection")
ObjConn.Open "DSN=Prislista"

while not objFile.atendofstream

    strLine = objFile.ReadLine

    iEnumber = Replace(Trim(Mid(strLine, 1, 8)), "'", "''")
    strArticlename = Replace(Trim(Mid(strLine, 9, 30)), "'", "''")
    strCategoryStorel = Replace(Trim(Mid(strLine, 42, 4)), "'", "''")
    strUnit = Trim(Mid(strLine, 39, 3))
    curPriceStorel = Trim(Mid(strLine, 46, 7))

    strSQL = "SELECT * FROM tblPricelist WHERE eNumber = '" & iEnumber & "'"

    set objRS = objConn.Execute (strSQL)

    If objRS.EOF Then
    ' Ny artikel, gör insert.
         strSQL = "INSERT INTO tblPriceList (eNumber, articleName, articleCategoryStorel, articleUnit, articlePriceStorel) VALUES (" & _
                  "'" & iEnumber & "', '" & strArticleName & "', '" & strCategoryStorel & "', " & strUnit & ", " & curPriceStorel & ")"

    Else
         strSQL = "UPDATE tblPriceList SET articleCategoryStorel = '" & strCategoryStorel & "', articlePriceStorel =  " & curPriceStorel
    End if

    objConn.Execute strSQL,,128

wend

objFile.close
set objFile = nothing
set objFSO = nothing
objRS.Close
Set objRS = Nothing
objConn.Close
Set objConn = Nothing

%>
</head>

<body>
Prislistan har lagrats i databasen! 
</body>
</html>

Gör gärna en jämförelse i hur lång tid originalkoden tar att köra jämfört med denna.

Om du ger mig några minuter så får du en ny version som helt utesluter alla 60000 SELECT-frågor. :)

Edit:

Nu ligger ju denn akod inom loopen. Är det rätt???

Nej, det är inte helt bra att öppna samma databaskoppling 60000 gånger. :)

Mvh

Medlem sedan juni 200032 969 inlägg
#19

Ny version, utan alla SELECTs för att se om en artikel finns:

<%@LANGUAGE="VBSCRIPT" CODEPAGE="1252"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Untitled Document</title>

<%
dim objConn, objRS, strLine, iEnumber, strCategory, strUnit, curPrice, strSQL

set objFSO = Server.CreateObject("Scripting.Filesystemobject")
set objFile = objFSO.OpenTextFile (Server.MapPath("\prislistor\storelpris.txt"))

Set objConn = Server.CreateObject("ADODB.Connection")
ObjConn.Open "DSN=Prislista"

while not objFile.atendofstream

    strLine = objFile.ReadLine

    iEnumber = Replace(Trim(Mid(strLine, 1, 8)), "'", "''")
    strArticlename = Replace(Trim(Mid(strLine, 9, 30)), "'", "''")
    strCategoryStorel = Replace(Trim(Mid(strLine, 42, 4)), "'", "''")
    strUnit = Trim(Mid(strLine, 39, 3))
    curPriceStorel = Trim(Mid(strLine, 46, 7))

    ' Först kör vi en update om artikeln redan finns.
    strSQL = "UPDATE tblPriceList SET articleCategoryStorel = '" & strCategoryStorel & "', articlePriceStorel =  " & curPriceStorel & " WHERE eNumber = '" & iEnumber  & "'"

    objConn.Execute strSQL, lngRA, 128

    if lngRA = 0 then
         ' Ny artikel, gör insert.
         strSQL = "INSERT INTO tblPriceList (eNumber, articleName, articleCategoryStorel, articleUnit, articlePriceStorel) VALUES (" & _
                  "'" & iEnumber & "', '" & strArticleName & "', '" & strCategoryStorel & "', " & strUnit & ", " & curPriceStorel & ")"
         objConn.Execute strSQL, , 128
    end if

wend

objFile.close
set objFile = nothing
set objFSO = nothing
objRS.Close
Set objRS = Nothing
objConn.Close
Set objConn = Nothing

%>
</head>

<body>
Prislistan har lagrats i databasen! 
</body>
</html>

Koden fungerar så här:

  1. Kör en updatefråga, kontrollera om den påverkade någon post. Om inte, gå till 2)
  2. Kör en insertfråga, eftersom updaten inte påverkade någon post, och artikeln således inte redan fanns.

Denna kod kommer att gå snabbare ju fler poster som redan finns i tabellen, så om jag förstått systemet rätt så gör du bara update på befintliga poster (dvs produkter som fanns i systemet sedan inläsning av tidigare prislista), och insert på nya?

Vad gör du med produkter som utgår?

Mvh

Medlem sedan jan. 20013 582 inlägg
#20

Du är som en jultomte... :)

Update på befintliga poster
Insert på nya

Det är rätt!!

Har inte tänkt på det....

Men eftersom du säger det så borde scriptet ta bort articlar från databasen som inte finns i den nya prislistan....

146 ms totalt · 3 externa anrop · v20260731065814-full.8a4e7caf
0 ms — hämta forumlista (cache)
0 ms — hämta statistik (cache)
144 ms — hämta tråd, inlägg och bilagor (db)