Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: Visual Basic + Access tietokantahaku SQL-käskyillä (VB.NET)

Sivun loppuun

VisuBasu [08.05.2009 13:13:23]

#

Elikkäs elämäni ensimmäistä kertaa olen tekemässä yhtään mitään millään ohjelmointikielellä joten apuja tarvittaisiin ihan yksinkertaisissakin asioissa. :)

Olen tekemässä harjoitustehtävää jossa pitäisi onnistua asiakastietojen haku, muokkaus, poisto yms. Accessin tietokannasta SQL-käskyillä. Käytössä on Visual Basic 2008 Express Edition. Tietojen muokkaus ja poisto toimii jo, mutta hakua toimii vaillinaisesti, nimittäin se toimii vain yhdellä hakutekijällä. Olen aloittanut koodin seuraavasti:

kasky.Connection = yhteyteni
kasky.CommandText = "SELECT * from astiedot WHERE Hetu = '" & TextBox1.Text & "'"

Try

yhteyteni.Open()
lukija = kasky.ExecuteReader
lukija.Read()

'tulostetaan tiedot niille varattuihin kenttiin

Label27.Text = lukija.Item("asnro")
TextBox7.Text = lukija.Item("Hetu")

jne., koodi loppuu näin:

Catch
MsgBox("Asiakastietoja ei löytynyt!", MsgBoxStyle.Information, "Ilmoitus")
yhteyteni.Close()
End Try
End Sub

Tämä siis toimii ok ja hakee tiedot. Mutta ongelma on siinä, että miten lisään tuonne SQL-käskyyn useampia hakutekijöitä? Eli jos haluan mahdollistaa hetulla hakemisen lisäksi asiakasnumerolla hakemisen? Kokeilin sitä mm. näin:

kasky.CommandText = "SELECT * from astiedot WHERE Hetu = '" & TextBox1.Text & "'" Or "Asnro = " & Val(TextBox2.Text)

mutta näin tehtynä ohjelma kaatuu aina. Olen kokeillut lukuisia muitakin variaatioita tuosta käskystä joita en enää edes muista mutta mikään ei tunnu toimivan. Tällöin myös hetulla tehtävä haku lakkaa toimimasta. Haluaisin saada haun toimimaan niin, että haku voidaan tehdä käyttäjän valinnan mukaan joko hetulla, asnrolla tai etu- ja sukunimellä. Mitenhän tuo tulisi toteuttaa että se oikeasti toimisi? Ohjelmassa minulla siis TextBox1.Text kohtaan syötetään hakutekijäksi hetu, TextBox2.Text asnro ja TextBox3.Text kohtaan etunimi ja TextBox4.Text on varattu sukunimi hakutekijälle. Tietokannassa asnro on Laskuri-tyyppiä, muut Teksti-tyyppiä koska hetussakin on väliviiva.

Mod. lisäsi kooditagit

Grez [08.05.2009 13:40:16]

#

Hirveän vaikeaa lukea noita ilman kooditageja.

En nyt ala sen enempää kommentoimaan Accessin käytöstä, mutta seuraavan

VisuBasu kirjoitti:

kasky.CommandText = "SELECT * from astiedot WHERE Hetu = '" & TextBox1.Text & "'" Or "Asnro = " & Val(TextBox2.Text)

pitäisi olla:

kasky.CommandText = "SELECT * from astiedot WHERE Hetu = '" & TextBox1.Text & "' Or Asnro = " & Val(TextBox2.Text)

Siis OR pitäisi olla siinä kyselylauseessa, ei sen ulkopuolella. Lisäksi laittaisin Val tilalle CInt, koska Val voi antaa myös liukuluvun ja jos sinulla on esim. suomalainen locale käytössä, niin siihen tulee pilkku joka tuottaa virheellisen SQL-kyselyn. Lisäksi tekstit olisi hyvä escapeta, tuossahan tuo kosahtaa jos hetu:un laittaa heittomerkin ja jos on ilkeämpi käyttäjä niin voisi tehdä pahempaakin.

VisuBasu [08.05.2009 14:04:16]

#

