Ricerca stringa parziale

sabato 03 gennaio 2009 - 22.54

cosmopsis Profilo | Junior Member

Sono riuscito a implementare il codice per la ricerca di una stringa in un db access.
Il codice è il seguente:
Public Sub ricercaCodice()
'...connessione db

Dim crit = "SELECT * FROM Nomi;"

Dim cmd As OleDbCommand
cmd = New OleDbCommand(crit, cn) 'cn rappresenta la connessione


Dim objOLEDBAdapter As OleDbDataAdapter
objOLEDBAdapter = New OleDbDataAdapter()
Dim dtTable As DataTable
dtTable = New DataTable()

Dim tabella As New DataTable("Nomi")
Dim dtView As New DataView(tabella)
Try
objOLEDBAdapter.SelectCommand = cmd
objOLEDBAdapter.Fill(tabella)

dtView.Sort = "Cognome"
Dim intindex As Integer = dtView.Find(txtNome.Text)
If intindex = -1 Then
MsgBox("non ci sono occorrenze")
Else
txtKey.Text = dtView(intindex)("key")
txtCognome.Text = dtView(intindex)("Cognome")
'eccetera...
End If
Catch ex As Exception
MsgBox(ex.Message)
End Try

'-------------------------------
'...disconnessione db
End Sub

...e funziona solo se do l'esatta stringa. Come faccio per quelle parziali?
ciao.

Jeremy Profilo | Guru

>Sono riuscito a implementare il codice per la ricerca di una
>stringa in un db access.
>Il codice è il seguente:
>Public Sub ricercaCodice()
> '...connessione db
>
> Dim crit = "SELECT * FROM Nomi;"
>
> Dim cmd As OleDbCommand
>cmd = New OleDbCommand(crit, cn) 'cn rappresenta la connessione
>
>
> Dim objOLEDBAdapter As OleDbDataAdapter
> objOLEDBAdapter = New OleDbDataAdapter()
> Dim dtTable As DataTable
> dtTable = New DataTable()
>
> Dim tabella As New DataTable("Nomi")
> Dim dtView As New DataView(tabella)
> Try
> objOLEDBAdapter.SelectCommand = cmd
> objOLEDBAdapter.Fill(tabella)
>
> dtView.Sort = "Cognome"
>Dim intindex As Integer = dtView.Find(txtNome.Text)
> If intindex = -1 Then
> MsgBox("non ci sono occorrenze")
> Else
> txtKey.Text = dtView(intindex)("key")
>txtCognome.Text = dtView(intindex)("Cognome")
> 'eccetera...
> End If
> Catch ex As Exception
> MsgBox(ex.Message)
> End Try
>
> '-------------------------------
> '...disconnessione db
> End Sub
>
>...e funziona solo se do l'esatta stringa. Come faccio per quelle
>parziali?
>ciao.

credo tu non debba usare il metodo find ma estrarre i valori dai campi e usare le regular expression!!!

> If intindex = -1 Then
> MsgBox("non ci sono occorrenze")
> Else
> txtKey.Text = dtView(intindex)("key")
>txtCognome.Text = dtView(intindex)("Cognome")
> 'eccetera...
> End If

Questa parte di codice, comunque, ti restituirebbe solo la prima occorenza, quindi dovresti, a mio avviso, popolare un datagridview con i risultati.

alexmed Profilo | Guru

Ciao
Puoi filtrare i dati direttamente qui

Dim crit = "SELECT * FROM Nomi;"

Aggiungendo la clausola WHERE e l'operatore LIKE

ad esempio

Dim crit = "SELECT * FROM Nomi WHERE Cognome LIKE Rossi;"

ti restituisce tutti i record in cui nella colonna Cognome compare Rossi
se aggiungi il carattere jolly che in SQL è il "%" e non il "*"

Dim crit = "SELECT * FROM Nomi WHERE Cognome LIKE Rossi%;"

Ti restituisce tutti i Rossi ma anche i Rossignol

Infine se aggingi anche prima il carattere jolli
Dim crit = "SELECT * FROM Nomi WHERE Cognome LIKE %Rossi%;"

Ti restituisce anche i Lanerossi ed i Lanerossignol

Ciao

alx_81 Profilo | Guru

@alexmed
>Puoi filtrare i dati direttamente qui
>Aggiungendo la clausola WHERE e l'operatore LIKE
Vero, ma attenzione a ciò che dici dopo:

>ad esempio
>Dim crit = "SELECT * FROM Nomi WHERE Cognome LIKE Rossi;"
>ti restituisce tutti i record in cui nella colonna Cognome compare Rossi
Purtroppo scritta così non restituisce nulla. La stringa Rossi va tra apici singole

