Come impostare una Query

mercoledì 05 maggio 2010 - 17.55

maxbolz Profilo | Newbie

Salve a tutti.
Ho una tabella con i record siffatti:
campo1=INIZIO tipo=DATA
campo2=FINE tipo=DATA
campo3=MSG tipo=TESTO

che rappresenta una raccolta di eventi provenienti da una macchina utensile (allarmi e messaggi).

Il periodo di interrogazione può essere lungo fino a 40 giorni (es.: 1/03 - 31/03).

Però io dovrei 'sovrapporre' al periodo scelto dall'utente una 'maschera' temporale che definisce i turni lavorativi,
ad es.: 8.00 - 12.00 , 14.00 - 18.00 da lunedì al venerdì.

Come posso formulare la query? Esiste in SQL una istruzione che mi permette di sovrapporre una maschera temporale così definita?
Grazie a chi vorrà rispondermi.
Ciao, Massimo.

dinoxet Profilo | Senior Member

descrivi un esempio non ho ben capito cosa intendi per sovrapporre.



DINOXET
__________________________________________
impossible is only a word

lbenaglia Profilo | Guru

>Come posso formulare la query? Esiste in SQL una istruzione che
>mi permette di sovrapporre una maschera temporale così definita?

Ciao Massimo,

Posta i comandi di CREATE TABLE della tabella, alcune righe di prova (INSERT INTO), alcuni esempi di query con il relativo result set che ti aspetti con i dati indicati.

>Grazie a chi vorrà rispondermi.
Prego.

Ciao!
--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org

maxbolz Profilo | Newbie

Finora, per presentare un risultato al cliente che chiedeva ad es. dati tra il 1 Marzo e il 31 Marzo, facevo la seguente query:
SELECT * FROM I_TABELLA
WHERE (FINE > '2010/03/01') AND (INIZIO < '2010/03/31')

In tal modo erano selezionati tutti i record compresi e a cavallo degli estremi temporali.

Ora devo complicare le cose perchè occorre tenere conto degli orari di lavoro.
Ovviamente dal 1 al 31 non tutte le ore sono lavorative e quindi i record (che possono coprire anche orari non lavorativi,
perchè un allarme macchina può coprire più turni, ma nelle ore non lavorative non deve essere conteggiato il tempo
ai fini del calcolo dell'efficienza di machina) devono essere 'spurgati' del tempo che non cade negli orari di lavoro.
Quindi, se un allarme è descritto così: INIZIO=9/03/2010 11:10 FINE=9/03/2010 15:45 MSG=MANCA OLIO, la query
deve dare un resultset in cui questo record compare così (in questo caso diventano 2):
INIZIO=9/03/2010 11:10 FINE=9/03/2010 12:00 MSG=MANCA OLIO
INIZIO=9/03/2010 14:00 FINE=9/03/2010 15:45 MSG=MANCA OLIO
perchè devo applicare una 'maschera' temporale data dall'orario di lavoro 8.00 - 12.00 e 14.00 - 18.00

Spero di essermi spiegato.
Grazie.

Jok83 Profilo | Junior Member

Ciao
>campo1=INIZIO tipo=DATA
>campo2=FINE tipo=DATA
>INIZIO=9/03/2010 11:10 FINE=9/03/2010 12:00 MSG=MANCA OLIO
>INIZIO=9/03/2010 14:00 FINE=9/03/2010 15:45 MSG=MANCA OLIO
Ma i campi INIZIO e FINE sono Data o DataTime?

Per raddoppiare il record come nell'esempio che dici tu forse si potrebbe fare una Union tra due select (una con gli orari di mattino (di inizio) e l'altra con quelli pomeridiani chiusi nella giornata)
se metti un esempio di creazione e popolazione della tabella magari proviamo a vedere se funziona.



maxbolz Profilo | Newbie

Grazie della risposta. Non volevo entrare troppo nel dettaglio per non appesantire il thread.
In azienda utilizziamo tabelle Paradox e ambiente di sviluppo Delphi (Windows XP e Vista).
La tabella viene generata da codice mediante componenti nativi Delphi.
I campi INIZIO e FINE son di tipo TDateTime (Data e Ora).
La popolazione della tabella viene eseguita da un applicativo, sempre tramite codice Delphi,
utilizzando il BDE; una cosa del tipo:

with ATable do begin //ATable è il componente per accedere a una tabella
if not Active then Active := True;
Append;
FieldByName('MSG').AsString := MEA.Msg; //MEA è un buffer di dati
FieldByName('INIZIO').AsDateTime := MEA.DataBegin;
FieldByName('FINE').AsDateTime := MEA.DataEnd;
Post;
end;//with

La lettura dei dati invece viene fatta da due nuovi applicativi, sviluppati da me, un Server e un Client.
Il Server legge i dati tramite un componente Delphi TQuery, nella cui proprietà SQL viene impostata
la stringa SQL da eseguire, quella che vi ho mostrato nel post precedente. Alla chiamata del metodo Open
di TQuery viene fornito il resultset.

