Da qualche tempo mi sono imbarcato in una nuova avventgura lavorativa presso Planeta Informatica & Sistemi.
Planeta Informatica & Sistemi Srl nasce nel 2005 con la volontà di proporsi come partner prettamente tecnologico per fornire servizi e consulenza di eccellente qualità. La pluriennale esperienza dei tecnici che compongono il nostro organico garantiscono ai nostri clienti successi nei seguenti ambiti: Gestione documentale
Conservazione sostitutiva
Consulenza tecnologica
Consulenza bancaria

Anche questo mese prosegue la collaborazione con la rivista DEV: Questa volta si parla della gestione della visibilità e della profilazione utilizzando le caratteristiche di SQL Server.

Buona lettura

 

 

 

 

Negli ultimi giorni e nonostante le contromisure predisposte da chi ci ospita in queste pagine, si sono intensificati i commenti/spam che vedo comparire sul mio blog.
Per adesso mi limito a cancellarli più in fretta possibile, ma penso che ben presto sarò costretto ad inibire la possibilità di  lasciare commenti.

Peccato, era interessante avere qualche feedback dai lettori!

Filed under:

Il numero 130 di DEV in edicola nel mese di Giugno è in gran parte dedicato a SQL Server.
Nell'ambito di questo speciale, è presente un mio articolo che parla di alcuni aspetti relativi alla gestione della sicurezza del sistema che ospita il database server di Microsoft.
L'articolo è il primo di una mini-serie che ne vedrà altri due e che si pone l'obiettivo di analizzare a tuttocampo la questione della sicurezza di SQL Server.
Buona lettura

 

Filed under:

Da qualche tempo è stata pubblicata - da parte del ministero competente - la normativa che regola gli scambi di messaggistica elettronica con valenza legale: la posta elettronica certificata.

Per chi vuole saperne di più, e non se la sente di leggersi il burocratese del DPR, leggete qui.

 

Buona lettura

Filed under:

Il processo di progettazione di un database prevede la produzione di diversi diagrammi che rappresentano ciascuna delle sue fasi. I diagrammi sono di importanza considerevole poiché sono l'unico strumento possibile per condividere le linee intraprese con altre persone, magari non informatici.

L'ottava parte del corso che stò curando su DEV parla di queste problematiche: buona lettura.

Filed under:

Microsoft Excel è dotato di un componente chiamato Risolutore (in inglese Solver) che è in grado di trovare soluzioni a sistemi di funzioni di una certa complessità.
Il risolutore può essere utilizzato sia in maniera interattiva, che da codice, magari all'interno di una macro. Se lo si utilizza da codice è possibile fare in modo che esso non emetta nessun Message-Box (cosa che invece fa di default). La cosa che nella documentazione non è spiegata in alcun modo è come sia possibile interpretare il risultato dell'elaborazione se si è scelto di nascondere la messaggistica... La documentazione ufficiale non ne fa nessun accenno.

Dopo un po' di ricerche ho trovato su un NG la soluzione ai miei interrogativi. Ecco l'elenco dei codici di ritorno e le relative spiegazioni:

0. Solver found a solution. All constraints and optimality conditions are satisfied.
1. Solver has converged to the current solution. All constraints are satisfied.
2. Solver cannot improve the current solution. All constraints are satisfied.
3. Stop chosen when the maximum iteration limit was reached.
4. The Set Cell values do not converge.
5. Solver could not find a feasible solution.
6. Solver stopped at user's request.
7. The conditions for Assume Linear Model are not satisfied.
8. The problem is too large for Solver to handle.
9. Solver encountered an error value in a target or constraint cell.
10. Stop chosen when maximum time limit was reached.
11. There is not enough memory available to solve the problem.
12. Another Excel instance is using SOLVER.DLL. Try again later.
13. Error in model. Please verify that all cells and constraints are valid.

with 1 comment(s)
Filed under:

Quali sono gli errori più comuni che si commettono in fase di progettazione di una base dati?
A che punto ci si deve fermare con il processo di normalizzazione dei dati?
Cosa sono i Dead-Lock e come è possibile evitarli?
Seguendo quali criteri si deve procedere nella scelta del tipo da assgnare alle colonne di una tabella?

La risposta a questi quesiti e a tanti altri la trovate nella sesta parte del corso di Database design in edicola questo mese con DEV n. 126.

Buona lettura

Filed under:

Un lettore di questo blog che non si è firmato mi ha segnalato un comportamento anomalo nella stored procedure che ho pubblicato qualche tempo fa per calcolare il giorno di Pasqua.
L'anomalia segnalata è docuta ad una svista nel codice che compromette la correttezza del calcolo per gli anni precedenti al 2000. In pratica era presente un 16 anziché un 19...

Ecco la stored procedure riveduta e corretta:

