Condividi tramite

VBA: codice per impostare cella ad una valore in base a criteri

Anonimo
2017-12-07T14:29:05+00:00

Buongiorno,

devo valorizzare il contenuto di una cella (RISULTATO) in base al contenuto delle informazioni riportate in tre campi distinti della stessa tabella  ed una lista di valori che si trova in un altra tabella in base a dei criteri.

I criteri da utilizzare sono:

Il valore da riportare  varia in base a questi criteri e secondo diverse priorità:

Innanzi tutto se il valore della cella nel "CAMPO13" è "descrizione3_campo13", nella rispettiva riga della colonna AH riporterò come RISULTATO "bloccato".

Solo se non viene soddisfatta questa condizione, verifico il valore del CAMPO14,  se è uguale a "caso1", il RISULTATO da riportare nella riga della colonna AH sarà prioritariamente il contenuto della rispettiva cella del campo12 solo se questo è diverso da vuoto e diverso da uno dei valori presenti nella tabella "valori esclusi", altrimenti dovrà essere riportato come RISULTATO il valore presente nel campo13, sempre nel caso in cui quest'ultimo sia diverso da vuoto e diverso da uno dei valori presenti nella tabella "valori esclusi". Se non è possibile assegnare uno dei valori del campo12 o del campo13, il valore da riportare come RISULTATO sarà "valore assente".

In tutti i casi in cui il valore del CAMPO14 è diverso da "caso1", il RISULTATO da riportare nella riga della colonna AH sarà prioritariamente  il contenuto della rispettiva cella del campo13, in seconda priorità il campo12 se il valore da riportare è vuoto o presente nella solita lista di valori da escludere. A cascata se anche il campo12 è un risultato da escludere (perchè vuoto o compreso nella lista valori da escludere), riporterò "valore assente.

Ho provato a fare questo (ad esclusione della ricerca del valore nella tabella "valori da escludere") con il codice sotto riportato... non so come fare la verifica sulla tabella dei valori da escludere, il file di esempio è qui.

Inoltre questa operazione andrebbe fatta su una lista di oltre 400.000 righe ed ho paura che questa da me abbozzata sia una soluzione snella...

Public Sub m()

    Dim wk As Workbook

    Dim sh1 As Worksheet

    Dim sh2 As Worksheet

    Dim lng As Long

    Dim lUltRiga As Long

    Dim Risultato As String

    Dim valore1 As String

    Dim valore2 As String

    Dim condizione1 As String

    Dim condizione2 As String

    Set WB = ThisWorkbook

    With WB

        Set sh1 = .Worksheets("dati")

    End With

    With sh1

       lUltRiga = Range("A" & Rows.Count).End(xlUp).Row

For lng = 2 To lUltRiga

            condizione1 = Range("M" & lng).Value

            condizione2 = Range("N" & lng).Value

            valore1 = Range("L" & lng).Value

            valore2 = Range("M" & lng).Value

If condizione1 = "descrizione3_campo13" Then

              Risultato = "BLOCCATO"

              Range("AH" & lng).Value = Risultato

 GoTo fine

End If

If condizione2 = "caso1" Then

               Risultato = valore1

                  If Risultato = "" Then

                        Risultato = valore2

                        If Risultato = "" Then

                              Risultato = "valore non valido"

                              Range("AH" & lng).Value = Risultato

                        End If

                   Range("AH" & lng).Value = Risultato

                   End If

              Range("AH" & lng).Value = Risultato

            End If

         If condizione2 <> "caso1" Then

                  Risultato = valore2

                        If Risultato = "" Then

                        Risultato = valore1

                              If Risultato = "" Then

                              Risultato = "valore non valido"

                              Range("AH" & lng).Value = Risultato

                              End If

                         End If

             Range("AH" & lng).Value = Risultato

          End If

fine:

Next

End With

    Set sh = Nothing

End Sub

Microsoft 365 e Office | Excel | Per la casa | Windows

Domanda bloccata. Questa domanda è stata eseguita dalla community del supporto tecnico Microsoft. È possibile votare se è utile, ma non è possibile aggiungere commenti o risposte o seguire la domanda.

0 commenti Nessun commento