Forse non ho capito il tuo suggerimento, ma nel mio caso dovrei fare 2*N Union? Ammesso che i turni lavorativi
siano solo 2! Da notare che le date sono 'assolute', comprendono anche l'ora e sono conteggiate con un numero
a 8 byte, la cui origine è il 1° gen 1900.
Penso comunque che l'SQL nativo non contenga una istruzione semplice per fare quello di cui ho bisogno, ma chissà...
Grazie dell'interessamento, Massimo.

Jok83 Profilo | Junior Member

Allora non sono sicuro d'aver capito bene e neanche che funzioni sulla tua piattaforma...
ho fatto una prova su un mio database di assistenze e trasportato sul tuo diventa così:

A- prendo tutti i "guasti" compresi in un orario di un giorno (il mio orario è 8-13 14-18) percui tutto ciò che fuori da questo orario per il giorno 05/05/2010 non lo pesco

select * from TUATABELLA
where ((DATEPART(hour,INIZIO)>8 and DATEPART(hour,INIZIO)<13) or
(datepart(hour,INIZIO)>14 and datepart(hour,INIZIO)<18 ))
and convert(date,INIZIO)=convert(date,'05/05/2010')

B - prendo tutti i guasti che sono iniziati nell'orario del mattino e terminati in quello pomeridiano

select * from TUATABELLA where DATEPART(hour,INIZIO)>8 and DATEPART(hour,INIZIO)<13 and convert(date,INIZIO)=convert(date,'05/05/2010')and DATEPART(hour,FINE)>13

C - UNISCO A E B mantenendo i record duplicati

select * from TUATABELLA
where ((DATEPART(hour,INIZIO)>8 and DATEPART(hour,INIZIO)<13) or
(datepart(hour,INIZIO)>14 and datepart(hour,INIZIO)<18 ))
and convert(date,INIZIO)=convert(date,'05/05/2010')
UNION ALL
select * from TUATABELLA where DATEPART(hour,INIZIO)>8 and DATEPART(hour,INIZIO)<13 and convert(date,INIZIO)=convert(date,'05/05/2010')and DATEPART(hour,FINE)>13

prova a vedere se funziona...

maxbolz Profilo | Newbie

Ti ringrazio moltissimo, domani sono in cassa integrazione, ma lunedì provo subito;
spero di riuscire a convertire le funzioni perchè il Paradox è proprio scarso...
Grazie e buon week-end, Massimo.

maxbolz Profilo | Newbie

Grazie per la risposta.
Però a me occorre che i record, nel caso cadano a cavallo di due turni, siano 'ritagliati',
come ho mostrato nel mio secondo intervento (a questo punto, penso che ciò debba essere
fatto al momento della generazione dei record in modo da trovarsi la tabella già pronta);
inoltre il cliente può richiedere i dati anche fino a 40 giorni per cui dovrei eliminare
dalla query di esempio da te inviata la parte

and convert(date,INIZIO)=convert(date,'05/05/2010')

in modo da raccogliere i dati su più giorni.
Se sei ancora disponibile, cosa ne pensi?
Ciao, Massimo.

Jok83 Profilo | Junior Member

>Grazie per la risposta.
>Però a me occorre che i record, nel caso cadano a cavallo di due turni, siano 'ritagliati',
>come ho mostrato nel mio secondo intervento (a questo punto, penso che ciò debba essere
>fatto al momento della generazione dei record in modo da trovarsi la tabella già pronta);
Ciao,
intendi che deve cambiare l'ora di INIZIO- FINE? come fai vedere qui:
>INIZIO=9/03/2010 11:10 FINE=9/03/2010 12:00 MSG=MANCA OLIO
>INIZIO=9/03/2010 14:00 FINE=9/03/2010 15:45 MSG=MANCA OLIO

>inoltre il cliente può richiedere i dati anche fino a 40 giorni per cui dovrei eliminare
>dalla query di esempio da te inviata la parte
>and convert(date,INIZIO)=convert(date,'05/05/2010')
>in modo da raccogliere i dati su più giorni.
certo qui puoi mettere l'intervello che ti richiedono as esempio da 01 al 31 maggio diventa:
and ((convert(date,INIZIO)>=convert(date,'01/05/2010'))AND(convert(date,INIZIO)<=convert(date,'31/05/2010')))
>Se sei ancora disponibile, cosa ne pensi?
Si non sono sicuro che la soluzione che ti sto proponendo sia la migliore o la più adatta al tuo caso (non sono un esperto)...probabilmente ci stiamo adattando alla situazione che hai, fammi fare una prova sul mio db.
le query che ti ho passato riesci a farle girare sul tuo sitema cmq giusto?

maxbolz Profilo | Newbie

>Ciao,
>intendi che deve cambiare l'ora di INIZIO- FINE? come fai vedere qui:
>>INIZIO=9/03/2010 11:10 FINE=9/03/2010 12:00 MSG=MANCA OLIO
>>INIZIO=9/03/2010 14:00 FINE=9/03/2010 15:45 MSG=MANCA OLIO
Esatto.