Kiitos vastauksestasi. Kokeilin tuota ehdottamaasi, ja sen verran parannusta tuli että vaikka siellä on nyt kaksi hakutekijää, niin hetulla haku toimii edelleen. Asnrolla haku ei siltikään toimi edelleenkään vaan heittää ilmoituksen "Asiakastietoja ei löytynyt", eli ei tunnista tuota toista hakutekijää tuolta koodista vaan hyppää suoraan Catch-kohtaan. Koodi on nyt siis kirjaintarkasti tässä muodossa:

kasky.CommandText = "SELECT * from astiedot WHERE Hetu = '" & TextBox1.Text & "' Or Asnro = " & Val(TextBox2.Text). Kuten mainitsin, olen todella aloittelija näissä hommissa, mutta minulla pisti nyt tässä korjatussa koodissa silmään se, että tuo OR-muuttuja on nyt tuolla VB:ssä oranssilla tekstillä kaiken muun koodin seassa, kun käsitykseni mukaan jotta nämä (OR, AND jne) toimisivat oikein, täytyisi sen olla merkattuna sinisellä tekstillä. Voin toki olla väärässäkin. :) Ja tuota CInt käskyä en myöskään saanut toimimaan...

Grez [08.05.2009 14:22:38]

#

No textbox2.text on sitten todennäköisesti jotain muuta kuin luku, jos kerran cint ei toimi.

Ja se Or on tarkoitus antaa sille tietokannalle SQL-kyselyssä, ei suorittaa VB.Netin puolella (josta johtuen tässä tapauksessa sen ei pidä olla sinisellä)

Kokeilepa laittaa vaikka

MsgBox("SELECT * from astiedot WHERE Hetu = '" & TextBox1.Text & "' Or Asnro = " & Val(TextBox2.Text))

ja katso näyttääkö se järkevältä.

Ja debuggaus voisi sujua helpommin jos katsoisit minkä exceptionin se heittää.

Tyyliin:

  Catch (e as Exception)
    Debug.Print(e.Message)
    MsgBox("Asiakastietoja ei löytynyt!", MsgBoxStyle.Information, "Ilmoitus")
    yhteyteni.Close()
  End Try
End Sub

VisuBasu [08.05.2009 15:23:02]

#

No niin, jotain pientä vikaa siellä kuitenkin oli, sillä nyt toimii kumpikin hakutekijä. Voisin vaikka vannoa tarkastaneeni tuon lukuisia kertoja ennen toista tänne postausta mutta näköjään silti jäänyt jotain siis huomaamatta... Iso kiitos siis jo tässä vaiheessa! Mutta ei niin hyvää ettei jotain huonoakin. Tuon myötä ilmeni uusi ongelma; haut siis onnistuu, mutta jos syötän hakutekijäksi vaikkapa asiakasnron jota tietokannassa ei ole, saan ilmoituksen ettei asiakastietoja löytynyt, tähän asti kaikki kuten pitääkin. Mutta, jos haen tämän ilmoituksen jälkeen tietoja sellaisella hakutekijällä joka oikeasti on tietokannassa, saan edelleen ilmoituksen ettei tietoja löytynyt. Sitten kun ohjelman sulkee, avaa uudelleen ja syöttää suoraan oikean hakutekijän toimii haku taas. Yritin saada tuota herjaa talteen ohjeesi mukaan (e as Exception Debug.Print(e.Message)jne)) mutta eipä tuo mitään tietoja minulle herjannut tai ilmoittanut. :/ Ongelma on nyt siis se, että epäonnistuneen haun jälkeen ei jotenkin osaakaan palata tekemään uutta hakua "puhtaalta pöydältä"?

Isot kiitokset sinulle jo tässä vaiheessa!

Grez [08.05.2009 15:43:32]

#

Tuolla debug.printillä näytettävät tekstit tulee Output-ikkunaan/lehdelle Visual Studiossa. Nyt kyllä helpottaisi vastaamista, kun tietäisi mitä sinne tulee.

Ja olin näköjään laittanut tuolla aiemmin tuon "e As Exception" vahingossa sulkuihin, vaikka ei pitäisi. Eli sulut pois.

VisuBasu [08.05.2009 16:04:29]

#

Heh, menee vaikeaksi. :) Nyt meinaan ei toimi sitten tuo debug, eli iskin sen tuonne nyt kirjaintarkasti näin:

