+ Rispondi al messaggio
Pagina 1 di 4 123 ... ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 35

Estrazione Dati in Range [gg/mm] senza [Anno]

  1. #1
    L'avatar di @Alex
    @Alex non è in linea Moderatore Globale
    Il tipico esempio è estrarre tutti i Clienti che compiono gli anni dal[gg/mm] al [gg/mm], senza quindi avere l'anno a vincolo.
    Questo tema, espone ad alcuni "problemi" che rendono la soluzione meno intuitiva di quanto possa sembrare.

    Non è possibile usare come criterio la parte gg/mm come si farebbe per l'uguiaglianza in quanto verrebbe vista come stringa e non come data:
    "SELECT * FROM T1 WHERE Format(CampoData,'mm/dd')='" & "mm/dd"
    
    In questo caso dobbiamo intercettare un Range DA÷A, serve quindi ricondurre il criterio a DATA, inserendo l'anno.
    Per rendere quindi il cirteio coerente con il CampoData, l'anno va recuperato dall'anno del campo data.

    Qui però nasce il problema del criteio nel caso in cui la parte del criterio di FINE RANGE abbia come Mese un mese con Numero inferiore dell'INIZIO RANGE.
    Ipotiziamo:
    CampoData=05/03/2000
    INIZIO RANGE=15/7		[15 Luglio]
    FINE RANGE=15/10		[15 Ottobre]
    
    Ricostruiamo il Range:
    INIZIO RANGE=15/7/2000	[15 Luglio]
    FINE RANGE=15/10/2000	[15 Ottobre]
    
    Sembra funzionare...!

    Ora prendiamo come criterio un range a cavallo dell'anno solare...
    INIZIO RANGE=15/12		[15 Dicembre]
    FINE RANGE=15/1			[15 Gennaio] <--- Questo è temporalmente nell'anno [n+1]
    
    Se componiamo l'anno recuperandolo dal campo data... le cose si complicano.
    Ipotiziamo:
    CampoData=05/01/2000
    INIZIO RANGE=15/12/2000	[15 Dicembre]
    FINE RANGE=15/1/2000	[15 Gennaio]<--- Questo NON è temporalmente nell'anno [n+1]
    
    Questo non è il criterio che ci serviva, in quanto confronta un range di tempo complementare a quanto richiesto.
    Noi avremmo dovuto ottenere [15/12/2000]÷[15/01/2001], sicchè il nostro CampoData risulta ESTERNO al range.

    Risultato...? NON FUNZIONA.

    Allora sommiamo 1 Anno, se il Mese della FINE RANGE è Minore del mese INIZIO RANGE... [Gennaio(1)]<[Dicembre(12)]
    Seguendo la logica esposta verrebbe:
    CampoData=05/01/2000
    INIZIO RANGE=15/12/2000	[15 Dicembre]
    FINE RANGE=15/1/2001	[15 Gennaio]
    
    Il nostro campo data verrebbe ancora ESLCUSO dal Range in quanto cade nel range giusto ma dell'anno precedente.

    Risultato...? NON FUNZIONA.

    Abbiamo compreso che il periodo critico è il caso in cui la data sia a cavallo dell'anno.
    Tra le varie soluzioni più e meno semplici, ho optato per questa che vi propongo che mi pare semplice ed intuitiva, ovvero usare il criterio di cui sopra, ma aggiungere un secondo criterio in OR che tenga conto anche dell'eventuale ANNO perso dal metodo.
    Infondo l'estrazione del criterio senza ANNO, significa che nel Range di mm/dd ci devono cadere TUTTI gli anni.

    Il Risultato è una Query parametrica così Strutturata:
    PARAMETERS pMINI Byte, pMEND Byte, pDINI Byte, pDEND Byte;
    SELECT *
    FROM T1 WHERE 	(T1.Nascita 			
    					Between	DateSerial(Year(T1.Nascita),[pMINI],[pDINI]) And 
    							DateSerial(Year(T1.Nascita)-([pMEND]<[pMINI]),[pMEND],[pDEND])) OR  
    				(Dateadd('YYYY',1,T1.Nascita) 	
    					Between DateSerial(Year(T1.Nascita),[pMINI],[pDINI]) And 
    							DateSerial(Year(T1.Nascita)-([pMEND]<[pMINI]),[pMEND],[pDEND]));
    

    Su questo tema ho realizzato un esempio semplice che implementa l'uso della Query Parametrica.
    Quì la funzione che restituisce un Recordset basato sulla Query Parametrica di cui sopra.

    La funzione in questione consente anche di passare solo il Mese, quindi da Marzo a Luglio... ricava in autonomia gli estremi.
    Private Function OpenQueryRange(MonthIni As Byte, MonthEnd As Byte, Optional DayIni, Optional DayEnd) As DAO.Recordset
        Dim qdf     As DAO.QueryDef
        
        Dim bMIni   As Byte
        Dim bMEnd   As Byte
        Dim bDIni   As Variant
        Dim bDEnd   As Variant
        
        bMIni = MonthIni
        bMEnd = MonthEnd
        bDIni = DayIni
        bDEnd = DayEnd
        
        If IsMissing(DayIni) Then bDIni = 1
        If IsMissing(DayEnd) Then bDEnd = Day(Fix(DateSerial(Year(Date), Month(bMEnd) + 1, 0)))
        
        Set qdf = DBEngine(0)(0).QueryDefs("Q1")
        With qdf
            Debug.Print .SQL
            .Parameters!pMINI = bMIni
            .Parameters!pDINI = bDIni
            .Parameters!pMEND = bMEnd
            .Parameters!pDEND = bDEnd
            Set OpenQueryRange = .OpenRecordset
        End With
        qdf.Close
    End Function
    
    BirthDay.zip

    P.S. Spero qualcuno abbia soluzioni più semplici, nel caso sarebbe interessante condividerle.
    Ultima modifica di @Alex; 20-08-2021 07:49 
    ℹ️ Leggi di più su @Alex ...

  2. #2
    L'avatar di Max.Riservo
    Max.Riservo non è in linea Scribacchino
    Ciao Alex,
    secondo me si può ragionare utilizzando il between (quando Mese/Giorno finale è superiore a Mese/Giorno iniziale) e usare il NOT Between quando è il contrario.
    Esempio :
    range 15/04 - 15/10 -> Between 15/04 and 15/10
    range 15/10 - 15/04 -> NOT Between 15/04 and 15/10 (quì in realtà dovrebbe essere 16/04 and 14/10)

    Risposta data così ... con un poco di ragionamento ma senza approfondire più di tanto (sicuramente sulle prestazione del NOT).

  3. #3
    L'avatar di @Alex
    @Alex non è in linea Moderatore Globale
    Non ho capito Max... puoi scrivermi il predicato SQL che lo provo...?
    Grazie
    ℹ️ Leggi di più su @Alex ...

  4. #4
    L'avatar di Max.Riservo
    Max.Riservo non è in linea Scribacchino
    Avrei dovuto lubrificare meglio le rotelle : il NOT Between non può fare quello che chiedi.
    Credo che questo approccio possa però funzionare :
    range 15/04 - 15/10
    Select * from tbl where DataNascita 
    Between year(DataNascita)/04/15 and year(DataNascita)/10/15
    
    range 15/10 - 15/04
    Select * from tbl where DataNascita
    Between year(DataNascita)/01/01 and year(DataNascita)/04/15 Or
    Between year(DataNascita)/10/15 and year(DataNascita)/12/31
    
    Però rispetto al tuo metodo prevede 2 query distinte ... quindi non è che mi soddisfi particolarmente.

  5. #5
    L'avatar di @Alex
    @Alex non è in linea Moderatore Globale
    Se il Periodo è 4/15÷10/15 significa controllare solo 15Aprile÷15Ottobre... mi pare che quanto proponi non faccia questo, in particolare la 2° query, che prende in esame un lasso che non comprendo.

    Il problema tuttavia è quando inserisci periodi a cavallo dell'anno... come spiegato nel mio "tema" sopra... in cui l'anno del periodo di STOP è Anno+1, hai provato a testarlo...?

    Poi sinceramente farew 2 Query credo sia peggio che farne 1
    ℹ️ Leggi di più su @Alex ...

  6. #6
    L'avatar di Max.Riservo
    Max.Riservo non è in linea Scribacchino
    Quote Originariamente inviato da @Alex Visualizza il messaggio
    Poi sinceramente fare 2 Query credo sia peggio che farne 1
    Concordo ...

    Quote Originariamente inviato da @Alex Visualizza il messaggio
    Se il Periodo è 4/15÷10/15 significa controllare solo 15Aprile÷15Ottobre... mi pare che quanto proponi non faccia questo, in particolare la 2° query, che prende in esame un lasso che non comprendo.
    La 2° query (15/10-15/04) considera il periodo 15/10-31/12 + 01/01-15/04 (il periodo è consecutivo SE c'è l'anno ma nel ns. caso, che NON vogliamo l'anno, occorre spezzare in 2 semi periodi).

    Forse l'ho già scritto : 1 query è meglio di 2 query

  7. #7
    L'avatar di @Alex
    @Alex non è in linea Moderatore Globale
    Quote Originariamente inviato da Max.Riservo Visualizza il messaggio
    Concordo ...


    La 2° query (15/10-15/04) considera il periodo 15/10-31/12 + 01/01-15/04 (il periodo è consecutivo SE c'è l'anno ma nel ns. caso, che NON vogliamo l'anno, occorre spezzare in 2 semi periodi).

    Forse l'ho già scritto : 1 query è meglio di 2 query
    Perdona se insisto... ma il periodo NON è consecutivo nell'esempio che fai...!
    15/10-31/12 + 01/01-15/04
    
    Se metti l'anno come Year(DataNascita)... otteniamo:
    15/10/2000-31/12/2000 + 01/01/2000-15/04/2000
    
    Concordi che non sono consecutivi...?
    Il secondo STEP è nella prima parte dell'anno, il primo nell'ultima... sembrano consecutivi ma non cambiando l'anno non lo sono più... sono agli estremi dello stesso anno
    ℹ️ Leggi di più su @Alex ...

  8. #8
    L'avatar di Max.Riservo
    Max.Riservo non è in linea Scribacchino
    Quote Originariamente inviato da @Alex Visualizza il messaggio
    Concordi che non sono consecutivi...?
    Il secondo STEP è nella prima parte dell'anno, il primo nell'ultima... sembrano consecutivi ma non cambiando l'anno non lo sono più... sono agli estremi dello stesso anno
    Concordo, però se ho compreso il tuo punto di partenza (l'estrazione di uno stesso periodo che comprende mese+giorno ma non l'anno, SENZA alcuna restrizione temporale ovvero i.e. tutti i nati tra il 15/10 anno del BingBang al 15/04 dell'infinito) anche il mio approccio funziona (certo occorrono 2 query quindi oltre a NON soddisfarmi NON aggiunge alcunché al tuo approccio).
    Se invece, vuoi estrarre dei record rispettando il periodo e ponendo un limite temporale alla ricerca (i.e. tutti i nati dal 15/10 al 15/04 TRA il 1970 e il 2020), allora il mio approccio sbaglia sugli estremi (1970/01/01-1970/04/15 e 2020/10/15-2020/12/31). Oltremodo in questo caso occorre anche porre una ulteriore clausola sull'anno iniziale e anno finale.

    Niente di più facile che io abbia frainteso cosa vuoi ottenere ...

  9. #9
    L'avatar di willy55
    willy55 non è in linea Scribacchino
    Se ho compreso l'esigenza: ovvero si vogliono determinare le date che ricadono in un intervallo continuo (DAL- AL) dei giorni (e mesi) indipendentemente dall'anno.
    Quindi nel caso in cui il valore DAL (come associazione di mese e giorno) sia più piccolo del valore (AL) l'intervallo ricade nell'anno in corso (e quindi applicabile la semplice BETWEEN dell'esempio); altrimenti (DAL maggiore di AL) siamo nel caso di intervalllo che ricade nell'anno successivo e quindi il criterio della BETWEEN può essere semplicemente DAL (come giorno, mese e anno della data) mentre per AL sarà giorno, mese e anno incrementato dell'unità.
    ℹ️ Leggi di più su willy55 ...

  10. #10
    L'avatar di @Alex
    @Alex non è in linea Moderatore Globale
    [@Max]
    L'intento è cercare chi compie gli anni dal [gg1/mm1]÷[gg2/mm2], quindi l'anno non deve avere alcuna rilevanza fattiva in qualsiasi anno compierebbero gli anni... bisestili inclusi

    Concordo con la funzionalità di cui parli... ma entra in gioco non solo l'aspetto delle 2 Query già chiaro, ma anche l'aspetto del Costrutto SQL che risulta più complesso da articolare come codice...
    Ultima modifica di @Alex; 20-08-2021 16:11 
    ℹ️ Leggi di più su @Alex ...

+ Rispondi al messaggio
Pagina 1 di 4 123 ... ultimoultimo

Potrebbero interessarti anche ...

  1. Generare numeri casuali senza duplicati (estrazione lotto)
    Da padronus5 nel forum Microsoft Excel
    Risposte: 4
    Ultimo Post: 06-06-2014, 10:36
  2. Estrazione URL da range di celle evitando ciclo
    Da genespos nel forum Microsoft Excel
    Risposte: 0
    Ultimo Post: 22-08-2013, 13:18
  3. Risposte: 5
    Ultimo Post: 07-08-2010, 09:41
  4. Filtrare per Mese e Anno senza inserire i Giorni
    Da Maury63 nel forum Visual Basic .Net
    Risposte: 9
    Ultimo Post: 01-07-2010, 15:59
  5. Inserimento solo l'anno (senza mese e giorno)
    Da Martin Landau nel forum Microsoft Word
    Risposte: 5
    Ultimo Post: 30-10-2006, 12:24