Risposta accettata dall'autore della domanda

  1. Anonimo
    2017-12-08T14:14:54+00:00

    Ciao nixio,

    ho provato il codice su una piccola parte di dati ed il risultato ottenuto è perfetto.

    Bene!

    Purtroppo c'è quel limite delle numerose righe... il file originale contiene piu di 400K righe :-(

    Provando infatti su quei dati si riceve il messaggio di errore "Memoria esaurita"...

    Controlla che tu stia utilizzando l'ultima versione del mio codice, La versione prima della modifica comprendeva una istruzione di scrivere al foglio un valore per ogni riga del arrDati. Questo comando era utilizzata da me, per commodità, solo per testare il codice ma renderebbe il codice lentissimo nel caso di centinaia di migliaia di righe di dati.

    Se hai ancora un problema, si potrebbe sempre modificare il codice per agire su (mettiamo) 100.000 righe alla volta. A questo proposito, nota che io avevo provato il codice con più di 100.000 righe e su un vechio pc con solo poca memoria.

    Tuttavia, credo sarebbe meglio che mi inviassi  la tua database di 400.000 record in modo che posso testarla direttamente. Faccendo clic sul mio profilo, troverai un indirizzo decifrabile.

    ===

    Regards,

    Norman

    La risposta è stata utile?

    1 persona ha trovato utile questa risposta.
    0 commenti Nessun commento

6 risposte aggiuntive

Ordina per: Più utili
  1. Anonimo
    2017-12-08T13:51:32+00:00

    Grazie,

    ho provato il codice su una piccola parte di dati ed il risultato ottenuto è perfetto.

    Purtroppo c'è quel limite delle numerose righe... il file originale contiene piu di 400K righe :-(

    Provando infatti su quei dati si riceve il messaggio di errore "Memoria esaurita"...

    La risposta è stata utile?

    0 commenti Nessun commento
  2. Anonimo
    2017-12-08T12:32:28+00:00

    Ciao  nixio, 

    devo valorizzare il contenuto di una cella (RISULTATO) in base al contenuto delle informazioni riportate in tre campi distinti della stessa tabella  ed una lista di valori che si trova in un altra tabella in base a dei criteri.

    I criteri da utilizzare sono:

    Il valore da riportare  varia in base a questi criteri e secondo diverse priorità:

    Innanzi tutto se il valore della cella nel "CAMPO13" è "descrizione3_campo13", nella rispettiva riga della colonna AH riporterò come RISULTATO "bloccato".

    Solo se non viene soddisfatta questa condizione, verifico il valore del CAMPO14,  se è uguale a "caso1", il RISULTATO da riportare nella riga della colonna AH sarà prioritariamente il contenuto della rispettiva cella del campo12 solo se questo è diverso da vuoto e diverso da uno dei valori presenti nella tabella "valori esclusi", altrimenti dovrà essere riportato come RISULTATO il valore presente nel campo13, sempre nel caso in cui quest'ultimo sia diverso da vuoto e diverso da uno dei valori presenti nella tabella "valori esclusi". Se non è possibile assegnare uno dei valori del campo12 o del campo13, il valore da riportare come RISULTATO sarà "valore assente".

    In tutti i casi in cui il valore del CAMPO14 è diverso da "caso1", il RISULTATO da riportare nella riga della colonna AH sarà prioritariamente  il contenuto della rispettiva cella del campo13, in seconda priorità il campo12 se il valore da riportare è vuoto o presente nella solita lista di valori da escludere. A cascata se anche il campo12 è un risultato da escludere (perchè vuoto o compreso nella lista valori da escludere), riporterò "valore assente.

    Ho provato a fare questo (ad esclusione della ricerca del valore nella tabella "valori da escludere") con il codice sotto riportato... non so come fare la verifica sulla tabella dei valori da escludere, il file di esempio è qui.

    Inoltre questa operazione andrebbe fatta su una lista di oltre 400.000 righe ed ho paura che questa da me abbozzata sia una soluzione snella...

    Public Sub m()

        Dim wk As Workbook

        Dim sh1 As Worksheet

        Dim sh2 As Worksheet

        Dim lng As Long

        Dim lUltRiga As Long

        Dim Risultato As String

        Dim valore1 As String

        Dim valore2 As String

        Dim condizione1 As String

        Dim condizione2 As String

        Set WB = ThisWorkbook

        With WB

            Set sh1 = .Worksheets("dati")

        End With

        With sh1

           lUltRiga = Range("A" & Rows.Count).End(xlUp).Row

    For lng = 2 To lUltRiga

                condizione1 = Range("M" & lng).Value

                condizione2 = Range("N" & lng).Value

                valore1 = Range("L" & lng).Value

                valore2 = Range("M" & lng).Value

    If condizione1 = "descrizione3_campo13" Then

                  Risultato = "BLOCCATO"

                  Range("AH" & lng).Value = Risultato

     GoTo fine

    End If

    If condizione2 = "caso1" Then

                   Risultato = valore1

                      If Risultato = "" Then

                            Risultato = valore2

                            If Risultato = "" Then

                                  Risultato = "valore non valido"

                                  Range("AH" & lng).Value = Risultato

                            End If

                       Range("AH" & lng).Value = Risultato

                       End If

                  Range("AH" & lng).Value = Risultato

                End If

             If condizione2 <> "caso1" Then

                      Risultato = valore2

                            If Risultato = "" Then

                            Risultato = valore1

                                  If Risultato = "" Then

                                  Risultato = "valore non valido"

                                  Range("AH" & lng).Value = Risultato

                                  End If

                             End If

                 Range("AH" & lng).Value = Risultato

              End If

    fine:

    Next

    End With

        Set sh = Nothing

    End Sub

    Prova qualcosa del genere:

    '=========>>

    Option Explicit

    Dim arrDati As Variant, arrEsclusi As Variant

    Dim arrOut() As Variant

    Dim i As Long

    Dim bEscluso As Boolean, bVuoto As Boolean

    Dim bAllocated As Boolean

    '--------->>

    Public Sub Tester()

        Dim WB As Workbook

        Dim SH_Dati As Worksheet, SH_Esclusi As Worksheet

        Dim RngDati As Range, rngEsclusi As Range

        Dim sStr12 As String, sStr13 As String

        Dim j As Long, UB As Long, LRow As Long

        Dim bFlag As Boolean, bFlag2 As Boolean

        Const sFoglioDati As String = "Dati"                        '<<=== Modifica

        Const sFoglioEsclusi As String = _

                                    "ValoriNonSignificativi"               '<<=== Modifica

        Const iColonnaCampo12 As Long = 12                    '<<=== Modifica

        Const iColonnaCampo13 As Long = 13                   '<<=== Modifica

        Const iColonnaCampo14 As Long = 14                    '<<=== Modifica

        Const sCondizione1 As String = _

                                    "descrizione3_campo13"              '<<=== Modifica

        Set WB = ThisWorkbook

        With WB

            Set SH_Dati = .Sheets(sFoglioDati)

            Set SH_Esclusi = .Sheets(sFoglioEsclusi)

        End With

        With SH_Dati

            LRow = LastRow(SH_Dati, .Columns("A:A"))

            Set RngDati = .Range("A2:AH" & LRow)

        End With

        With SH_Esclusi

            LRow = LastRow(SH_Esclusi, .Columns("A:A"))

            Set rngEsclusi = .Range("A2:A" & LRow)

        End With

        arrDati = RngDati.Value

        UB = UBound(arrDati)

        arrEsclusi = rngEsclusi.Value

        For i = 1 To UB

                bAllocated = False

            If arrDati(i, iColonnaCampo13) = sCondizione1 Then

                arrDati(i, 34) = "bloccato"

            Else

                sStr12 = arrDati(i, 12)

                sStr13 = arrDati(i, 13)

                Select Case True

                Case arrDati(i, 14) = "caso1"

                    arrDati(i, 34) = Risposta(sStr12, sStr13)

                Case Else

                    arrDati(i, 34) = Risposta(sStr13, sStr12)

                End Select

            End If

        Next i

        ReDim arrOut(1 To UB, 1 To 1)

        For j = 1 To UB

        arrOut(j, 1) = arrDati(j, 34)

        Next j

        On Error GoTo XIT

            With Application

            .Calculation = xlCalculationManual

            .ScreenUpdating = False

        End With

        RngDati.Columns(34).Value = arrOut

            Call MsgBox( _

                 Prompt:="Finito!", _

                 Buttons:=vbInformation, _

                 Title:="REPORT")

    XIT:

        With Application

            .Calculation = xlCalculationAutomatic

            .ScreenUpdating = True

        End With

    End Sub

    '--------->>

    Public Function Risposta(aStr As String, bStr As String) As String

        Dim Res As Variant, Res2 As Variant

        Res = Application.Match(aStr, arrEsclusi, 0)

        bEscluso = Not IsError(Res)

        bVuoto = aStr = vbNullString

        If Not bEscluso And Not bVuoto Then

            Risposta = aStr

            bAllocated = True

        Else

            Res2 = Application.Match(bStr, arrEsclusi, 0)

            bEscluso = Not IsError(Res2)

            bVuoto = bStr = vbNullString

            If Not bEscluso And Not bVuoto Then

                Risposta = bStr

                bAllocated = True

            End If

        End If

        If Not bAllocated Then

            Risposta = "valore non valido"

        End If

     End Function

    '--------->>

    Public Function LastRow(SH As Worksheet, _

                            Optional Rng As Range, _

                            Optional minRow As Long = 1, _

                            Optional sPassword As String)

        Dim bProtected As Boolean

        With SH

            If Rng Is Nothing Then

                Set Rng = .Cells

            End If

            bProtected = .ProtectContents = True

            If bProtected Then

                .Unprotect Password:=sPassword

            End If

        End With

        On Error Resume Next

        LastRow = Rng.Find(What:="*", _

                           after:=Rng.Cells(1), _

                           Lookat:=xlPart, _

                           LookIn:=xlFormulas, _

                           SearchOrder:=xlByRows, _

                           SearchDirection:=xlPrevious, _

                           MatchCase:=False).Row

        On Error GoTo 0

        If LastRow < minRow Then

            LastRow = minRow

        End If

        If bProtected Then

            SH.Protect Password:=sPassword, _

                       UserInterfaceOnly:=True

        End If

    End Function

    '<<=========

    Postscriptum:

    I risultati otttenuti da me con i tuoi dati erano tutti in accordo con quelli indicati da te come atteso.

    Ho anche provato il codice, estendendo i tuoi dati sino a 100.000 righe e, utilizzando il mio pc più vecchio, ci voleva circa 12 secondi. Visto che si trattava di una database di circa 3.500.000 celle e che il tuo compito sia mensile, questo tempo di esecuzione non mi era molto preoccupante.

    ===

    Regards,

    Norman

    La risposta è stata utile?

    0 commenti Nessun commento
  3. Anonimo
    2017-12-07T19:29:05+00:00

    Grazie Norman per l'interesse verso il caso esposto.

    Spiego meglio il passaggio seguente:

    [...]

    In tutti i casi in cui il valore del CAMPO14 è diverso da "caso1", il RISULTATO da riportare nella riga della colonna AH sarà prioritariamente  il contenuto della rispettiva cella del campo13, in seconda priorità il campo12 se il valore da riportare è vuoto o presente nella solita lista di valori da escludere. A cascata se anche il campo12 è un risultato da escludere (perchè vuoto o compreso nella lista valori da escludere), riporterò "valore assente.

    [...]Spiego meglio il punto

    Dopo avere verificato le condizioni che precedono, verifico il valore del CAMPO14, se contiene un valore diverso da "caso1", il valore che assegnerò come RISULTATO da inserire in corrispondenza della cella di colonna AH, sarà il contenuto del campo13. Se pero' il campo13 contiene un valore vuoto o uno dei valori presenti nella tabella "valori esclusi", in colonna AH riporterò il valore del campo12. Tuttavia se anche questo valore è vuoto o è un valore contenuto nella lista della tabella "valori esclusi", il valore da assegnare a RISULTATO sarà "Valore Assente".

    Spero di aver spiegato meglio.

    buona serata

    Nixio

    La risposta è stata utile?

    0 commenti Nessun commento
  4. Anonimo
    2017-12-07T18:08:22+00:00

    Ciao nixio,

    Quello che chiede non è difficile ma, dato le 400k righe della database, se fosse per me, a parte leggere i dati iniziali e successivamente copiare i dati finali, tutti i passi sarebbero eseguiti in memoria. 

    Detto ciò, ti chiederei gentilmente di rispiegare la seguente condizione in modo più dettaliato:

    [...]

    In tutti i casi in cui il valore del CAMPO14 è diverso da "caso1", il RISULTATO da riportare nella riga della colonna AH sarà prioritariamente  il contenuto della rispettiva cella del campo13, in seconda priorità il campo12 se il valore da riportare è vuoto o presente nella solita lista di valori da escludere. A cascata se anche il campo12 è un risultato da escludere (perchè vuoto o compreso nella lista valori da escludere), riporterò "valore assente.

    [...]

    ===

    Regards,

    Norman

    La risposta è stata utile?

    0 commenti Nessun commento