Avatar billede svinget Praktikant
22. marts 2010 - 14:51 Der er 14 kommentarer og
1 løsning

Tjek om der er data

Af og til rammer jeg ind i at min "SELECT * from" ikke får data retur, så jeg får en tom side eller denne fejl:

ADODB.Field error '80020009'
Either BOF or EOF is True, or the current record has been deleted. Requested operation requires a current record.

Er det muligt at lægge et kald ind I toppen af siden, som laver en Response.Redirect eller laver en response.write hvis der ikke er nogen data?
Avatar billede claes57 Ekspert
22. marts 2010 - 15:28 #1
Typisk vil du aldrig få BOF, da det kun er, hvis du læser tabellen sekventielt baglæns.
Hvis du slå direkte op på en post (noget med 'where xx=yy') så vil du kun kunne få EOF.
Så lige efter kaldet til databasen laver du en
if rs.eof then response.redirect fejl.asp
men du skal så kalde databasen via
strSQL=strSQL & " ORDER BY " & strItem & ", Postnr"
rst.Open strSQL, con, adOpenForwardOnly, adLockReadOnly
if rst.eof then

og ikke noget med
SQL = "UPDATE basis SET inklmoms=" & Request("inklmoms") & " WHERE id=1"
Con.Execute(SQL)

hvis du bruger den sidste type kald, så skal du i stedet validere dine data før du opdaterer/sletter, fx

SQL=strSQL & " ORDER BY " & strItem & ", Postnr"
rst.Open SQL, con, adOpenForwardOnly, adLockReadOnly
if rst.eof then response.redirect fejl.asp
SQL = "UPDATE basis SET inklmoms=" & Request("inklmoms") & " WHERE id=1"
Con.Execute(SQL)

ovenstående er bare asp-kode nappet fra forskellige stedet - de hænger ikke sammen til noget brugbart.
Avatar billede softspot Forsker
22. marts 2010 - 15:47 #2
Du kan gøre noget á la dette:

dinConnectionStreng = "... dine forbindelsesdata ..."
set conn = Server.CreateObject("ADODB.Connection")
conn.open dinConnectionStreng
set rs = conn.Execute("SELECT * FROM tabel1")
if not rs.eof then
  ' udskriv eller arbejd med dine data her...
else
  response.write "Der var ingen data"
end if
rs.close
conn.close
set rs = nothing
set conn = nothing


Det er vigtigt at du får lukket din databaseforbindelse igen, ellers risikerer du at løbe tør for forbindelser. Det betyder også at det IKKE er en god idé at redirecte siden i else-delen af if-sætningen, da din forbindelse så ikke bliver lukket korrekt.
Avatar billede Slettet bruger
22. marts 2010 - 17:43 #3
Hej.

Jeg ville nok bruge den her if kode i stedet for.. :-)

If Not (rs.EOF Or rs.BOF) Then
Response.Write("Der er data, du")
Else
Response.Write("Der er ingen data, du")
'Eller hvis du vil redirecte.
'Response.Redirect("IngenData.asp)
End If
Avatar billede softspot Forsker
22. marts 2010 - 18:24 #4
Med en forward only cursor giver der ikke meget mening at tjekke for BOF (som claes57 også var inde på i sit indlæg).

Og så var der jo lige det der med at redirecte inden der er lukket for forbindelsen (eller rettere at lade være med det)... ;-)
Avatar billede Slettet bruger
22. marts 2010 - 21:14 #5
Det med at lukke forbindelsen inden kan man jo bare lave en dim..


dinConnectionStreng = "... dine forbindelsesdata ..."
set conn = Server.CreateObject("ADODB.Connection")
conn.open dinConnectionStreng
set rs = conn.Execute("SELECT * FROM tabel1")
Dim Redirect = "false"

if Not (rs.EOF) then
Response.Write("Vis data")
else
Redirect = "true"

end if

rs.close
conn.close
set rs = nothing
set conn = nothing

if (Redirect = "true") Then Response.Redirect("IngenData.asp")



Læg mærke til at rs.BOF ikke er med.. ;)
Avatar billede svinget Praktikant
24. marts 2010 - 09:12 #6
Tak for svarene - jeg har prøvet lidt af hver, og kommet frem til at denne virker når jeg looper:
##########
<%
strSQL = "SELECT * FROM report005 WHERE Attribute_Attribute_ID = " & request.QueryString("id") & " "
set report005 = objConn.Execute(strSQL)
if not report005.eof then
do while not report005.eof
%>

Data her: <%=report005.Fields("Rule_ID")%>

<% 
report005.MoveNext
  loop 
else
  response.write "No data available"
End If
%>
##########

Jeg ved ikke om det er den optimale kode, men hvad kan jeg gøre når jeg ikke skal loope, men bare liste indholdet af en tabel?
Avatar billede softspot Forsker
24. marts 2010 - 09:31 #7
Den kode er fin nok. Den fanger de mest almindelige fejlsituationer.

Du skal dog være opmærksom på SQL-injections og at du åbner porten på vid gab for dette problem med den kode du laver. Det er konstruktionen af din SQL-sætning du skal være opmærksom på.

