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
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.
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...
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
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!
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.
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
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.
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.
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ää.
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
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.
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ä?
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... :)
Aihe on jo aika vanha, joten et voi enää vastata siihen.