CREATE PROCEDURE GetPasqua (
@Anno INT,
@Pasqua DATETIME OUTPUT)
AS
DECLARE @T1 INT
DECLARE @T2 INT
DECLARE @T3 INT
DECLARE @T4 INT
DECLARE @T5 INT
DECLARE @Var1 INT
DECLARE @Var2 INT
DECLARE @NumGG INT

SET @T1 = 0
SET @T2 = 0
SET @T3 = 0
SET @T4 = 0
SET @T5 = 0


IF @Anno < 1900 OR @Anno > 2199
BEGIN
RAISERROR ('La procedura gestisce solo le date comprese tra il 1500 ed il 2199', 16, 1)
END 

IF @Anno >= 1900 AND @Anno <= 2099
BEGIN
SET @Var1 = 24
SET @Var2 = 5
END
IF @Anno >= 2100 AND @Anno <= 2199
BEGIN
SET @Var1 = 24
SET @Var2 = 6
END


SET @T1 = @Anno % 19
SET @T2 = @Anno % 4
SET @T3 = @Anno % 7
SET @T4 = ((19 * @T1) + @Var1) % 30
SET @T5 = ((2 * @T2) + (4 * @T3) + (6 * @T4) + @Var2) % 7

SET @NumGG = 22 + @T4 + @T5

IF @NumGG <= 31
BEGIN
SET @Pasqua = CAST(CAST(@Anno AS VARCHAR(4)) + '03' + RIGHT('0' + CAST(@NumGG AS VARCHAR(2)), 2) AS DATETIME)
END ELSE
BEGIN
SET @NumGG = @NumGG - 31
SET @Pasqua = CAST(CAST(@Anno AS VARCHAR(4)) + '04' + RIGHT('0' + CAST(@NumGG AS VARCHAR(2)), 2) AS DATETIME)
END

RETURN(0)

La cosa interessante è che quel lettore mi ha suggerito un modo alternativo per ottenere il medesimo risultato allegando la stored procedure che riporto di seguito:

CREATE PROCEDURE GetPasqua (
@Anno INT,
@Pasqua DATETIME OUTPUT)
AS
DECLARE @Sec INT
DECLARE @H INT
DECLARE @I INT
DECLARE @J INT
DECLARE @L INT
DECLARE @Mese INT
DECLARE @Giorno INT

SET @Sec = @anno % 19
SET @H = (
24+19*@Sec) % 30
SET @I = @H - CEILING(@H/28)
set @J = (@ANNO + ceiling(@ANNO/4) + @I -13) % 7
SET @L = @i - @j
SET @Mese = 3 + ceiling((@l+40)/44)
SET @Giorno = @L + 28 -31*CEILING(@Mese/4)

IF @Mese > 3
BEGIN
SET @Pasqua = CAST(CAST(@Anno AS VARCHAR(4)) + '04' + RIGHT('0' + CAST(@Giorno AS VARCHAR(2)), 2) AS DATETIME)
END ELSE
BEGIN
SET @Pasqua = CAST(CAST(@Anno AS VARCHAR(4)) + '03' + RIGHT('0' + CAST(@Giorno AS VARCHAR(2)), 2) AS DATETIME)
END
RETURN(0)

 

Per chi, come me, effettua parecchie installazioni e disinstallazioni sul proprio computer, non è raro che si arrivi ad un punto in cui il sistema non funziona più correttamente.
Mi è capitato parecchie volte di ricevere un messaggio che più o meno diceva "Una precedente installazione ha lasciato operazioni su file in sospeso. Riavviare il computer prima di effetuare l'installazione".
Inutile dire che - anche riavviando il pc - il messaggio si ripresenta uguale!
Il problema (come accade spesso) è un problema di registry: una chiave che serve per rinominare o rimuovere i file in uso è rimasta sporca. Si tratta della chiave
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperation.
Per aggirare il problema è sufficente eliminare o rinominare questa chiave.

Lorenzo
Filed under:
Prosegue anche questo mese la rassegna dedicata alle tecniche di progettazione delle basi dati che stò curando per la rivista DEV. In questa puntata - la sesta della serie che ne comprenderà alla fine dieci - si parla delle business rule. Fino a che livello è possibile specificare le logiche delle applicazioni direttamente a livello di database? Che vantaggi si ottengono con l'introduzione delle BR nel DB?
Queste sono tutte domande alle quali l'articolo in edicola questo mese fornisce una risposta...
Buona lettura!
Filed under:

Ci sono almeno due algoritmi con cui - chi prima, chi poi - tutti ci siamo trovati a doverci confrontare:

  • Il calcolo del codice fiscale,
  • il calcolo del Lunedì di Pasqua