>le query che ti ho passato riesci a farle girare sul tuo sitema cmq giusto?
Non ho nemmeno provato perchè con una SELECT non riesco ad ottenere i
record modificati, dovrei generare prima una tabella o vista e poi usarli,
comunque sì, penso che riuscirei a convertirla per Paradox.

Grazie comunque del tuo gentile supporto.
Massimo.

Jok83 Profilo | Junior Member

Allora proviamo:

' per modificare l'ora uso un case when sulla fine nella prma query e sull'inizio nella seconda, ho sostituito i campi con i tuoi spero di non aver fatto confusione perchè non ho modo di provarla sul tuo db:

select INIZIO as INIZIO,case when datepart(hour,FINE)>13 then convert(nvarchar(50),(Convert(date,FINE,1)))+' ' + '13:00:00' else FINE end as FINE,MSG from TUATABELLA
where ((DATEPART(hour,INIZIO)>8 and DATEPART(hour,INIZIO)<13) or
datepart(hour,INIZIO)>14 and datepart(hour,INIZIO)<18 ) and convert(date,INIZIO)=convert(date,'05/05/2010')
UNION ALL
select case when datepart(hour,FINE)>13 then convert(nvarchar(50),(Convert(date,INIZIO,1)))+' ' + '14:00:00' else INIZIO end as INIZIO,FINE AS FINE ,MSG from TUATABELLA
where DATEPART(hour,INIZIO)>8 and DATEPART(hour,INIZIO)<13 and convert(date,INIZIO)=convert(date,'05/05/2010')and DATEPART(hour,FINE)>13

io l'ho provata su un mio db dove ho una tabella che racchiude le richieste di assistenza (SEDE,DATARICHIESTA (il tuo inizio),datachiusuta(la tua FINE):

select CodPT,DataOraRichiesta as INIZIO,case when datepart(hour,DataOraChiusura)>13 then convert(nvarchar(50),(Convert(date,dataorarichiesta,1)))+' ' + '13:00:00' else DataOraChiusura end as FINE from rcaassistenza
where ((DATEPART(hour,dataorarichiesta)>8 and DATEPART(hour,dataorarichiesta)<13) or
datepart(hour,dataorarichiesta)>14 and datepart(hour,dataorarichiesta)<18 ) and convert(date,DataOraRichiesta)=convert(date,'05/05/2010')
UNION ALL
select CodPT,case when datepart(hour,DataOraChiusura)>13 then convert(nvarchar(50),(Convert(date,dataorarichiesta,1)))+' ' + '14:00:00' else DataOraChiusura end as INIZIO,DataOraChiusura AS FINE from rcaassistenza
where DATEPART(hour,dataorarichiesta)>8 and DATEPART(hour,dataorarichiesta)<13 and convert(date,dataorarichiesta)=convert(date,'05/05/2010')and DATEPART(hour,DataOraChiusura)>13
ORDER BY CodPT

e ottengo questo:
SEDE INIZIO FINE
an2 2010-05-05 12:26:27 2010-05-05 13:00:00
an2 2010-05-05 14:00:00 2010-05-05 17:50:46
br1 2010-05-05 15:06:15 2010-05-05 13:00:00
cl1 2010-05-05 15:26:36 2010-05-05 17:00:00
cr1 2010-05-05 09:44:53 2010-05-05 13:00:00
cr1 2010-05-05 14:00:00 2010-05-05 17:23:41

in pratica an2 è iniziato alle 12:26 e finito alle 17:50
e cr1 è iniziato alle 9:44 e finito alle 17:23 mentre br1 e cl1 si sono chiusi nell'arco del turno.

ora rova a lanciarla sul tuo e dimmi se ti da errori e se ti torna qualcosa...

maxbolz Profilo | Newbie

Caro Jok83, sei gentilissimo; non è facile trovare persone come te.
Purtroppo qui siamo costretti a usare Paradox, il cui sviluppo è stato
fermato 20 anni fa' circa e quindi non possiede costrutti del tipo
'case when'; supporta solo un set minimale di SQL92.
Inoltre, poichè i nostri clienti possono definire turni molto variabili
(chi due, chi tre, chi lavora in modo continuato), penso che la soluzione
sia proprio quella di costruire i record ad hoc man mano che viene popolata
la tabella, in modo che la query di raccolta dati tenga solo in considerazione
il range temporale di ispezione selezionato dal cliente.
Dal punto di vista della velocità, l'applicativo di raccolta dati dal campo non ha
problemi a costruire una ulteriore tabella con i dati già 'ritagliati'.
Penso che questa sia la soluzione migliore, a meno di non cambiare il motore DB.
Di nuovo 1000 grazie per la tua disponibilità e auguri per il tuo lavoro.
Ciao, Massimo.

Jok83 Profilo | Junior Member

Purtroppo non conosco per nulla Paradox non ho altre vie, però se riesci a risolvere nell'inserimento è sicuramente la soluzione più congeniale.
Magari qualcuno più in gamba tra un pò ti posta una soluzione ancora più efficace...
Ciao e Buon Lavoro!
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