Catch e As Exception
Debug.Print(e.Message)
MsgBox("Asiakastietoja ei löytynyt!", MsgBoxStyle.Information, "Ilmoitus")
yhteyteni.Close()

ja VB herjaa tuosta ensimmäisestä yksittäisestä e-kirjaimesta tuolla Catch-sanan perässä, ei hyväksy/tunnista sitä ja tuo Output-välilehti ilmoittaa nyt vain ": error BC30616: Variable 'e' hides a variable in an enclosing block.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped"

Mod. lisäsi kooditagit

Grez [08.05.2009 16:22:45]

#

No sinulla ilmeisesti on jo käytössä muuttuja nimeltä e. Anna sille jokin muu nimi, vaikka Catch ex as Exception ja sitten vastaavasti Debug.Print(ex.Message)

Tai sitten laita koko koodi jonnekin näkyville.

VisuBasu [08.05.2009 18:00:38]

#

Grez kirjoitti:

No sinulla ilmeisesti on jo käytössä muuttuja nimeltä e. Anna sille jokin muu nimi, vaikka Catch ex as Exception ja sitten vastaavasti Debug.Print(ex.Message)

Tai sitten laita koko koodi jonnekin näkyville.

Nyt tuo debuggaus onnistui mutta eipä sieltä mitään virheitä tullut, eli blankkoa Output sivua näyttää.

Tässäpä tuo koodi:

Imports System.Data.SqlClient
Public Class Form2
    Dim yhteys = "Provider= Microsoft.Jet.OLEDB.4.0;Data Source = xxxx xxxx.mdb
    Dim yhteyteni As New OleDb.OleDbConnection(yhteys)
    Dim lukija As OleDb.OleDbDataReader
    Dim kasky As New System.Data.OleDb.OleDbCommand

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

kasky.Connection = yhteyteni
kasky.CommandText = "SELECT * from Astiedot WHERE Hetu = '" & TextBox1.Text & "' Or Yritys = '" & TextBox5.Text & "' Or Etunimi = '" & TextBox3.Text & "' And Sukunimi = '" & TextBox4.Text & "' Or Asnro = " & Val(TextBox2.Text)

        Try

            yhteyteni.Open()
            lukija = kasky.ExecuteReader
            lukija.Read()

            'asiakastiedot
            Label27.Text = lukija.Item("Asnro")
            TextBox7.Text = lukija.Item("Hetu")
            TextBox8.Text = lukija.Item("Etunimi")
            TextBox9.Text = lukija.Item("Sukunimi")
            TextBox10.Text = lukija.Item("Yritys")
            TextBox11.Text = lukija.Item("Postiosoite")
            TextBox12.Text = lukija.Item("Postinumero")
            TextBox13.Text = lukija.Item("Postitoimipaikka")
            TextBox14.Text = lukija.Item("Puhelinnumero")
            TextBox66.Text = lukija.Item("Sähköposti")

            yhteyteni.Close()

        Catch
        MsgBox("Asiakastietoja ei löytynyt!", MsgBoxStyle.Information, "Ilmoitus")

    End Try
    End Sub

Eli; nyt tuo yhteyteni.close on tuolla ennen Catchia, tällöin haku toimii niin pitkään kun syötän kannassa olevia tietoja, jos syötän yhden väärän tiedon saan ilmoituksen että tietoja ei löydy, mutta uusi haku olemassaolevalla tiedolla palauttaa silti tiedon ettei tietoja löydy. Toimii taas kun ohjelman sammuttaa ja käynnistää uudelleen.

Jos tuon yhteyteni.closen siirtää Catchin jälkeen menee homma niin, että yksi haku onnistuu, sen jälkeen ei onnistu mikään haku edes oikeilla tiedoilla.

Sam76 [08.05.2009 21:49:26]

#

Kannattaisiko tuo yhteys avata aina formin latauksen yhteydessä ja antaa olla auki niin kauan kuin ohjelmakin on käynnissä? Sulkisi sen samaan aikaan ohjelman kanssa. Ei tartteis kikkailla sen kanssa sitten sen enempää.

Grez [08.05.2009 22:42:27]

#

Tuota Sam76:n ehdotusta kannattaa myös harkita. Jos yhteyttä ja muita availlaan vasta tuon Button1_Click tapahtuman sisällä, niin ehkä ne kannattaisi myös määrittää siellä.