Sul primo si è scritto molto, ed io stesso ho contribuito ad aumentare le pagine ad esso dedicato pubblicando su Visual Basic & .NET Journal l'articolo "Calcolo del codice fiscale in VB6" nei primi mesi del 2004.
Sulla  Pasqua, invece, si trovano molti meno esempi ed articoli, tantè che spesso si tende ad inserire nei propri programmi un elenco dei giorni di Pasqua dei successivi 20 anni senza implmentare alcun algoritmo di calcolo.

Provo a colmare questa lacuna, anche se - come si vedrà - l'algoritmo risulta essere parecchio empirico e richiede "aggiustamenti" per poter funzionare correttamente.
In generale diciamo che

  1. Il giorno di Pasqua (e di conseguenza il Lunedì di Pasqua) cade nella prima Domenica che succede al plenilunio immediatamente successivo all'equinozio di primavera.
  2. per ragioni astronomiche la data può variare tra il 22 di Marzo ed il 25 di Aprile

Il calcolo si basa su tre variabili, due delle quali sono il risultato di una tabella compilata a priori e statica che ha lo scopo di "aggiustare" il calcolo, la terza è l'anno del quale si vuole conoscere la data del giorno di Pasqua.

1583-1699 22 2
1700-1799 23 3
1800-1899 23 4
1900-2099 24 5
2100-2199 24 6
2200-2299 25 0
2300-2399 26 1

Possedendo i dati di questa tabella, è sufficiente  eseguire cinque divisioni e considerare i loro resti per ottenere il risultato.desiderato. Come si vede dall'esempio che riporto di seguito, il risultato è un numero che può essere superiore o inferiore a 31. Se è inferiore a 31, allora si considera quel numero come il giorno del mese di Marzo, in caso contrario, si sottre 31 e si considera come mese Aprile.

Riporto qui di seguito una stored procedure per SQL server che realizza tale algoritmo.

CREATE PROCEDURE GetPasqua (
@Anno INT,
@Pasqua DATETIME OUTPUT)
AS
DECLARE @T1 INT
DECLARE @T2 INT
DECLARE @T3 INT
DECLARE @T4 INT
DECLARE @T5 INT
DECLARE @Var1 INT
DECLARE @Var2 INT
DECLARE @NumGG INT

SET @T1 = 0
SET @T2 = 0
SET @T3 = 0
SET @T4 = 0
SET @T5 = 0


IF @Anno < 1900 OR @Anno > 2199
BEGIN
RAISERROR ('La procedura gestisce solo le date comprese tra il 1500 ed il 2199', 16, 1)
END 

IF @Anno >= 1900 AND @Anno <= 2099
BEGIN
SET @Var1 = 24
SET @Var2 = 5
END
IF @Anno >= 2100 AND @Anno <= 2199
BEGIN
SET @Var1 = 24
SET @Var2 = 6
END


SET @T1 = @Anno % 19
SET @T2 = @Anno % 4
SET @T3 = @Anno % 7
SET @T4 = ((19 * @T1) + @Var1) % 30
SET @T5 = ((2 * @T2) + (4 * @T3) + (6 * @T4) + @Var2) % 7

SET @NumGG = 22 + @T4 + @T5

IF @NumGG <= 31
BEGIN
SET @Pasqua = CAST(CAST(@Anno AS VARCHAR(4)) + '03' + RIGHT('0' + CAST(@NumGG AS VARCHAR(2)), 2) AS DATETIME)
END ELSE
BEGIN
SET @NumGG = @NumGG - 31
SET @Pasqua = CAST(CAST(@Anno AS VARCHAR(4)) + '04' + RIGHT('0' + CAST(@NumGG AS VARCHAR(2)), 2) AS DATETIME)
END

RETURN(0)

Lascio a voi l'esercizio di realizzare la stessa procedura con altri linguaggi di programmazione...Buon divertimento!

Volete avvicinarvi ad ASP.NET e non sapete da dove cominciare?
Conoscete ADO e volete passare ad ADO.NET?
Volete farvi un'idea sui Web Services?

Insomma, se siete ai primi passi e non volete perdere tempo, non potete perdervi le guide How Do I?
Le trovate a questo indirizzo samples.gotdotnet.com/quickstart/howto

Buona lettura!

Lorenzo
Filed under:

Mi è successo di incappare in un errore riportato da SQL Server che - a mio modesto parere - se non è un buco, è quantomeno poco chiaro e rischia di trarre in inganno il DBA.
L'errore si presenta nelle situazioni in cui si definiscono diverse relazioni di integrità referenziale residenti sulla stessa tabella ed aventi come "padre" una seconda tabella.
I books on line parlano di una situazione analoga a quella che vado a descrivere solo nel caso di relazioni autoreferenzianti. In quel caso è vero che la situazione può prendere strade che portano ad un loop, ma in questo caso no!

Ma vediamo di capire bene di cosa stò parlando con un esempio... 

Supponiamo di avere due tabelle (Ordini ed Utenti) aventi la struttura riportata di seguito:

use [Test_DB]
GO

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[Ordini]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[Ordini]
GO

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[Utenti]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[Utenti]
GO


CREATE TABLE [dbo].[Ordini] (
[OrdineID] [int] NOT NULL ,
[Data] [datetime] NULL ,
[UtenteInserimento] [int] NULL ,
[UtenteAggiornamento] [int] NULL 
) ON [PRIMARY]
GO

CREATE TABLE [dbo].[Utenti] (
[UtenteID] [int] NOT NULL ,
[Cognome] [varchar] (50) COLLATE Latin1_General_CI_AS NULL ,
[Nome] [varchar] (50) COLLATE Latin1_General_CI_AS NULL 
) ON [PRIMARY]
GO

Una volta definite le tabelle, passiamo ad inserire le loro chiavi primarie.

ALTER TABLE [dbo].[Ordini] WITH NOCHECK ADD 
CONSTRAINT [PK_Ordini] PRIMARY KEY CLUSTERED 
(
[OrdineID]
) ON [PRIMARY] 
GO

ALTER TABLE [dbo].[Utenti] WITH NOCHECK ADD 
CONSTRAINT [PK_Utenti] PRIMARY KEY CLUSTERED 
(
[UtenteID]
) ON [PRIMARY] 
GO

A questo punto, diciamo che vogliamo porre qualche vincolo  allo scopo di garantire l'integrità dei dati presenti nelle due tabelle. La cosa più semplice e lineare sarebbe quella di inserire due foreign key per i campi UtenteInserimento ed UtenteAggiornamento vincolandoli al campo UtenteID della relativa tabella.
Se però vogliamo dare  ai nostri utenti la possibilità di modificare il codice identificativo degli utenti anche dopo che essi hanno inserito e/o aggiornato degli ordini, la definizione delle relazioni dovrà essere come riportato di seguito:

ALTER TABLE [dbo].[Ordini] ADD 
CONSTRAINT [FK_Ordini_Utenti_Inserimento] FOREIGN KEY 
(
[UtenteInserimento]
) REFERENCES [dbo].[Utenti] (
[UtenteID]
) ON DELETE CASCADE ON UPDATE CASCADE 
GO

ALTER TABLE [dbo].[Ordini] ADD 
CONSTRAINT [FK_Ordini_Utenti_Aggiornamento] FOREIGN KEY 
(
[UtenteAggiornamento]
) REFERENCES [dbo].[Utenti] (
[UtenteID]
) ON DELETE CASCADE ON UPDATE CASCADE 
GO

Specificando le clausole ON DELETE e ON UPDATE, infatti, si ottiene la propagazione automatica su tutti i record referenziati delle eventuali modifiche e cancellazioni svolte sulla tabella  Utenti.

Se, però, si esegue quest'ultima parte dello script si ottiene il seguente errore:

Server: messaggio 1785, livello 16, stato 1, riga 1
L'impostazione del vincolo FOREIGN KEY 'FK_Ordini_Utenti_Aggiornamento' nella tabella 'Ordini' potrebbe generare cicli o percorsi a catena multipla. Specificare ON DELETE NO ACTION oppure ON UPDATE NO ACTION oppure modificare altri vincoli FOREIGN KEY.
Server: messaggio 1750, livello 16, stato 1, riga 1
Impossibile creare il vincolo. Vedere gli errori precedenti.

Analizzando la struttura (molto semplice, per la verità) delle due tabelle, è evidente che non c'è alcun rischio di ciclo o di percorso multiplo come invece ci segnala l'RDBMS di Microsoft.

Soluzione
Non esiste una soluzione "pulita": SQL Server 2000 non supporta questo tipo di integrità referenziale "multipla". Faccio notare, però, che RDBMS come Oracle o addirittura Access la supportano tranquillamente...
L'unica scappatoia che si presenta è quella di implmentare l'integrità referenziale non con le relazioni bensì con i trigger.

Lorenzo Braidi
...acquista "Database Design", il mio primo libro!

Filed under: ,
Prosegue anche questo mese il corso di Database Design che stò tenendo su DEV nella rubrica "Programmo subito". Questa lezione è interamente dedicata alle viste: cosa sono, a cosa servono, come si definiscono, ecc.


Nei mesi scorsi (a Marzo) è uscito su Visual Basic Journal un mio articolo che illustrava l'algoritmo che si utilizza per calcolare e validare un codice fiscale. Allegato a quell'articolo c'era anche un piccolo progettino VB6 che implementava l'algoritmo oggetto dell'articolo. Un lettore si è accorto di un caso particolare nel quale il software suddetto non funzionava correttamente. Nel numero di VBJ di questo mese è pubblicata la correzione di tale baco. Comunque, il software che si scarica dal sito FTP di Infomedia è stato immediatamente corretto...
Filed under: ,
More Posts Next page »