>se aggiungi il carattere jolly che in SQL è il "%" e non il "*"
Si sta parlando di access. Se non ricordo male il wildcard di default è proprio "*" e devi cambiarlo da impostazioni avanzate (dando la compatibilità con la sintassi SQL Server ANSI-92). Non so il 2007 come si comporta, potrebbero in effetti funzionare entrambi, ma la butto lì, non si sa mai

>Infine se aggingi anche prima il carattere jolli
>Dim crit = "SELECT * FROM Nomi WHERE Cognome LIKE %Rossi%;"
Anche qui, come nell'esempio precedente servono le apici singole ('%Rossi%').

@cosmopsis
Fai attenzione che se la tabella ha veramente tanti record una ricerca di dell'utlimo tipo non è performante, meglio tenere il wildcard a destra per quanto possibile..
La soluzione che ti propone alexmed è valida come approccio e ti consiglio di seguire quanto indicato da lui, a meno che tu non abbia un caso così particolare da dover caricare comunque tutti i record. In ogni caso, se la tabella è di notevoli dimensioni, pensa anche ad alcuni indici (o per il LIKE o per lo scan).

Ciao!
--

Alessandro Alpi | SQL Server MVP

http://www.alessandroalpi.net
http://blogs.dotnethell.it/suxstellino
http://mvp.support.microsoft.com/profile/Alessandro.Alpi
http://italy.mvps.org

alexmed Profilo | Guru

Ciao

>Purtroppo scritta così non restituisce nulla. La stringa Rossi va tra apici singole
La fretta di scrivere
In teoria per quanto riguarda la prima, ovvero ricercare un'occorrenza esatta non sarebbe meglio scrivere:
WHERE nome_colonna = 'Rossi' ?

>Si sta parlando di access. Se non ricordo male il wildcard di default è proprio "*"
Ho fatto delle prove su un db Access, credo 2003 (mi è stato mandato via email), e funziona solo con il "%"
Ma bene a sapersi per il futuro.

CIao

Jeremy Profilo | Guru

Rimango dell'idea che qualsiasi manipolazione sulle stringhe vada fatta con le regular expression.

alx_81 Profilo | Guru

@alexmed

>In teoria per quanto riguarda la prima, ovvero ricercare un'occorrenza esatta non sarebbe meglio scrivere:
>WHERE nome_colonna = 'Rossi'?
Sicuramente, e magari con un bell'indice per fare una seek su nome_colonna (ed eventualmente sui campi della select per fare la copertura)

>Ma bene a sapersi per il futuro.
Non ricordo di preciso.. so che un problema c'era, ma forse solo nelle versioni un po' più vecchiotte. Dall'help in linea di 2007 l'esempio è con * ma sembra che si possa usare anche il %.

@jeremy
> Rimango dell'idea che qualsiasi manipolazione sulle stringhe vada fatta con le regular expression.
Sinceramente non sono d'accordo. Ma non sono uno di quelli che le odia per partito preso.
Sono molto potenti, non c'è dubbio, ed in certi casi le trovo anche essenziali. Infatti ho avuto a che fare con casi reali, non direttamente gestiti da me, ma da un collega che le ha usate davvero (Mike, il suo blog sulle regular che spero seguirà quest'anno con più fervore http://blogs.dotnethell.it/regulator), e ho visto che per quello che doveva fare, ovvero un'applicazione multithread con frequenze di richiesta molto elevate che parsava interi documenti html, erano molto potenti e prestanti.
Ritengo invece, che se puoi sfruttare gli indici del tuo database è meglio usarli direttamente sulla ricerca, piuttosto che scaricarsi tutto in memoria e poi procedere di RegExp per filtrare o comunque lavorare su DataTable o DataSet o Entità che si voglia. Una buona query, su tabelle indicizzate a dovere, offre prestazioni veramente elevate, poco overhead di rete, e un basso utilizzo di CPU.
Ma alla fine, si tratta sempre di una scelta. Potrebbe essere che in alcuni casi convenga usare il motore di RegExp, ma non arriverei a dire di usare SEMPRE una soluzione piuttosto che l'altra.
--

Alessandro Alpi | SQL Server MVP

http://www.alessandroalpi.net
http://blogs.dotnethell.it/suxstellino
http://mvp.support.microsoft.com/profile/Alessandro.Alpi
http://italy.mvps.org

Jeremy Profilo | Guru

> ma non arriverei a dire di usare SEMPRE una soluzione piuttosto che
>l'altra.

Hai ragione, a questo punto però, consiglierei Cosmopsis di parametrizzare le sue Query, in modo da non incorrere in problemi di tipo di campo e valore.
Dim ds as New Dataset
Dim objCmd As New OleDb.OleDbCommand
Dim par(0) As OleDb.OleDbParameter
objCmd.Connection = Conn
objCmd.CommandText = "SELECT * FROM Nomi WHERE Cognome LIKE @Cognome"
par(0) = New OleDb.OleDbParameter With { _
.ParameterName = "@Cognome", _
.DbType = DbType.String, _
.Value = txtNome.Text}
objCmd.Parameters.Add(par(0))
Dim da As New Data.OleDb.OleDbDataAdapter(objCmd)
da.Fill(ds, "Occorrenze")
da.Dispose()
objCmd.Parameters.Clear()

alx_81 Profilo | Guru

>Hai ragione, a questo punto però, consiglierei Cosmopsis di parametrizzare
>le sue Query, in modo da non incorrere in problemi di tipo di
>campo e valore.
eheheh.. sì, bravo, ti quoto ancora come nell'altro post. E' importantissimo, anche per non incappare in attacchi di tipo SQL-Injection.
Aggiungo anche qui il link all'articolo: http://www.dotnethell.it/articles/SQL-Injection-Tutorial-Security.aspx

Ciao!
--

Alessandro Alpi | SQL Server MVP

http://www.alessandroalpi.net
http://blogs.dotnethell.it/suxstellino
http://mvp.support.microsoft.com/profile/Alessandro.Alpi
http://italy.mvps.org

alexmed Profilo | Guru

Perfetto!
Ma adesso abbiamo fatto una panoramica completa, ma per non perdere lo scopo del Thread bisogna dirgli dove andare a mettere il jolly (%)
E per togliermi ogni dibbio ve lo chiedo io

.Value = txtNome.Text + "%"}

è la posizione giusta?

Alessandro

Jeremy Profilo | Guru

Il carattere jolly vale solo se il parametro è di tipo String....per le date e i campi Interi si potrebbe usare l'operatore BETWEEN(per esempio).
A questo punto mi creerei una funzione che, in base alla quantità di textbox valorizzate, costruisce la SqlString opportunamente al tipo dei dati, che posso ottenere direttamente dal dataset precedentemente popolato con almeno un record, e, successivamente, manipolarla......ahimè.....con l'aiuto delle Regex per ottenere una stringa parametrizzata, poi .....costruire i parametri da fornire al command.


Comunque, a parte l'uso di + e non di & per concatenazione di stringhe, la posizione potrebbe essere quella corretta....dico potrebbe perchè dipende da cosa vuoi cercare!!

Teech Profilo | Expert

Personalmente preferisco operare direttamente sui valori dei parametri e crearmi delle funzioni mirate alla gestione del parametro stesso:
Per un codice dove uso i parametri simile al seguente:
Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra
La funzione può essere implementata come segue o comunque maggiormente elaborata:
Protected Function LikeString(ByVal s As String) As String 'Aggiunge "%" per le stringhe utilizzati nei parametri con operatori Like s = IIf(s.StartsWith("%"), s, String.Concat("%", s)) s = IIf(s.EndsWith("%"), s, String.Concat(s, "%")) Return s End Function
Preferisco fare così semplicemente perchè spesso uso dei miei Adapter che gestiscono le tabelle e quindi sono fortemente tipizzati, in altri casi, questo approccio potrebbe essere controproducente (in ambiti poco tipizzati per esempio).
--------------
Maurizio Brini
--------------
Nessuna impresa è mai stata compiuta da un uomo ragionevole

Jeremy Profilo | Guru

>Personalmente preferisco operare direttamente sui valori dei
>parametri e crearmi delle funzioni mirate alla gestione del parametro
>stesso:
>Per un codice dove uso i parametri simile al seguente:
>Dim sSQL As String = "SELECT * FROM Tabella WHERE Campo Like

Ok...però tu qui ha già una SqlString fatta e quindi sai a priori quanti parametri hai bisogno e di che tipo..io, invece pensavo di creare una SqlString in base alla quantità di criteri(textbox valorizzate) che l'utente decide, ottenerne il tipo e, appunto, la quantità di parametri necessari.
Ovviamente anche io, per questo, ho una classe fortemente tipizzata contente tutte le proprietà necessarie per costruire 'tutto' il command(parametri compresi).
tale classe poi la passo ad un WebMethod che si preoccupa di prelevare(dal mio oggetto) tutte le informazioni necessarie per la costruzione del command e per la restituzione di un Dataset popolato a dovere.


cosmopsis Profilo | Junior Member

Grazie a tutti per le risposte e scusate il ritardo!
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2024
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5