Ciclo in TransactSQL

giovedì 16 aprile 2015 - 22.31
Tag Elenco Tags  SQL Server 2008 R2

renarig Profilo | Expert

Ho un problema che con VBA a lato applicazione riuscirei a risolvere
con un semplice ciclo sul RecordSet.

Ma in questo caso devo farlo a lato DataBase ( SQLServer )
e non sono preparato.

Le 2 tabelle ridotte all'osso sono:

"Originale"
- IdOrig -- Key Autoincrementale
- Peiodicita - nvarchar(3)
- Desc1 - nvarchar(250)
Nel campo Periodicita sono ammessi soli i valori
--- Set
--- Men
( significa Settimanale e Mensile )

La seconda tabella si chiama "Replicata"
- OrigRef --- Numerico
- Data ------ DateTime
- Desc2 --- nvarchar(250)
( oltre naturalmente all' Id in questo momento ininfluente )

I record della tabella "Originale"
devono essere copiati/replicati nella tabella "Replicata"
in funzione della periodicita definita al campo Originale.Periodicita

se vogliamo esemplificare nella tabella "Originale" ho:
- IdOrig ------ Periodicita --------- Desc1 ------
-- 101 ------------- Set ------------- aaa
-- 102 ------------- Set ------------- bbb
-- 103 ------------- Set ------------- ccc
-- 104 ------------- Men ------------- ddd
-- 105 ------------- Set ------------- eee

Nella tabella "Replicata" ho:
- OrigRef --------- Data --------- Desc2 ---------
---- 101 -------- 31/03/2015 ------ aaa
---- 101 -------- 07/04/2015 ------ aaa

---- 102 -------- 06/04/2015 ------ bbb
---- 102 -------- 13/04/2015 ------ bbb

---- 103 -------- 25/04/2015 ------ ccc

---- 104 -------- 10/03/2015 ------ ddd
---- 104 -------- 10/04/2015 ------ ddd

oggi è il 16/04/2015 Devo creare una routine/Insert che aggiunga questi record alla "Replicata":
- OrigRef --------- Data --------- Desc2 ---------
---- 101 -------- 14/04/2015 ------ aaa
---- 101 -------- 21/04/2015 ------ aaa (Stop perche ha superato oggi )

---- 102 -------- 20/04/2015 ------ bbb (Stop perche ha superato oggi )

-------------------------------------- ( 103 nulla perche è gia a posto )

---- 104 -------- 10/05/2015 ------ ddd (Stop perche ha superato oggi)

---- 105 -------- 16/04/2015 ------ eee ( Non c'era nessun precedente quindi inserisce solo quello odierno )

Idee ???
Grazie

Segue il CreateTable di quanto sopra detto
USE [master] GO CREATE DATABASE [Demo] GO USE [Demo] GO CREATE TABLE [dbo].[Originale] ( [IdOrig] [int] IDENTITY(1,1) NOT NULL, [Periodicita] [nvarchar](3) NULL, [Desc1] [nvarchar](250) NULL ) ON [PRIMARY] GO CREATE TABLE [dbo].[Replicata] ( [OrigRef] [int] NULL, [Data] [datetime] NULL, [Desc2] [nvarchar](250) NULL, [IdReplic] [int] IDENTITY(1,1) NOT NULL ) ON [PRIMARY] GO SET IDENTITY_INSERT [dbo].[Originale] ON GO INSERT [dbo].[Originale] ([IdOrig], [Periodicita], [Desc1]) VALUES (101, N'Set', N'aaa'), (102, N'Set', N'bbb'), (103, N'Set', N'ccc'), (104, N'Men', N'ddd'), (105, N'Set', N'eee') SET IDENTITY_INSERT [dbo].[Originale] OFF GO INSERT [dbo].[Replicata] ([OrigRef], [Data], [Desc2]) VALUES (101, CAST(0x0000A46C00000000 AS DateTime), N'aaa'), (101, CAST(0x0000A47300000000 AS DateTime), N'aaa'), (102, CAST(0x0000A47200000000 AS DateTime), N'bbb'), (102, CAST(0x0000A47900000000 AS DateTime), N'bbb'), (103, CAST(0x0000A48500000000 AS DateTime), N'ccc'), (104, CAST(0x0000A45700000000 AS DateTime), N'ddd'), (104, CAST(0x0000A47600000000 AS DateTime), N'ddd') GO


alx_81 Profilo | Guru

Ciao renarig,
credo di essermi perso. Ho capito che hai una tabella "Originale" ed una "Replicata", ho capito che hai un campo periodicita che dovrebbe discriminare l'inserimento, credo di aver capito che gli inserimenti debbano essere fatti FINO AD UNA DATA (nel tuo esempio, il 16 aprile). Ma mi manca la f(x).. mi manca la discriminante delle insert che ti servono. Purtroppo sono decontestualizzato, e nonostante i tuoi sforzi per la spiegazione (che apprezzo, tanta gente nemmeno mette gli script come hai fatto tu), non sono certo dei requisiti.
Ho preparato un SQLFiddle con le tue create table.
Vediamo di mettere a posto queste regole, se necessario:

- per ogni record di Originale leggo la periodicità
- se è settimanale, inserisco n record nella Replicata, dove n è il numero di date che stanno tra la data del record di Originale e la data X, con step di 7 giorni
- se è mensile, inserisco n record nella Replicata, dove n è il numero di date che stanno tra la data del record di Originale e la data X, con step di un mese
- se la data X è antecedente la data di Originale, non faccio nulla

Si tratta di questo?
grazie,
ciao
Alessandro Alpi | SQL Server MVP
MCP|MCITP|MCTS|MCT

http://blogs.dotnethell.it/suxstellino
http://suxstellino.wordpress.com
http://mvp.microsoft.com/en-us/mvp/Alessandro%20Alpi-4014222

renarig Profilo | Expert

>- se è settimanale, inserisco n record nella Replicata, dove n è il numero di date
>che stanno tra la data del record di Originale e la data X, con step di 7 giorni
> .......
>Si tratta di questo?

No, e quasi giusto ma devo spiegarmi meglio

Nella tabella originale non c'e nessuna data !!! solo la periodicita

quindi quella frase citata si traduce/corregge cosi:
- se è settimanale, inserisco n record nella Replicata, dove n è il numero di date
che stanno tra la Massima "data" del record di Replicata e la data X, con step di 7 giorni
( Dove la Massima "data" viene letta in GROUP BY sul campo "dbo.Replicata.OrigRef" )

Poi penso che non possiamo usare step(7) che andrebbe bene nelle settimanali.
ma nelle Mensili cosa ci metto ????

In Access esiste la comoda Funzione DateAdd(......) ma non so il corrispettivo del Transact


________________________________________________________________________

Detto molto più terra terra. Si tratta di gestione Edifici adebiti a uffici
Abbiamo un contratto di Manutenzione con una serie infinita di operazioni pianificate da eseguire
- Ogni settimana pulire le scale
- Ogni mese innaffiare i giardini
- Ogni giorno rilevare le temperature nelle sale riunioni

Nella tabella "Originale" c'è l'elenco delle operazioni da svolgere con la periodicita.
questo elenco non cambia MAI ( oppure solo raramente per adeguamenti contrattuali )

Nella tabella "Replicata" devo creare i singoli record delle singole operazioni con cadenza
periodica letta nel campo dbo.Originale.Periodicita

La tabella Replicata deve essere aggiornata a >Oggi
significa che se ho una annuale e la Max(data) nella Replicata è 15/02/2015
allora devo INSERTARE 15/02/2016

______________________________________________________________

Quindi io immagino qualcosa cosi:

-Un ciclo su tutti i record della tabella "Originale"
-Leggo IdOrig e Periodicita
-Trovo in "Replicata" la Max(Data) "WHERE dbo.Originale.IdOrig=dbo.Replicata.OrigRef"
-Valuto in funzione della Periodicita e data Odierna se necessario aggiungere dei record
-Solo se necessario faccio una INSERT in "Replicata"
-passo al prossimo record della Originale


Questa routine verra lanciata da applicazione in PassTrought

Grazie




renarig Profilo | Expert

Non pretendo che qualche "santo" mi scriva tutta la Routine.

In effetti ieri sera/notte sono gia arrivato a un certo punto
( i miei problemi sono più che altro di sintassi )

questa sera a mente fresca la controllo e la pubblico fino a dove sono arrivato
e vediamo insieme i dettagli/prblemi


Grazie

alx_81 Profilo | Guru

Se ho capito, qualcosa del genere come va?

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra
Alessandro Alpi | SQL Server MVP
MCP|MCITP|MCTS|MCT

http://blogs.dotnethell.it/suxstellino
http://suxstellino.wordpress.com
http://mvp.microsoft.com/en-us/mvp/Alessandro%20Alpi-4014222

renarig Profilo | Expert

Wowww!! Non ho parole
Io non ci sarei mai arrivato,
Ti devo 100 birre .....
è quasi perfetto ci sono solo 2 problemi marginali.

1)
Ti hai impostato la data del 31/05/2015
> DECLARE @EndDate AS date = '20150531';
e questo va bene, ma i record per ogni tipologia di servizio
vengono interrotti nella tabella "Replicata"
all'ultima data prima del 31/05/2015.
invece devono interrompersi alla prima data dopo il 31/05/2015

2)
Nel caso venga aggiunto un record alla tabella "Originale"
( è una cosa possibile ) noto che lo stesso non viene mai replicato
perché manca il corrispettivo nella tabella "Replicata".
Invece in quel caso il nuovo record deve essere INSERTITO
una sola volta nella "Replicata" con data odierna GETDATE()
Questo aspetto diventa molto più rilevante alla inizializzazione
del DB quando la "Originale" è popolata
mentre la "Replicata" è ancora vuota


Grazie
Mancini


alx_81 Profilo | Guru

>Wowww!! Non ho parole
>Io non ci sarei mai arrivato,
>Ti devo 100 birre .....
>è quasi perfetto ci sono solo 2 problemi marginali.
menomale.. riesci a finirlo tu o te lo correggo?
Alessandro Alpi | SQL Server MVP
MCP|MCITP|MCTS|MCT

http://blogs.dotnethell.it/suxstellino
http://suxstellino.wordpress.com
http://mvp.microsoft.com/en-us/mvp/Alessandro%20Alpi-4014222

renarig Profilo | Expert

>menomale.. riesci a finirlo tu o te lo correggo?

Oggi e domani che sono libero mi metto di impegno.
se riesco io sono anche più contento perché intanto lo capisco e imparo
eventualmente lunedì mattina ti faccio sapere se non riesco

Intanto accetto la risosta sopra perché è di fatto il 98% della soluzione

Grazie

renarig Profilo | Expert

> .... Oggi e domani che sono libero mi metto di impegno. ....
Mi è rimasto vivo solamente un neurone ........
pero forse sono arrivato a una conclusione

Confesso che innanzitutto ho tentato di mettere a posto quei problemini
sul tuo codice ma non sono riuscito.
Quei 3/4 cicli nidificati mi mandavano nel pallone il mio povero cervellino

allora ho ricominciato dall'inizio seguendo la strada
che avrei usato in VBA con un RecordSet ( Cursore )
e sembra che funziona.

Chiaramente non penso assolutamente che sia migliore del tuo,
Sarei ubriaco se lo pensassi, il primo ciclo in TSQL che faccio
su un ripiego perché non sono riuscito a sistemarne un altro

Poi ho usato un Cursore che ho letto da qualche parte che è deprecato.

Lo posto sotto, prova a dargli una occhiata "esperta" per capire l' andazzo
Puoi dirmi tranquillamente tutto quello che non va


Poi sarei molto curioso di vedere il tuo codice perfezionato
per eliminare i 2 problemini, per cui alla tua domanda
se devi corregermelo, a questo punto rispondo di Si
se non è troppo lavoro

Grazie
Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

alx_81 Profilo | Guru

>Poi ho usato un Cursore che ho letto da qualche parte che è deprecato.
Deprecato no.. alcuni tipi sono deprecati, ma il cursore in sè no.. Diciamo che sarebbe meglio non usare in generale logiche iterative su db, solo che hai detto di essere costretto
Preferisco non usare il cursore in questo caso, così faccio la insert SET BASED alla fine di tutto.

>Poi sarei molto curioso di vedere il tuo codice perfezionato
>per eliminare i 2 problemini, per cui alla tua domanda
>se devi corregermelo, a questo punto rispondo di Si
>se non è troppo lavoro
Allora, in effetti era tardi quando ti ho risposto, e si vede
Ti ho rifatto il giro più documentato e semplificato.
Vedi se può andare:

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra
Alessandro Alpi | SQL Server MVP
MCP|MCITP|MCTS|MCT

http://blogs.dotnethell.it/suxstellino
http://suxstellino.wordpress.com
http://mvp.microsoft.com/en-us/mvp/Alessandro%20Alpi-4014222

renarig Profilo | Expert

Perfetto,
adesso lo ho capito anch'io e mi piace

Mi manca solo da rinominare i campi della demo e metterlo in servizio

Grazie infinite
Mancini

alx_81 Profilo | Guru

>Mi manca solo da rinominare i campi della demo e metterlo in servizio
facci sapere

Alessandro Alpi | SQL Server MVP
MCP|MCITP|MCTS|MCT

http://blogs.dotnethell.it/suxstellino
http://suxstellino.wordpress.com
http://mvp.microsoft.com/en-us/mvp/Alessandro%20Alpi-4014222

renarig Profilo | Expert

>facci sapere

è andato tutto bene, grazie
Mancini
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