Der findes forskellige muligheder for at beskytte sig mod dette, men den bedste er nok at lære at benytte parametreriserede forespørgsler mod din database. Du kan læse min artikel om emnet her: http://www.eksperten.dk/guide/1250, men der findes naturligvis også rigtig mange andre gode artikler om emnet (keysersoze, en anden bruger her på eksperten, har bla. lavet en hvor SQL-injections bliver demonstreret: http://www.web-dev.dk/post/SQL-injections-mere-end-bare-et-pling.aspx).
Avatar billede svinget Praktikant
24. marts 2010 - 10:28 #8
Det kan jeg godt se - det er dog lidt "langhåret" at dække sig af mod SQL-injektions, når man ikke er en haj, men det må jeg tage mig tiden til at finde ud af :)

Jeg befinder mig dog på et intranet, så der er umiddelbart ikke den type personer med usle hensigter.

Hvordan kan jeg lave et tilsvarende tjek om der er data når jeg ikke looper?:

<%
strSQL = "SELECT * FROM report005 WHERE Attribute_Attribute_ID = " & request.QueryString("id") & " "
set report005 = objConn.Execute(strSQL)
%>

Data her: <%=report005.Fields("Rule_ID")%>
Avatar billede softspot Forsker
24. marts 2010 - 11:12 #9
Dit tjek ligger i if-sætningen og den kan bruges uanset om der er en løkke involveret eller ej (som vist i eksemplet i indlæg #2).
Avatar billede softspot Forsker
24. marts 2010 - 11:18 #10
Den tid du investerer i at finde ud af hvordan parametre fungerer er rigtig godt givet ud, så det kan jeg kun anbefale at du tager dig tid til :-)
Avatar billede softspot Forsker
24. marts 2010 - 11:55 #11
Parametre behøver ikke være sindsygt svært. Du kan pakke opsætningen af command-objektet ind i en funktion og benytte en ultrasimpel metode til at kalde command-objektet (som nok kan bruges i 80-90% af de tilfælde du har behov for at kalde databasen). Nogenlunde således (du kan med fordel placere funktionen i en separat fil, så du kan drage nytte af den mange steder):


<%
function getTextCommand(conn, sql)
  dim cmd
  set cmd = Server.CreateObject("ADODB.Command")
  cmd.CommandText = sql
  cmd.CommandType = adCmdText
  cmd.ActiveConnection = conn
  set getTextCommand = cmd
end function
%>


<%
strSQL = "SELECT * FROM report005 WHERE Attribute_Attribute_ID = ?"
set cmd = getTextCommand(objConn, strSQL)
set report005 = cmd.Execute(,array(request.QueryString("id")))

if not report005.eof then
%>

Data her: <%=report005("Rule_ID")%>

<%
else
%>

Der var ingen data

<%
end if
report005.Close
objConn.Close
%>

Bemærk at parametrene overføres i et array og i den rækkefølge de forekommer i SQL-strengen. ADO finder selv i det fleste tilfælde ud af typerne på parametrene, så du skal bare sørge for at sende dem ind i den rigtige rækkefølge.

Denne metode er dog ikke anvendelig, hvis du arbejder med stored procedures der returnerer værdier i output-parametre, men rigtig ofte har man også blot brug for at sende input-parametre til forespørgsler mod databasen.

Metoden skulle også fungere for UPDATE, INSERT og DELETE-kommandoer, så det er rigtig anvendeligt.

Skal du arbejde med stored procedures vil jeg i øvrigt anbefale dig at anvende en lidt anden opsætning af command-objektet, helt konkret at du anvender adCmdStoredProc i stedet for adCmdText i CommandType. Du kan rende ind i at databasesystemet gerne vil have parametrenes navne oplyst eksplicit og i så fald skal du over i noget á la det jeg nævner i min artikel.

HUSK AT TESTE MEGET! ADO kan til tider godt være lidt spøjs... :D
Avatar billede softspot Forsker
24. marts 2010 - 12:04 #12
I virkeligheden burde man nok benytte set for at tildele connection-objektet til command-objeketet i førnævnte funktion, ellers vil VBScript nok benytte strengudgaven af connection-string fra connectionobjektet og tildele activeconnection i commandobjektet og dermed oprette en ny connection (vil jeg tro). Så derfor denne udgave:


function getTextCommand(conn, sql)
  dim cmd
  set cmd = Server.CreateObject("ADODB.Command")
  cmd.CommandText = sql
  cmd.CommandType = adCmdText
  set cmd.ActiveConnection = conn
  set getTextCommand = cmd
end function
Avatar billede softspot Forsker
26. marts 2010 - 12:29 #13
Hvad så - skred du i svinget? :-)
Avatar billede svinget Praktikant
26. marts 2010 - 13:43 #14
Næ næ - jeg har bare ikke fået testet parameter funktionaliteten endnu :)

Det andet virker, så dem der er interesseret i points poster et svar. Jeg har jo brugt lidt fra de fleste.

Tak for hjælpen :)
Avatar billede softspot Forsker
26. marts 2010 - 13:49 #15
Velbekomme :-)
Avatar billede Ny bruger Nybegynder

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.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester