MACRO excel filtrare foglio controllo accessi badge tornello

Anonimo
2017-12-27T14:49:03+00:00

Salve a tutti,

mi trovo nella situazione di gestire un foglio Excel prodotto in automatico da un sistema di controllo accessi con tornello e badge personale, vi spiego bene l'antefatto per arrivare alla richiesta di aiuto.

Tale foglio contiene tutte e dico TUTTE le strisciate con badge per l'ingresso/uscita al tornello, registrate su 5 colonne: N° badge, nome cognome, ditta, data ora, IN/OUT. Succede quindi che 10 IN/OUT vengono registrate singolarmente senza distinzione tranne che per data ora (scritto in un'unica cella) e con 60-70 persone ho fogli mensili con migliaia di righe.

1 Tizio AAA  01/01/2018  IN

1 Tizio AAA  01/01/2018  IN

1 Tizio AAA  01/01/2018  IN

1 Tizio AAA  02/01/2018  IN

1 Tizio AAA  02/01/2018  IN

1 Tizio AAA  03/01/2018  IN

2 Caio AAA  01/01/2018  IN

2 Caio AAA  01/01/2018  IN

2 Caio AAA  01/01/2018  IN

2 Caio AAA  03/01/2018  IN

2 Caio AAA  03/01/2018  IN

2 Caio AAA  03/01/2018  IN

3 Sempronio BBB  02/01/2018  IN

3 Sempronio BBB  02/01/2018  IN

3 Sempronio BBB  03/01/2018  IN

3 Sempronio BBB  03/01/2018  IN

3 Sempronio BBB  04/01/2018  IN

3 Sempronio BBB  04/01/2018  IN

3 Sempronio BBB  04/01/2018  IN

3 Sempronio BBB  05/01/2018  IN

Vorrei quindi poter filtrare in modo da creare su un altro foglio (o più fogli) una lista con la singola presenza nel tal giorno.

Esempio:

1 Tizio AAA  01/01/2018  IN

1 Tizio AAA  02/01/2018  IN

1 Tizio AAA  03/01/2018  IN

2 Caio AAA  01/01/2018  IN

2 Caio AAA  03/01/2018  IN

3 Sempronio BBB  02/01/2018  IN

3 Sempronio BBB  03/01/2018  IN

3 Sempronio BBB  04/01/2018  IN

3 Sempronio BBB  05/01/2018  IN

In questo modo si ha una lista con 1 solo record per persona per giorno, mi basta solo sapere che la persona era presente tal giorno, eliminando anche le righe date da doppie-triple-quadruple striciate perchè il tornello non gira e invece il lettore ha registrato il passaggio.

Con i filtri classici di Excel non si riesce perchè non c'è differenza tra varie badgate ripetute consecutive, cambia solo la colonna data-ora. Forse con una formula "SE" ripetuta molto complessa che possa prendere una sola volta il nome all'interno di una selezione di 1 singolo giorno e lo scriva in un'altra cella.. ma non ne vengo fuori in sostanza.

Vi ringrazio per i suggerimenti.

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

Anonimo
2017-12-27T16:18:52+00:00

Posso suggerire una soluzione, temo però che a causa dell'elevato numero di righe il calcolo richieda tempi lunghi.

Se è così sarebbe meglio una soluzione VBA che, però, lascio agli esperti di codice quale io non sono.

Nell'ipotesi che la colonna della data del foglio1 contenga anche l'ora (cosa che non risulta dall'esempio che hai riportato),

innanzitutto assegniamo dei nomi agli intervalli:

nome: Badge

riferito a: =SCARTO($A$1;1;;CONTA.VALORI($A:$A)-1)

nome: Nome

riferito a: =SCARTO($A$1;1;1;CONTA.VALORI($A:$A)-1)

nome: Ditta

riferito a: =SCARTO($A$1;1;2;CONTA.VALORI($A:$A)-1)

nome: Data_Ora

riferito a: =INT(SCARTO($A$1;1;3;CONTA.VALORI($A:$A)-1))

nome: IN_OUT

riferito a: =SCARTO($A$1;1;4;CONTA.VALORI($A:$A)-1)

Nel Foglio 2, dopo avere inserito le intestazioni in riga 1:

attenzione, tutte le formule che seguono sono matriciali, perciò, una volta copiate nella barra delle formule, vanno confermate con Ctrl+Maiusc+Invio.

in A2: =SE.ERRORE(INDICE(Badge;PICCOLO(SE(VAL.NUMERO(CONFRONTA(RIF.RIGA(Badge)-1;CONFRONTA(Badge&Data_Ora;Badge&Data_Ora;0);0));CONFRONTA(Badge&Data_Ora;Badge&Data_Ora;0);"");RIF.RIGA($A1)));"")

in B2: =SE.ERRORE(INDICE(Nome;CONFRONTA($A2&$D2;Badge&Data_Ora;0));"")

in C2: =SE.ERRORE(INDICE(Ditta;CONFRONTA($A2&$D2;Badge&Data_Ora;0));"")

in D2: =SE.ERRORE(INDICE(Data_Ora;PICCOLO(SE(VAL.NUMERO(CONFRONTA(RIF.RIGA(Badge)-1;CONFRONTA(Badge&Data_Ora;Badge&Data_Ora;0);0));CONFRONTA(Badge&Data_Ora;Badge&Data_Ora;0);"");RIF.RIGA($A1)));"")

in E2: =SE.ERRORE(INDICE(IN_Out;CONFRONTA($A2&$D2;Badge&Data_Ora;0));"")

ora seleziona l'intervallo A2:E2, prendi il quadratino di riempimento e trascina in basso fino a quando non compaiono più risultati.

Scarica il file d'esempio QUI.

La risposta è stata utile?

0 commenti Nessun commento

2 risposte aggiuntive

Ordina per: Più utili
  1. Anonimo
    2018-01-02T12:03:52+00:00

    Ciao Andrea,

    Salve,

    innanzitutto ringrazio per la risposta e devo dire che ha risolto in buona parte la questione. Va detto che il foglio è pesante a livello di calcolo, cosa peraltro anticipata , e ad ogni modifica o apertura mette al massimo l'utilizzo del computer per diversi minuti. Mi trovo infatti un file mensile con circa 10000 righe e sto pensando a come semplificare il processo di ricerca. 

    Ovvero immettere solo 3 intervalli: nome, ditta, data (data senza ora) tralasciando il dato di numero badge ed in-out in quanto è sufficiente che sia presente 1 record per giorno per considerarlo. Il numero badge è superfluo perché considero che il badge sia personale e non cedibile, IN-OUT rimando questo controllo ad un secondo momento.

    Credo basti adattare le formule sopra, ci proverò ma sennò se ci sono ulteriori suggerimenti ben vengano.

    Per sfruttare un approccio VBA, che dovrebbe essere molto veloce ed efficiente, anche con migliaia di record, prova qualcosa del genere:

    • Alt+F11 per aprire l'editor di VBA
    • Alt+IM per inserire un nuovo modulo di codice
    • Nel nuovo modulo vuoto, incolla il seguente codice:

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

    Option Explicit

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

    Public Sub Tester()

        Dim WB As Workbook

        Dim srcSH As Worksheet, reportSH As Worksheet

        Dim srcRng As Range, destRng As Range, tableRng As Range

        Dim arrIn As Variant, arrOut() As Variant

        Dim arrHeaders As Variant, arrJoin As Variant

        Dim oDic As Object

        Dim sStr As String

        Dim LRow As Long

        Dim i As Long, j As Long, k As Long

        Dim iCtr As Long

        Dim UB As Long, UB2 As Long

        Dim CalcMode As Long

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

        Const sFoglioReport As String = "Foglio2"                   '<<=== Modifica

        Set WB = ThisWorkbook

        With WB

            Set srcSH = .Sheets(sFoglioDati)

            Set reportSH = .Sheets(sFoglioReport)

        End With

        reportSH.UsedRange.ClearContents

        With srcSH

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

            Set srcRng = .Range("A2:E" & LRow)

        End With

        arrIn = srcRng.Value2

        arrHeaders = srcRng.Rows(0).Value

        UB = UBound(arrIn)

        UB2 = UBound(arrIn, 2)

        ReDim arrOut(1 To UB, 1 To UB2)

        ReDim arrJoin(1 To UB2)

        Set oDic = CreateObject("Scripting.Dictionary")

        With oDic

            .CompareMode = vbTextCompare

            For i = 1 To UB

                arrJoin(1) = arrIn(i, 1)

                arrJoin(2) = arrIn(i, 2)

                arrJoin(3) = arrIn(i, 3)

                arrJoin(4) = CLng(arrIn(i, 4))

                arrJoin(5) = arrIn(i, 5)

                sStr = Join(arrJoin, "-")

                If Not .exists(sStr) Then

                    .Add Key:=sStr, Item:=Nothing

                    iCtr = iCtr + 1

                    For j = 1 To UB2

                        arrOut(iCtr, j) = arrIn(i, j)

                    Next j

                End If

                sStr = vbNullString

            Next i

        End With

        If CBool(iCtr) Then

    '        On Error GoTo XIT

            With Application

                CalcMode = .Calculation

                .Calculation = xlCalculationManual

                .ScreenUpdating = False

            End With

            Set destRng = reportSH.Range("A2").Resize(iCtr, UB2)

            With destRng

                .Rows(0).Value = arrHeaders

                .Value = arrOut

                .Columns(2).ColumnWidth = 30

                 .Columns(3).ColumnWidth = 25

                With .Columns(4)

                    .NumberFormat = "dd/mm/yyyy hh:mm"

                    .ColumnWidth = 20

                End With

                Set tableRng = .Offset(-1).Resize(iCtr + 1)

                With tableRng

                    .HorizontalAlignment = xlCenter

                    .VerticalAlignment = xlCenter

                End With

            End With

            reportSH.ListObjects.Add( _

                    xlSrcRange, tableRng, , xlYes).Name = "TabellaFiltrata"

        End If

            Call MsgBox( _

                 Prompt:="Finito!", _

                 Buttons:=vbInformation, _

                 Title:="REPORT")

    XIT:

        With Application

            .Calculation = CalcMode

            .ScreenUpdating = True

        End With

        Set oDic = Nothing

    End Sub

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

    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

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

    • Alt+Q per chiudere l'editor di VBA e tornare a Excel
    • Salva il file con l’estensione xlsm
    • Alt+F8 per aprire  la finestra di gestione delle macro
    • Seleziona Tester
    • Esegui

    Potresti scaricare il mio file di prova Andrea20180102.xlsm

    ===

    Regards,

    Norman

    La risposta è stata utile?

    0 commenti Nessun commento
  2. Anonimo
    2018-01-02T09:39:57+00:00

    Salve,

    innanzitutto ringrazio per la risposta e devo dire che ha risolto in buona parte la questione. Va detto che il foglio è pesante a livello di calcolo, cosa peraltro anticipata , e ad ogni modifica o apertura mette al massimo l'utilizzo del computer per diversi minuti. Mi trovo infatti un file mensile con circa 10000 righe e sto pensando a come semplificare il processo di ricerca. 

    Ovvero immettere solo 3 intervalli: nome, ditta, data (data senza ora) tralasciando il dato di numero badge ed in-out in quanto è sufficiente che sia presente 1 record per giorno per considerarlo. Il numero badge è superfluo perché considero che il badge sia personale e non cedibile, IN-OUT rimando questo controllo ad un secondo momento.

    Credo basti adattare le formule sopra, ci proverò ma sennò se ci sono ulteriori suggerimenti ben vengano.

    Ringrazio nuovamente.

    La risposta è stata utile?

    0 commenti Nessun commento