Ongelma on kuitenkin se, että käytät tuota try catchia mielestäni hieman väärin. Jos tietokannasta ei löydy mitään, niin lukija.Read() palauttaa False. Et kuitenkaan tarkista tätä mitenkään, vaan yrität lukea lukijasta, löytyi jotain tai ei, jolloin Label1.Text = lukija.Item("Asnro") aiheuttaa poikkeutuksen.

Minusta on myöskin hassua importata System.Data.SqlClient vaikka sitä ei koskaan käytetä.

Tekisin tuon ehkä pikemminkin näin:

Public Class Form2
    Const yhteys As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=I:\o\putka\VisuBasu\as.mdb"

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim yhteyteni As New OleDb.OleDbConnection(yhteys)
        Try
            yhteyteni.Open()
        Catch ex As Exception
            MsgBox("Yhteyden avaaminen epäonnistui" & vbCrLf & vbCrLf & "Poikkeus: " & ex.Message)
            Return
        End Try

        Suoritahaku(yhteyteni)

        yhteyteni.Close()

    End Sub
    Private Sub Suoritahaku(ByVal yhteyteni As OleDb.OleDbConnection)
        Dim lukija As OleDb.OleDbDataReader
        Dim kasky As New System.Data.OleDb.OleDbCommand

        kasky.Connection = yhteyteni
        kasky.CommandText = "SELECT * from Astiedot WHERE Hetu = '" & TextBox1.Text & "' " & _
                        "Or Yritys = '" & TextBox5.Text & "' Or (Etunimi = '" & TextBox3.Text & "' " & _
                        "And Sukunimi = '" & TextBox4.Text & "') Or Asnro = " & Val(TextBox2.Text)

        Try
            lukija = kasky.ExecuteReader()
        Catch ex As Exception
            MsgBox("Kyselyssä oli jotain vikaa, tai Executereader epäonnistui muuten vaan." & _
                   vbCrLf & vbCrLf & "Poikkeus: " & ex.Message)
            Return
        End Try

        If lukija.Read() Then
            'asiakastiedot
            Label1.Text = lukija.Item("Asnro")
            TextBox7.Text = lukija.Item("Hetu")
            TextBox8.Text = lukija.Item("Etunimi")
            TextBox9.Text = lukija.Item("Sukunimi")
            TextBox10.Text = lukija.Item("Yritys")
            TextBox11.Text = lukija.Item("Postiosoite")
            TextBox12.Text = lukija.Item("Postinumero")
            TextBox13.Text = lukija.Item("Postitoimipaikka")
            TextBox14.Text = lukija.Item("Puhelinnumero")
            TextBox15.Text = lukija.Item("Sähköposti")
        Else
            MsgBox("Asiakastietoja ei löytynyt!", MsgBoxStyle.Information, "Ilmoitus")
        End If
        lukija.Close()

    End Sub
End Class

VisuBasu [08.05.2009 23:35:13]

#

Tuosta esimerkkikoodistasi sai paljon hyviä vinkkejä, kiitos niistä! Kokeilin tuota tuollaisenaan ja toimii muuten mainiosti, mutta jos syötän hakutekijäksi sellaisen tekijän jota ei oikeasti tietokannassa ole, tulostuu näytölle silti tietokannassa viimeisenä olevan asiakkaan tiedot eikä ilmoitusta siitä, ettei asiakastietoja löydy, tule koskaan.

Grez [08.05.2009 23:40:14]

#

Väittäisin, että se toimii oikein. Ainakin itselläni tuli "asiakastietoja ei löytynyt"

Ehkäpä sinulla jokin "haku"ehdoista vastaa sitä viimeistä asiakastasi. Esimerkiksi jos jätit jonkin kentän tyhjäksi, ja viimeisen asiakkaan ko. tieto on myös tyhjä?

VisuBasu [09.05.2009 00:23:29]

#

Joo, itsehän taas tosiaan täällä sössin, eli toimii todella hienosti :) Todella isot kiitokset sinulle, hienoa että joku jaksaa ja viitsii auttaa kun aloittelevat tumpelot yrittää jotain saada aikaan... :)


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta