+ Rispondi
Pagina 1 di 2 1 2 UltimaUltima
Risultati da 1 a 10 di 16

Discussione: [SQL] condizione LIKE con jolly su dato in db e non su parametro

  1. #1
    Neofita della community
    reputazione complessiva: 1 1

    Messaggi
    55

    [SQL] condizione LIKE con jolly su dato in db e non su parametro

    Ciao a tutti ed intanto un po' di auguri sparsi in giro :-)

    oggi ho evidentemente il cervello in ferie per cui non mi resta che chiedere una cosa bizzarra che mi si è presentata e non ho ancora risolto. Il DB di riferimento è da MSDE 1 a SQLServer 2005, passando per MSDE2000, SQLServer 7 e SQLServer 2000.

    Ho una tabella che contiene dei dati come qui in esempio

    tabCATEGORIE:
    NOME_CAT CATEGORIA (più altre colonne qui non importanti da riportare)
    cat 1 AB1
    cat 2 AB113A
    cat 3 CCD12
    cat 4 G01
    etc.

    dove la 'categoria' è in senso lato, in quanto AB1 'contiene' AB113A per esmepio.
    Quel che mi giova fare è una select su questa tabella (fonte: DA TERZI) quando viene interrogato un articolo avente un dato codice categoria (es. G01AA1) e tirare fuori le informazioni (tutte, non per forza 1 riga) relative al match anche parziale della categoria del prodotto sui dati nel campo CATEGORIA di questa tabella.

    Brutalmente parlando farei una
    SELECT * FROM tabCategorie WHERE "<codice_categoria>" LIKE CATEGORIA+'%'
    ipotizzando che fosse possibile invertire la più normale e consona
    SELECT * FROM tabCategorie WHERE CATEGORIA LIKE "<codice_categoria>%"

    Non riesco a farmi venire una idea, senza stravolgere i dati non potendo ristrutturare la gestione delle categorie dei prodotti e dei dati relativi a più categorie in contemporanea (es. la riga in tabCategoria con G01 si riferisce a TUTTE le categorie G01%...)

    Spero in un regalo natalizio da parte di qualcuno che si è già imbattuto in qualcosa di questo genere.

    Grazie ed ancora auguri a tutti!
    Byte byte by Vinx
    www.cipcarbone.it

  2. #2
    Very Important Person L'avatar di sspintux
    reputazione complessiva: 28 28

    Messaggi
    942
    Blogs
    5
    Citazione Originariamente Scritto da vinxonline Visualizza Messaggio
    Ciao a tutti ed intanto un po' di auguri sparsi in giro :-)
    Ciao ed auguri anche a te,

    sarà l'effetto dei brindisi ma non mi è molto chiaro il problema;

    ...anzi, ad occhio e croce sembrerebbe impossibile da risolvere, ma tentar non nuoce

    Citazione Originariamente Scritto da vinxonline Visualizza Messaggio
    Ho una tabella che contiene dei dati come qui in esempio

    tabCATEGORIE:
    NOME_CAT CATEGORIA (più altre colonne qui non importanti da riportare)
    cat 1 AB1
    cat 2 AB113A
    cat 3 CCD12
    cat 4 G01
    etc.

    dove la 'categoria' è in senso lato, in quanto AB1 'contiene' AB113A per esemepio.
    esiste qualche tipo di relazione tra le 'categorie di base' (AB1) e quelle 'derivate' (AB113A) ?

    .....dagli esempi che hai fatto sembrerebbe che la categoria di base
    sia sempre identificata dai primi 3 caratteri di una categoria derivata;

    Puoi fare un esempio con dati significativi che mettano in evidenza le difficoltà da superare ed il risultato desiderato.
    Ultima modifica di sspintux; 26-12-2008 alle 01:49
    Ciao sspintux
    ------------------------------------------------------------
    Volevamo cambiare il mondo...peccato che abbiamo perso lo scontrino

  3. #3
    Neofita della community
    reputazione complessiva: 1 1

    Messaggi
    55
    Ciao,

    allora, assodato che ho risolto con un workaround non essendo riuscito a pensare ad altra soluzione, do qualche dettaglio in più e poi spiego il mio workaround.

    La categoria AB1 rispetto a AB1C123 o AB1A2C etc. diciamo che le "contiene", mi spiego meglio con un esempio: AB1 indica un MACRO GRUPPO le cui informazioni sono valide per se stesso e qualuque GRUPPO DERIVATO (es. AB1xxxx), è come se parlassimo per AB1 di MAMMIFERI e AB1C1231 per l'UOMO specificatamente e AB1C12 per i mammiferi carnivori tra cui l'uomo. A me gioverebbe poter appiccicare una etichetta al macro gruppo AB1 che sia valida per tutti i gruppi AB1 e derivati (es. una qualunque caratteristica comune a livello più o meno alto)

    La tabella delle CATEGORIE contiene proprio informazioni di questo tipo:

    Categoria Informazione
    AB1 - hanno sangue caldo
    AB1C1 - sono onnivori (anche e sopratutto a Natale)
    AB1C123 - è l'uomo, ha il cervello più grosso di tutti ma non trova soluzione alla query

    e dato che io interrogo l'oggetto VINCENZO con categoria AB1C123 mi aspetto di trovarvi le info che "ha sangue caldo", è "onnivoro" ed è "uomo che non risolve query" :-)

    Ora, scherzi a parte, questa cosa sembra semanticamente immediata in quanto direi di fare un LIKE tra il dato che ho ed i dati in tabella... ma in tabella ho le RADICI di questa categoria dell'oggetto interrogato, per cui non posso fare il LIKE * che speravo e su cui ancora rifletto...

    Nel mentre pero' ho trovato il workaround grazie all'analisi dei gruppi: la categoria non ha lunghezza infinita (max 8 char) e ho potuto indicizzare esplicitamente quel campo nella tabella, per cui ho escogitato questa query elaborata in automatico ad ogni necessità in due step:

    STEP (1): preparazione della condizione sulla categoria
    sSplittedCAT è una variabile stringa d'appoggio
    sCategoria è la stringa della categoria passata in analisi per l'oggetto da "investigare"
    For i = 1 To Len(sCategoria)
    sSplittedCAT = sSplittedCAT & "'" & Left$(sCategoria, i) & "',"
    Next
    queste iterazioni 'carattere per carattere' della categoria creano una cosa di questo genere
    in sSplittedCAT: 'A','AB','AB1','AB1C','AB1C1','AB1C12','AB1C123',
    da cui ovviamentre strippo via la virgola finale

    STEP(2): creare la query
    ecco la query che a questo punto uso
    sSQL = "SELECT * FROM tabCategoria WHERE Categoria IN (" & sSplittedCAT & ")"
    così facendo la query tira fuori TUTTO quel che riguarda ogni singola parte dell'alberto di categoria, dalle fondamenta alla specifica di massimo dettaglio e raggiungo il mio scopo.

    Anche se il giro sembra pindarico devo essere sincero che mi ha stupito in velocità (tnx SqlServer...) e tutto sommato in semplicità dato che il "gran lavoro" come vedere è un ciclo for e basta. Questa composizione tra l'altro permette elaborazioni integrabili molto facilmente con l'aggiunta di OR o AND per aggiungere "cugini" o viceversa per stringere il cerchio ancor più se dovesse nel futuro arrivare qualche altro dato utile al filtraggio.

    Che ne pensate?
    malsano? :-)
    Byte byte by Vinx
    www.cipcarbone.it

  4. #4
    Collega della community L'avatar di bumm
    reputazione complessiva: 29 29

    Messaggi
    868
    Vediamo se ho capito bene:

    inserndo valore del parametro 'AB113A' vorresti avere seguenti risultati
    AB1
    AB113A
    AB123B
    AB1....
    e.t.c
    Giusto?


    Vediamo come posiamo risolverla:

    1. Lunghezza precisa del "CodiceBase" Conosciuta.
    Nel esempio sono 3 caratteri ('AB1')

    Basta fare select con la funzione SUBSTRING

    Esempio:
    Codice:
    SELECT     ID, NOME_CAT, CATEGORIA
    FROM         tabCATEGORIE
    WHERE     (CATEGORIA LIKE (SUBSTRING(@Categoria,1,3)+N'%'))
    2. Lunghezza del "CodiceBase" Sconosciuta.
    Cioè puo essere 'AB' oppure 'AB11'

    Ho creato una funzione(non e proprio performante, ma non hai molta scelta) che restituisce il "CodiceBase" in base dei dati esistenti nella tabella.

    Codice:
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE FUNCTION dbo.GetCategoriaBase
    (@CatRichiesta nvarchar(50))
    RETURNS  nvarchar(50)
    AS
    BEGIN
    
        DECLARE @CatBase nvarchar(50) --Parametro di ritorno
        DECLARE @ResCount integer -- serve per confrontare risultato della query select
        DECLARE @Flag integer -- va incrementato dopo ogni query SELECT
        SET @flag =0
    -------------------------------------------------
    -- Dobbiamo ripetere il ciclo finche query SELECT
    -- non restituira valore > 0 
    WHILE (@Flag < Len(@CatRichiesta))
        BEGIN
            BEGIN
               --Utilizziamo SUBSTRING per avere il parametro
               --Dopo ogni passaggio, viene aggiunta una lettera
               SET @Rescount = (SELECT COUNT(*) FROM tabCategorie WHERE Categoria = SUBSTRING(@CatRichiesta,1,@FLAG))
            END
        
        IF(@Rescount > 0)
            BEGIN
                --query ha restituito uno o piu records
                --possiamo interrompere il ciclo
                SET @CatBase = SUBSTRING(@CatRichiesta,1,@FLAG)
                BREAK
            END
        ELSE
            BEGIN
                -- query non ha restituito i records
                -- incrementiamo @Flag e continuiamo
                SET @Flag = @Flag + 1
                CONTINUE
            END
         END 
        RETURN @CatBase
    
    
    END
    GO
    Ok, Adesso possiamo creare una Stored Procedure, che restituisce i risultati con Like

    Codice:
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE PROCEDURE GetCategories 
    @Category nvarchar(50)
    AS
    BEGIN
    
        SET NOCOUNT ON;
    
    DECLARE @CatReturned nvarchar(50)
    SET @CatReturned = ([dbo].[GetCategoriaBase](@Category) +  N'%')
    
    SELECT     ID, NOME_CAT, CATEGORIA
    FROM         tabCATEGORIE
    WHERE     (CATEGORIA LIKE @CatReturned)
    
    END
    GO
    Controliamo funzionamento:

    Codice:
    USE [MyDBName]
    GO
    
    DECLARE    @return_value int
    
    EXEC    @return_value = [dbo].[GetCategories]
            @Category = N'G0133A'
    
    SELECT    'Return Value' = @return_value
    
    GO
    Ho avuto:

    5 cat 4 G01
    6 cat 5 G0111A
    7 cat 6 G0133A
    Premi se vuoi commentare l'intervento.

    "HeloWorld.exe" 17 errors, 31 warnings.

  5. #5
    Collega della community L'avatar di bumm
    reputazione complessiva: 29 29

    Messaggi
    868
    STEP (1): preparazione della condizione sulla categoria
    sSplittedCAT è una variabile stringa d'appoggio
    sCategoria è la stringa della categoria passata in analisi per l'oggetto da "investigare"
    For i = 1 To Len(sCategoria)
    sSplittedCAT = sSplittedCAT & "'" & Left$(sCategoria, i) & "',"
    Next
    queste iterazioni 'carattere per carattere' della categoria creano una cosa di questo genere
    in sSplittedCAT: 'A','AB','AB1','AB1C','AB1C1','AB1C12','AB1C123',
    da cui ovviamentre strippo via la virgola finale

    STEP(2): creare la query
    ecco la query che a questo punto uso
    sSQL = "SELECT * FROM tabCategoria WHERE Categoria IN (" & sSplittedCAT & ")"
    così facendo la query tira fuori TUTTO quel che riguarda ogni singola parte dell'alberto di categoria, dalle fondamenta alla specifica di massimo dettaglio e raggiungo il mio scopo.
    ma in questo caso inserendo 'AB1C123', nei risultati non troverai per esempio 'AB1C223' che comunque ha la stessa base 'AB1'.
    Va bene per te?
    Premi se vuoi commentare l'intervento.

    "HeloWorld.exe" 17 errors, 31 warnings.

  6. #6
    Very Important Person L'avatar di Cteniza
    reputazione complessiva: 51 51

    Messaggi
    3,472
    Blogs
    27
    Io proverei anche una cosa del genere:
    testo cancellato, risposta non coerente
    Ultima modifica di Cteniza; 26-12-2008 alle 22:06
    ----------------------------------------------------------
    Se avete delle domande fatele prima al forum
    Se ti è piaciuta una risposta, ovviamente se la risposta è la mia è meglio Commenta L'intervento
    Il mio blog su Masterdrive.it
    Il mio blog su Visual-Basic.it

  7. #7
    Neofita della community
    reputazione complessiva: 1 1

    Messaggi
    55
    CIao Bumm,

    Citazione Originariamente Scritto da bumm Visualizza Messaggio
    ma in questo caso inserendo 'AB1C123', nei risultati non troverai per esempio 'AB1C223' che comunque ha la stessa base 'AB1'.
    Va bene per te?
    mi sono espresso male: è giusto che NON trovo AB1C223 se parto da AB1C123, in quanto quel che giova tirare fuori è la relazione inversa del jolly applicato alle categorie in tabella che mi portino a AB1C123, per cui A* è ok, AB* è ok... AC* NON va bene, come neanche AB1C223 che è diverso da AB1C123, non mi riesco a spiegare meglio se non con un esempio appunto.

    ciao e grazie,
    Byte byte by Vinx
    www.cipcarbone.it

  8. #8
    Neofita della community
    reputazione complessiva: 1 1

    Messaggi
    55
    Ciao Cteniza,

    Citazione Originariamente Scritto da Cteniza Visualizza Messaggio
    Io proverei anche una cosa del genere:
    SELECT * FROM tabCategorie WHERE CATEGORIA BETWEEN '<codice_categoria>' AND '<codice categoria>~' (la tilde è alt-126)
    scusa non ti seguo, se io parto dalla AB1C123 dovrei fare

    SELECT * FROM tabCategorie WHERE Categoria BETWEEN 'AB1C123' AND 'AB1C123~'

    ma non otterrei nulla, ma se prendo da 'A' a 'AB1C123' prendo anche un sacco di cose inopportune (es. AC o A06 che non mi giovano anche se presenti).
    La tilde a cosa servirebbe esattamente?

    Ciao e grazie,
    Byte byte by Vinx
    www.cipcarbone.it

  9. #9
    Very Important Person L'avatar di sspintux
    reputazione complessiva: 28 28

    Messaggi
    942
    Blogs
    5
    Citazione Originariamente Scritto da vinxonline
    ....
    se parto da AB1C123, ....
    A* è ok, AB* è ok... AC* NON va bene, come neanche AB1C223 che è diverso da AB1C123, non mi riesco a spiegare meglio se non con un esempio appunto.
    ...ora mi sembra più chiaro,

    questa è una soluzione che dovrebbe andare bene per tutte le versione di sql server che hai citato (comunque provala su tutte per sicurezza).

    (...se la lunghezza del codice categoria fosse sensibilmente più lunga di 8 c'è una soluzione più elegente alla sfliza di union all)

    Codice:
    --preparazione dati di prova
    use tempdb 
    go
    
    if object_id('T') is not null drop table T
    go
    
    create table T (Cat varchar(8))
    
    insert into T(Cat) Values ('A')
    insert into T(Cat) Values ('AB')
    insert into T(Cat) Values ('AB1')
    insert into T(Cat) Values ('AB1C')
    insert into T(Cat) Values ('AB1CY')
    insert into T(Cat) Values ('AX')
    insert into T(Cat) Values ('AY')
    go
    --fine preparazione dati di prova
    
    -- la categoria da esaminare
    declare @CatIn varchar(8)
    set @CatIn='AB1C'
    
    --la soluzione proposta
    select T.* from T
    Where T.Cat IN
    (
        select Left(q.CatIn,tbCross.N) as CatRad
        from
        (select @CatIn as CatIn) as q
        cross Join
        (
         select 1 as N
         union all
         select 2
         union all
         select 3 
         union all
         select 4
         union all
         select 5 
         union all
         select 6 
         union all
         select 7
         union all
         select 8
        ) as tbCross
        where tbCross.N<=Len(@CatIn)
    )
    Ultima modifica di sspintux; 26-12-2008 alle 23:26 Motivo: ...correzioni varie
    Ciao sspintux
    ------------------------------------------------------------
    Volevamo cambiare il mondo...peccato che abbiamo perso lo scontrino

  10. #10
    Neofita della community
    reputazione complessiva: 1 1

    Messaggi
    55
    Ciao Sspintux,

    risposta molto interessante e che vorrei approfondire, ma credo che a livello di complicatezza ed applicabilità la mia prima soluzione (condizione WHERE Categoria IN ...) sebbene più brutale sia più scalabile e sopratutto automaticamente a prescindere dalla lunghezza del codice della categoria, che non ti nego che potrebbe benissimo essere variabile anche a mia insaputa (entro un range tollerabile comunque).

    Mi proponi l'idea più elegante indipendente dagli union all ?

    Infine sarebbe interessante ragionare sul "costo" degli union all in caso la tabella tabCategoria fosse (come oggi è) di oltre 130mila righe...

    Ciao e grazie
    Byte byte by Vinx
    www.cipcarbone.it

+ Rispondi
Pagina 1 di 2 1 2 UltimaUltima

Tag per Questa Discussione

Permessi di Scrittura

  • Tu non puoi inviare nuove discussioni
  • Tu non puoi inviare risposte
  • Tu non puoi inviare allegati
  • Tu non puoi modificare i tuoi messaggi