<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>GianfraSoft</title>
	<atom:link href="http://gianfrasoft.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://gianfrasoft.wordpress.com</link>
	<description>yet another software developer</description>
	<lastBuildDate>Tue, 19 Apr 2011 06:14:51 +0000</lastBuildDate>
	<language>it</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='gianfrasoft.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>GianfraSoft</title>
		<link>http://gianfrasoft.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://gianfrasoft.wordpress.com/osd.xml" title="GianfraSoft" />
	<atom:link rel='hub' href='http://gianfrasoft.wordpress.com/?pushpress=hub'/>
		<item>
		<title>Fondamenti PHP5 &#8211; dipense del corso</title>
		<link>http://gianfrasoft.wordpress.com/2008/11/02/corso-di-php5/</link>
		<comments>http://gianfrasoft.wordpress.com/2008/11/02/corso-di-php5/#comments</comments>
		<pubDate>Sun, 02 Nov 2008 11:36:07 +0000</pubDate>
		<dc:creator>gianfrasoft</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[corso]]></category>
		<category><![CDATA[corso di PHP5]]></category>
		<category><![CDATA[fondamenti]]></category>
		<category><![CDATA[PHP5]]></category>
		<category><![CDATA[programmazione]]></category>
		<category><![CDATA[sicurezza]]></category>

		<guid isPermaLink="false">http://gianfrasoft.wordpress.com/?p=24</guid>
		<description><![CDATA[Pubblico, a beneficio dei partecipanti, le dispense del corso di 24 ore su PHP5 tenuto a Roma presso Lottomatica S.p.A. Nell&#8217;ambito del corso vengono trattati il paradigma di programmazione web, le strutture principali del linguaggio PHP5, la programmazione ad oggetti. Inoltre, si fa riferimento costante ai problemi legati alla sicurezza ed allo stile di programmazione [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gianfrasoft.wordpress.com&amp;blog=2822728&amp;post=24&amp;subd=gianfrasoft&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Pubblico, a beneficio dei partecipanti, le dispense del corso di 24 ore su PHP5 tenuto a Roma presso Lottomatica S.p.A.</p>
<p>Nell&#8217;ambito del corso vengono trattati il paradigma di programmazione web, le strutture principali del linguaggio PHP5, la programmazione ad oggetti. Inoltre, si fa riferimento costante ai problemi legati alla sicurezza ed allo stile di programmazione che previene le principali modalità di attacco ai siti realizzati in PHP: <em>SQL injection</em>, <em>session fixation</em>, ecc.</p>
<p><span id="more-24"></span><a href="http://rapidshare.com/files/159900274/Gianfrasoft_-_Corso_di_PHP_-_parte_1.pdf">Gianfrasoft &#8211; Corso di PHP &#8211; parte 1</a></p>
<p><a href="http://rapidshare.com/files/159900328/Gianfrasoft_-_Corso_di_PHP_-_parte_2.pdf">Gianfrasoft &#8211; Corso di PHP &#8211; parte 2</a></p>
<p><a href="http://rapidshare.com/files/159900360/Gianfrasoft_-_Corso_di_PHP_-_parte_3.pdf">Gianfrasoft &#8211; Corso di PHP &#8211; parte 3</a></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/gianfrasoft.wordpress.com/24/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/gianfrasoft.wordpress.com/24/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/gianfrasoft.wordpress.com/24/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/gianfrasoft.wordpress.com/24/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/gianfrasoft.wordpress.com/24/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/gianfrasoft.wordpress.com/24/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/gianfrasoft.wordpress.com/24/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/gianfrasoft.wordpress.com/24/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/gianfrasoft.wordpress.com/24/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/gianfrasoft.wordpress.com/24/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/gianfrasoft.wordpress.com/24/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/gianfrasoft.wordpress.com/24/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/gianfrasoft.wordpress.com/24/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/gianfrasoft.wordpress.com/24/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gianfrasoft.wordpress.com&amp;blog=2822728&amp;post=24&amp;subd=gianfrasoft&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://gianfrasoft.wordpress.com/2008/11/02/corso-di-php5/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/905a08842a0c78883ed66254de5fc75a?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">gianfrasoft</media:title>
		</media:content>
	</item>
		<item>
		<title>Personalizzare l&#8217;ordinamento di una query in SQL Server 2005 portando, in cima al risultato, il record col campo di ricerca uguale alla chiave.</title>
		<link>http://gianfrasoft.wordpress.com/2008/05/16/personalizzare-lordinamento-di-una-query-in-sql-server-2005-portando-in-cima-al-risultato-il-record-col-campo-di-ricerca-uguale-alla-chiave/</link>
		<comments>http://gianfrasoft.wordpress.com/2008/05/16/personalizzare-lordinamento-di-una-query-in-sql-server-2005-portando-in-cima-al-risultato-il-record-col-campo-di-ricerca-uguale-alla-chiave/#comments</comments>
		<pubDate>Fri, 16 May 2008 12:05:50 +0000</pubDate>
		<dc:creator>gianfrasoft</dc:creator>
				<category><![CDATA[Transact SQL]]></category>
		<category><![CDATA[alla]]></category>
		<category><![CDATA[campo di ricerca]]></category>
		<category><![CDATA[chiave.]]></category>
		<category><![CDATA[cima]]></category>
		<category><![CDATA[ordinamento]]></category>
		<category><![CDATA[Personalizzare]]></category>
		<category><![CDATA[query]]></category>
		<category><![CDATA[risultato]]></category>
		<category><![CDATA[SQL Server 2005]]></category>
		<category><![CDATA[uguale]]></category>

		<guid isPermaLink="false">http://gianfrasoft.wordpress.com/?p=16</guid>
		<description><![CDATA[Nell&#8217;ambito di una query di ricerca che, ad esempio, utilizza l&#8217;operatore LIKE vogliamo ottenere un risultato ordinato: per far ciò facciamo uso dell&#8217;operatore ORDER BY in questo modo: SELECT * FROM Tabella WHERE Tabella.Campo1 LIKE '%CHIAVE%' ORDER BY Tabella.Campo1 Se talora la chiave coincide esattamente col campo sul quale stiamo effettuando la ricerca, ovvero si [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gianfrasoft.wordpress.com&amp;blog=2822728&amp;post=16&amp;subd=gianfrasoft&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Nell&#8217;ambito di una query di ricerca che, ad esempio, utilizza l&#8217;operatore LIKE vogliamo ottenere un risultato ordinato: per far ciò facciamo uso dell&#8217;operatore ORDER BY in questo modo:</p>
<pre>SELECT
  *
FROM
  Tabella
WHERE
  Tabella.Campo1 LIKE '%CHIAVE%'
ORDER BY
  Tabella.Campo1</pre>
<p>Se talora la chiave coincide esattamente col campo sul quale stiamo effettuando la ricerca, ovvero si verifica che in almeno un record Tabella.Campo1 = &#8216;CHIAVE&#8217;, possiamo ottenere che il record che la contiene venga posizionato in testa alla query di ricerca sfruttando la clausaola ORDER BY CASE di SQL Server 2005 in questo modo:</p>
<p><span id="more-16"></span></p>
<pre>SELECT
  *
FROM
  Tabella
WHERE
  Tabella.Campo1 LIKE '%CHIAVE%'
ORDER BY
  CASE WHEN Tabella.Campo1 = 'CHIAVE' THEN 1 ELSE 2 END,
  Tabella.Campo1</pre>
<p>L&#8217;esempio è facilmente adattabile all&#8217;utilizzo con altri operatori.</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/gianfrasoft.wordpress.com/16/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/gianfrasoft.wordpress.com/16/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/gianfrasoft.wordpress.com/16/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/gianfrasoft.wordpress.com/16/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/gianfrasoft.wordpress.com/16/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/gianfrasoft.wordpress.com/16/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/gianfrasoft.wordpress.com/16/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/gianfrasoft.wordpress.com/16/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/gianfrasoft.wordpress.com/16/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/gianfrasoft.wordpress.com/16/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/gianfrasoft.wordpress.com/16/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/gianfrasoft.wordpress.com/16/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/gianfrasoft.wordpress.com/16/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/gianfrasoft.wordpress.com/16/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/gianfrasoft.wordpress.com/16/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/gianfrasoft.wordpress.com/16/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gianfrasoft.wordpress.com&amp;blog=2822728&amp;post=16&amp;subd=gianfrasoft&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://gianfrasoft.wordpress.com/2008/05/16/personalizzare-lordinamento-di-una-query-in-sql-server-2005-portando-in-cima-al-risultato-il-record-col-campo-di-ricerca-uguale-alla-chiave/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/905a08842a0c78883ed66254de5fc75a?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">gianfrasoft</media:title>
		</media:content>
	</item>
		<item>
		<title>Una stored procedure per la duplicazione delle righe di una tabella generica</title>
		<link>http://gianfrasoft.wordpress.com/2008/04/25/una-stored-procedure-per-la-duplicazione-delle-righe-di-una-tabella-generica/</link>
		<comments>http://gianfrasoft.wordpress.com/2008/04/25/una-stored-procedure-per-la-duplicazione-delle-righe-di-una-tabella-generica/#comments</comments>
		<pubDate>Fri, 25 Apr 2008 08:29:14 +0000</pubDate>
		<dc:creator>gianfrasoft</dc:creator>
				<category><![CDATA[Transact SQL]]></category>
		<category><![CDATA[COLUMNS]]></category>
		<category><![CDATA[duplicazione]]></category>
		<category><![CDATA[generica]]></category>
		<category><![CDATA[INFORMATION_SCHEMA]]></category>
		<category><![CDATA[righe]]></category>
		<category><![CDATA[tabella]]></category>
		<category><![CDATA[Una stored procedure per la duplicazione delle righe di]]></category>

		<guid isPermaLink="false">http://gianfrasoft.wordpress.com/?p=13</guid>
		<description><![CDATA[Duplicare la riga di una tabella è una operazione sempre possibile ma spesso non immediata: la tabella in questione può essere caratterizzata dalla presenza di una chiave univoca che coinvolga uno o più campi, da campi NOT NULL che vanno valorizzati talora con i propri valori di default, ecc&#8230; Lo script INSERT che effettua l&#8217;inserimento [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gianfrasoft.wordpress.com&amp;blog=2822728&amp;post=13&amp;subd=gianfrasoft&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Duplicare la riga di una tabella è una operazione sempre possibile ma spesso non immediata: la tabella in questione può essere caratterizzata dalla presenza di una chiave univoca che coinvolga uno o più campi, da campi NOT NULL che vanno valorizzati talora con i propri valori di default, ecc&#8230;</p>
<p>Lo script INSERT che effettua l&#8217;inserimento di una riga duplicata deve, nella maggior parte dei casi, specificare la lista dei campi da caricare nel nuovo record e questo perché lo script non deve definire valori duplicati per i campi chiave, se richiesto non deve sovrascrivere i valori di default, non deve definire valori per i campi auto-incrementali e quant&#8217;altro.</p>
<p>Consideriamo il caso, piuttosto diffuso, di tabelle caratterizzate da una chiave primaria composta da un campo auto-incrementale, e realizziamo una procedura che:</p>
<ul>
<li>sia in grado di semplificare l&#8217;operazione di duplicazione della riga di una tabella, agendo indipendentemente dalla struttura della stessa;</li>
<li>restituisca l&#8217;indice univoco del campo chiave del nuovo record;</li>
<li>non valorizzi i campi che hanno valori di default;</li>
<li>agisca su una qualsiasi tabella dove sia presente una chiave primaria composta da un campo auto-incrementale.</li>
</ul>
<p><span id="more-13"></span></p>
<p>Il cuore della procedura è nella generazione al volo di uno script di insert completo della lista esplicita di tutti i campi della tabella su cui andiamo a duplicare il record. La lista dei campi viene recuperata mediante la view di sistema INFORMATION_SCHEMA mentre una chiamata alla stored procedure di sistema sp_executesql permetterà di eseguire lo script INSERT appena creato.</p>
<p>La procedura in questione esporrà, pertanto, tra i parametri:</p>
<ol>
<li>il nome della tabella della quale s&#8217;intende duplicare una riga,</li>
<li>il nome del campo chiave,</li>
<li>l&#8217;id univoco della riga che si vuole duplicare</li>
</ol>
<p>e restituirà l&#8217;id del record duplicato generato. Ecco il codice commentato:</p>
<pre><span style="font-family:Courier New;">IF EXISTS (SELECT SPECIFIC_NAME FROM INFORMATION_SCHEMA.ROUTINES WHERE SPECIFIC_NAME = 'ClonaRecord')</span>
<span style="font-family:Courier New;"> DROP PROCEDURE dbo.ClonaRecord</span>
<span style="font-family:Courier New;">GO

</span><span style="font-family:Courier New;">CREATE PROCEDURE dbo.ClonaRecord(</span>
<span style="font-family:Courier New;">  @Tabella varchar(90),</span>
<span style="font-family:Courier New;">  @NomeCampoID varchar(90),</span>
<span style="font-family:Courier New;">  @IDSorgente varchar(16), </span>
<span style="font-family:Courier New;">  @IDDestinazione varchar(16) OUTPUT</span>
<span style="font-family:Courier New;">) AS</span>
<span style="font-family:Courier New;">BEGIN</span>
<span style="font-family:Courier New;">  DECLARE @ErrMsg nvarchar(4000), @ErrSeverity int</span>
<span style="font-family:Courier New;">  IF @IDSorgente IS NULL</span>
<span style="font-family:Courier New;">  BEGIN</span>
<span style="font-family:Courier New;">    SET @IDDestinazione = 'ERROR'</span>
<span style="font-family:Courier New;">    </span>
<span style="font-family:Courier New;">    -- Verifica che il campo </span><span><span style="font-family:Courier New;">@NomeCampoID </span></span><span style="font-family:Courier New;">non sia nullo. Se lo è, solleva un'eccezione</span>
<span style="font-family:Courier New;">    SELECT @ErrMsg = 'Errore nei parametri - ' + @NomeCampoID + ' nullo.',</span>
<span style="font-family:Courier New;">          @ErrSeverity = 1</span>
<span style="font-family:Courier New;">    RAISERROR(@ErrMsg, @ErrSeverity, 1)</span>
<span style="font-family:Courier New;">    RETURN</span>
<span style="font-family:Courier New;">  END</span>
<span style="font-family:Courier New;">  </span>
<span style="font-family:Courier New;">  DECLARE @i int</span>
<span style="font-family:Courier New;">  DECLARE @Script nvarchar(max)</span>
<span style="font-family:Courier New;">  </span>
<span style="font-family:Courier New;">  -- PROCESSAMENTO --</span>
<span style="font-family:Courier New;">  BEGIN TRY
   </span> -- La procedura lavora con le transazioni
    <span style="font-family:Courier New;">BEGIN TRANSACTION</span>
<span style="font-family:Courier New;">    </span>
<span style="font-family:Courier New;">    DECLARE @IDValue varchar(100)</span><span style="font-family:Courier New;"> </span>
<span style="font-family:Courier New;">    DECLARE @Fields nvarchar(max)</span>
<span style="font-family:Courier New;">    DECLARE @Ordinal integer</span>
<span style="font-family:Courier New;">    </span>
<span style="font-family:Courier New;">    SET @Script = ''</span>
<span style="font-family:Courier New;">
</span>    -- La procedura inoltre accede alla view di sistema <span><span style="font-family:Courier New;">INFORMATION_SCHEMA
    -- per recuperare la lista dei campi indispensabili per la generazione
    -- dello script di INSERT
</span></span><span style="font-family:Courier New;">    SELECT @Ordinal = MIN(ORDINAL_POSITION) FROM </span>
<span style="font-family:Courier New;">      INFORMATION_SCHEMA.COLUMNS</span>
<span style="font-family:Courier New;">      WHERE TABLE_NAME = @Tabella</span>
<span style="font-family:Courier New;">    </span>
<span style="font-family:Courier New;">    WHILE @Ordinal IS NOT NULL</span>
<span style="font-family:Courier New;">    BEGIN</span>
<span style="font-family:Courier New;">      SELECT @IDValue = COLUMN_NAME FROM </span>
<span style="font-family:Courier New;">        INFORMATION_SCHEMA.COLUMNS</span>
<span style="font-family:Courier New;">        WHERE TABLE_NAME = @Tabella</span>
<span style="font-family:Courier New;">        AND ORDINAL_POSITION = @Ordinal</span>
<span style="font-family:Courier New;">
</span>      -- Un ciclo sul recordset individuato nella view <span><span><span style="font-family:Courier New;">INFORMATION_SCHEMA
      -- permette di popolare la stringa </span></span></span><span><span style="font-family:Courier New;">@Fields</span></span><span><span><span style="font-family:Courier New;"> destinate a contenere la
      -- lista dei campi </span></span></span>
<span style="font-family:Courier New;">      IF @IDValue &lt;&gt; @NomeCampoID</span>
<span style="font-family:Courier New;">      BEGIN</span>
<span style="font-family:Courier New;">        IF @Fields IS NULL</span>
<span style="font-family:Courier New;">          SET @Fields = @IDValue</span>
<span style="font-family:Courier New;">        ELSE</span>
<span style="font-family:Courier New;">          SET @Fields = @Fields + ', ' + @IDValue</span>
<span style="font-family:Courier New;">      END</span>
<span style="font-family:Courier New;">      </span>
<span style="font-family:Courier New;">      SELECT @Ordinal = MIN(ORDINAL_POSITION) FROM </span>
<span style="font-family:Courier New;">        INFORMATION_SCHEMA.COLUMNS</span>
<span style="font-family:Courier New;">        WHERE TABLE_NAME = @Tabella</span>
<span style="font-family:Courier New;">        AND ORDINAL_POSITION &gt; @Ordinal</span>
<span style="font-family:Courier New;">        AND COLUMN_DEFAULT IS NULL  -- * NEW * --</span>
<span style="font-family:Courier New;">    END</span>
<span style="font-family:Courier New;">
</span>    -- Ecco finalmente lo script INSERT che viene generato al volo nell'ambito
    -- della stringa @Script di dimensioni<span style="font-family:Courier New;"> </span><span><span style="font-family:Courier New;">nvarchar(max)
   </span></span> <span style="font-family:Courier New;">SET @Script = 'INSERT INTO ' + @Tabella + ' (' + @Fields + ')' +</span>
<span style="font-family:Courier New;">      ' SELECT ' + @Fields + ' FROM ' + @Tabella + </span>
<span style="font-family:Courier New;">      ' WHERE ' + @NomeCampoID + ' = ''' + @IDSorgente + ''''</span>
<span style="font-family:Courier New;">    </span>
<span style="font-family:Courier New;">    -- Lo script viene eseguito
  </span><span style="font-family:Courier New;">  EXECUTE sp_executesql @Script</span>
<span style="font-family:Courier New;">
</span>    -- Nella variabile <span><span style="font-family:Courier New;">@IDDestinazione viene conservato l'IDENTITY del nuovo
    -- record
</span></span><span style="font-family:Courier New;">    SET @IDDestinazione = @@IDENTITY</span>
<span style="font-family:Courier New;">    </span>
<span style="font-family:Courier New;">    COMMIT TRANSACTION</span>
<span style="font-family:Courier New;">  END TRY</span>
<span style="font-family:Courier New;">  BEGIN CATCH</span>
<span style="font-family:Courier New;">    IF @@TRANCOUNT &gt; 0</span>
<span style="font-family:Courier New;">      ROLLBACK</span>
<span style="font-family:Courier New;">    </span>
<span style="font-family:Courier New;">    SET @IDDestinazione = 'ERROR'</span>
<span style="font-family:Courier New;">    </span>
<span style="font-family:Courier New;">    -- Se </span><span><span style="font-family:Courier New;">@IDDestinazione non è stato popolato, solleva un'eccezione</span></span>
<span style="font-family:Courier New;">    SELECT @ErrMsg = ERROR_MESSAGE(),</span>
<span style="font-family:Courier New;">      @ErrSeverity = ERROR_SEVERITY()</span>
<span style="font-family:Courier New;">    RAISERROR(@ErrMsg, @ErrSeverity, 1)</span>
<span style="font-family:Courier New;">  END CATCH  </span>
<span style="font-family:Courier New;">END</span>
<span style="font-family:Courier New;">GO</span></pre>
<p>Un esempio di chiamata alla procedura appena descritta è riportata di seguito:</p>
<pre>DECLARE @IDDestinazione varchar(16);
EXECUTE dbo.DuplicateRecord 'test', 'id', '6', @IDDestinazione OUTPUT
PRINT 'Nuovo id: ' + @IDDestinazione</pre>
<p>dove alla chiamata segue la stampa nello standard output di SQL Server dell&#8217;id univoco del record appena generato.</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/gianfrasoft.wordpress.com/13/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/gianfrasoft.wordpress.com/13/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/gianfrasoft.wordpress.com/13/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/gianfrasoft.wordpress.com/13/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/gianfrasoft.wordpress.com/13/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/gianfrasoft.wordpress.com/13/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/gianfrasoft.wordpress.com/13/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/gianfrasoft.wordpress.com/13/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/gianfrasoft.wordpress.com/13/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/gianfrasoft.wordpress.com/13/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/gianfrasoft.wordpress.com/13/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/gianfrasoft.wordpress.com/13/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/gianfrasoft.wordpress.com/13/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/gianfrasoft.wordpress.com/13/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/gianfrasoft.wordpress.com/13/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/gianfrasoft.wordpress.com/13/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gianfrasoft.wordpress.com&amp;blog=2822728&amp;post=13&amp;subd=gianfrasoft&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://gianfrasoft.wordpress.com/2008/04/25/una-stored-procedure-per-la-duplicazione-delle-righe-di-una-tabella-generica/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/905a08842a0c78883ed66254de5fc75a?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">gianfrasoft</media:title>
		</media:content>
	</item>
		<item>
		<title>Generare un recordset contenente tutti gli elementi di un intervallo in SQL Server 2005</title>
		<link>http://gianfrasoft.wordpress.com/2008/04/13/generare-un-recordset-contenente-tutti-gli-elementi-di-un-intervallo-in-sql-server-2005/</link>
		<comments>http://gianfrasoft.wordpress.com/2008/04/13/generare-un-recordset-contenente-tutti-gli-elementi-di-un-intervallo-in-sql-server-2005/#comments</comments>
		<pubDate>Sun, 13 Apr 2008 16:13:36 +0000</pubDate>
		<dc:creator>gianfrasoft</dc:creator>
				<category><![CDATA[Transact SQL]]></category>
		<category><![CDATA[Common Table Expression]]></category>
		<category><![CDATA[CTE]]></category>
		<category><![CDATA[date]]></category>
		<category><![CDATA[elementi]]></category>
		<category><![CDATA[Generare un recordset contenente]]></category>
		<category><![CDATA[interval]]></category>
		<category><![CDATA[intervallo]]></category>
		<category><![CDATA[SQL Server 2005]]></category>

		<guid isPermaLink="false">http://gianfrasoft.wordpress.com/?p=12</guid>
		<description><![CDATA[Talvolta ci si trova a dover incrociare i dati di una query con le date di uno specifico intervallo. Ad esempio, consideriamo una tabella che contiene le vendite effettuate da un&#8217;azienda nell&#8217;arco di un anno: vogliamo rappresentare in un recordset gli importi totali delle vendite di ogni mese. La questione si risolve con un semplice [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gianfrasoft.wordpress.com&amp;blog=2822728&amp;post=12&amp;subd=gianfrasoft&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Talvolta ci si trova a dover incrociare i dati di una query con le date di uno specifico intervallo.</p>
<p>Ad esempio, consideriamo una tabella che contiene le vendite effettuate da un&#8217;azienda nell&#8217;arco di un anno: vogliamo rappresentare in un recordset gli importi totali delle vendite di ogni mese. La questione si risolve con un semplice raggruppamento dati, ammenocché non si voglia riportare un importo nullo <span style="text-decoration:underline;">anche in corrispondenza dei mesi in cui non sono state effettuate vendite</span>.</p>
<p>La soluzione ideale è quella di effettuare il raggruppamento dopo avere incrociato i dati delle vendite con un recordset contenente una riga per ciascuna data di inizio o di fine mese. Questo è possibile generando una tabella temporanea e popolandola, prima di effettuare la query sulle vendite.</p>
<p>Un&#8217;alternativa che agisca <em>on the fly</em> è quella basata sulle <strong>CTE</strong> ovvero <strong>Common Table Expression</strong>: le CTE consentono di effettuare query SQL di tipo ricorsivo, che è proprio quanto a noi serve.</p>
<p><span id="more-12"></span></p>
<p>Nell&#8217;esempio seguente, ho realizzato uno script SQL che produce un recordset contenente tutte le date di tipo inizio mese che coprono il periodo che va dall&#8217;01/01/2007 all&#8217;01/01/2008:</p>
<pre><span style="font-family:Courier New;">WITH CTE(X)</span><span style="font-family:Courier New;">
AS</span><span style="font-family:Courier New;">
(</span><span style="font-family:Courier New;">
  SELECT X = convert(datetime, '20070101')</span><span style="font-family:Courier New;">
</span><span style="font-family:Courier New;"> </span><span style="font-family:Courier New;"> UNION ALL</span><span style="font-family:Courier New;">
</span><span style="font-family:Courier New;"> </span><span style="font-family:Courier New;"> SELECT X = DATEADD(month, 1, X) FROM CTE</span><span style="font-family:Courier New;">
</span><span style="font-family:Courier New;"> </span><span style="font-family:Courier New;">  WHERE X &lt; '20080101'</span><span style="font-family:Courier New;">
)</span><span style="font-family:Courier New;">
SELECT X FROM CTE</span>
<span style="font-family:Courier New;">ORDER BY X</span><span style="font-family:Courier New;">
</span></pre>
<p><span style="font-family:Courier New;"> </span></p>
<p>Il recordset X può facilmente essere messo in join nell&#8217;ambito dello script &#8220;SELECT X&#8230;&#8221;.</p>
<p>Da questo script è facile ricavare recordset contenenti, ad esempio, intervalli di numerazione progressiva ascendene o discendente.</p>
<p>Attenzione, però: testando questa query su intervalli di date che richiedono più di 100 ricorsioni ci s&#8217;imbatterà nel messaggio di errore: &#8220;Istruzione interrotta. Numero massimo di ricorsioni 100 esaurito prima del completamento dell&#8217;istruzione.&#8221;. Difatti, il numero massimo di ricorsioni possibili di default in SQL Server è limitato a 100. Per consentire alla query di superare questo limite basterà fissare un nuovo limite e dichiararlo nell&#8217;ambito della stessa interrogazione con l&#8217;opzione MAXRECURSION come di seguito riportato:</p>
<pre><span style="font-family:Courier New;">WITH CTE(X)</span><span style="font-family:Courier New;">
AS</span><span style="font-family:Courier New;">
(</span><span style="font-family:Courier New;">
  SELECT X = convert(datetime, '20070101')</span><span style="font-family:Courier New;">
</span><span style="font-family:Courier New;"> </span><span style="font-family:Courier New;"> UNION ALL</span><span style="font-family:Courier New;">
</span><span style="font-family:Courier New;"> </span><span style="font-family:Courier New;"> SELECT X = DATEADD(month, 1, X) FROM CTE</span><span style="font-family:Courier New;">
</span><span style="font-family:Courier New;"> </span><span style="font-family:Courier New;"> WHERE X &lt; '20200101'</span><span style="font-family:Courier New;">
)</span><span style="font-family:Courier New;">
SELECT X FROM CTE</span><span style="font-family:Courier New;">
ORDER BY X </span><span style="font-family:Courier New;">
O</span><span style="font-family:Courier New;">PTION (MAXRECURSION 500);</span><span style="font-family:Courier New;">
</span></pre>
<p>Nell&#8217;esempio appena descritto l&#8217;intervallo di date restituisce un recordset di 157 elementi e senza l&#8217;opzione di cui all&#8217;ultima riga andrebbe in errore.</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/gianfrasoft.wordpress.com/12/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/gianfrasoft.wordpress.com/12/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/gianfrasoft.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/gianfrasoft.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/gianfrasoft.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/gianfrasoft.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/gianfrasoft.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/gianfrasoft.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/gianfrasoft.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/gianfrasoft.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/gianfrasoft.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/gianfrasoft.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/gianfrasoft.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/gianfrasoft.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/gianfrasoft.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/gianfrasoft.wordpress.com/12/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gianfrasoft.wordpress.com&amp;blog=2822728&amp;post=12&amp;subd=gianfrasoft&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://gianfrasoft.wordpress.com/2008/04/13/generare-un-recordset-contenente-tutti-gli-elementi-di-un-intervallo-in-sql-server-2005/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/905a08842a0c78883ed66254de5fc75a?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">gianfrasoft</media:title>
		</media:content>
	</item>
		<item>
		<title>Realizzazione di un servizio di prenotazione risorse on line in SQL</title>
		<link>http://gianfrasoft.wordpress.com/2008/02/24/realizzazione-di-un-servizio-di-prenotazione-risorse-on-line-in-sql/</link>
		<comments>http://gianfrasoft.wordpress.com/2008/02/24/realizzazione-di-un-servizio-di-prenotazione-risorse-on-line-in-sql/#comments</comments>
		<pubDate>Sun, 24 Feb 2008 13:12:51 +0000</pubDate>
		<dc:creator>gianfrasoft</dc:creator>
				<category><![CDATA[Transact SQL]]></category>
		<category><![CDATA[prenotazione]]></category>
		<category><![CDATA[risorse]]></category>
		<category><![CDATA[servizio]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[sql server]]></category>
		<category><![CDATA[transact]]></category>

		<guid isPermaLink="false">http://gianfrasoft.wordpress.com/?p=11</guid>
		<description><![CDATA[Introduzione Questo documento e tutto il lavoro che ne è scaturito, hanno come obiettivo la progettazione e l’implementazione di un sistema informatico che risponda alle richieste contenute nelle linee guida riportate di seguito: si è proceduto alla progettazione di una base dati per il supporto di un sistema informatico che realizzi un servizio web per [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gianfrasoft.wordpress.com&amp;blog=2822728&amp;post=11&amp;subd=gianfrasoft&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><b>Introduzione</b></p>
<p class="MsoBodyTextIndent">Questo documento e tutto il lavoro che ne è scaturito, hanno come obiettivo la progettazione e l’implementazione di un sistema informatico che risponda alle richieste contenute nelle <i>linee guida</i> riportate di seguito: si è proceduto alla progettazione di una base dati per il supporto di un sistema informatico che realizzi un servizio web per la gestione di un insieme condiviso di risorse hardware per un dipartimento. Questo sistema informativo consente la prenotazione delle risorse da parte di utenti registrati, oltre a fornire come servizio la possibilità di verificare la disponibilità di una risorsa in uno specifico giorno ed in uno specifico orario.</p>
<p class="MsoBodyTextIndent">Sono state così implementate tutte le funzionalità di:</p>
<ul>
<li><!--[if !supportLists]--><span style="font-family:'Times New Roman';"><span style="font-family:'Times New Roman';font-style:normal;font-variant:normal;font-weight:normal;font-size:7pt;line-height:normal;">  </span></span><!--[endif]-->inserimento di una risorsa</li>
<li><!--[if !supportLists]--><span style="font-family:'Times New Roman';"></span>registrazione degli utenti</li>
<li><!--[if !supportLists]--><span style="font-family:'Times New Roman';"></span>consultazione delle risorse disponibili</li>
<li><!--[if !supportLists]--><span style="font-family:'Times New Roman';"></span>prenotazione delle risorse</li>
<li><!--[if !supportLists]--><span style="font-family:'Times New Roman';"></span>cancellazione di una prenotazione</li>
<li><!--[if !supportLists]--><span style="font-family:'Times New Roman';"><span style="font-family:'Times New Roman';font-style:normal;font-variant:normal;font-weight:normal;font-size:7pt;line-height:normal;"></span></span><!--[endif]-->memorizzazione di dati relativi a utenti, risorse e prenotazioni</li>
</ul>
<p><b>Strategia di progetto</b></p>
<p class="MsoBodyTextIndent2">Già nell’ambito delle linee guida si possono identificare le entità principali attorno alle quali il sistema informativo deve svilupparsi, e cioè: l’<i>utente</i>, la <i>risorsa</i> e la <i>prenotazione</i>.</p>
<p class="MsoBodyTextIndent2">Al fine di rendere il sistema quanto più possibile aperto e funzionale, si è ritenuto opportuno introdurre alcune ulteriori specifiche riguardanti le suddette entità:</p>
<p><!--[if !supportLists]--></p>
<ul>
<li><span style="font-family:Symbol;"><span style="font-family:'Times New Roman';font-style:normal;font-variant:normal;font-weight:normal;font-size:7pt;line-height:normal;"></span></span>gli utenti del sistema si dividono in due categorie: <i>amministratori</i> e <i>utenti semplici</i>; ai primi è dato potere di accedere ad ogni parte del sistema mentre ai secondi alcune aree di lavoro sono interdette;</li>
<li><span style="font-family:Symbol;"><span style="font-family:'Times New Roman';font-style:normal;font-variant:normal;font-weight:normal;font-size:7pt;line-height:normal;"></span></span>ad ogni risorsa sono associati orari di disponibilità, cioè intervalli temporali all’esterno dei quali la risorsa non può mai essere prenotata;</li>
<li><span style="font-family:Symbol;"><span style="font-family:'Times New Roman';font-style:normal;font-variant:normal;font-weight:normal;font-size:7pt;line-height:normal;"></span></span>alla prenotazione delle risorse da parte di utenti generici o di amministratori viene fornito un sistema di visualizzazione grafica degli intervalli temporali di disponibilità della risorsa che rende superfluo qualsiasi ulteriore accorgimento;</li>
<li><span style="font-family:Symbol;"><span style="font-family:'Times New Roman';font-style:normal;font-variant:normal;font-weight:normal;font-size:7pt;line-height:normal;"></span></span>viene implementato a scopo didattico un semplice metodo di storicizzazione delle informazioni relativamente all’entità <i>prenotazione</i> che consente di aggirare alcuni problemi relativi all’aggiornamento delle risorse.</li>
</ul>
<p><!--[endif]--><!--[if !supportLists]--><!--[endif]--><!--[if !supportLists]--><!--[endif]--><!--[if !supportLists]--><!--[endif]--><span id="more-11"></span>  <b>Definizioni</b></p>
<p class="MsoNormal">Riportiamo la prima parte di un glossario utile alla comprensione delle specifiche di lavoro come di seguito riportate:</p>
<p class="MsoNormal">Indicheremo con <i>risorsa</i> l’oggetto d’interesse di una <i>prenotazione</i>. Con la parola <i>utente</i> faremo riferimento ad un qualsiasi utente, con <i>utente semplice</i> o <i>amministratore</i> indicheremo invece gli utenti specifici.</p>
<p>Con la parola <i>prenotabilità</i> faremo riferimento alle ore in cui una risorsa risulta prenotabile, con <i>disponibilità</i> indicheremo le ore in cui la risorsa è prenotabile e libera: una risorsa <i>prenotabile</i> sarà pertanto <i>disponibile</i> in una particolare fascia oraria solo qualora non vi fossero già presenti in quelle ore altre prenotazioni.</p>
<p>I giorni di prenotabilità di una risorsa si indicheranno come <i>giornate</i>, ed anche queste verranno rappresentate nel database nell’ambito di una specifica entità che si chiamerà <i>giorno</i>.</p>
<p>Nell’ambito del database tutti gli oggetti di cui sopra saranno identificabili nell’ambito di entità che porteranno i nomi di: <b>Risorse</b>, <b>Prenotazioni</b>, <b>Utenti</b> (entità omogenea per utenti semplici ed amministratori) e <b>Giorni</b>.</p>
<p><b>Entià</b></p>
<p>Nell’ambito della progettazione concettuale dobbiamo per primo identificare le entità che partecipano al progetto. Abbiamo descritto in un primo momento tre entità: utenti, risorse e prenotazioni.</p>
<p>Al fine di rendere alcune funzionalità relative alle prenotazioni e di cui parleremo in seguito, anticipiamo che tra le altre viene introdotta una quarta entità che è il <i>giorno</i>.</p>
<p><b>Utenti</b></p>
<p class="MsoNormal">Si dividono in utenti semplici ed amministratori. Agli amministratori soltanto è riservato il potere di</p>
<ul>
<li><!--[if !supportLists]--><span style="font-family:'Times New Roman';"><span style="font-family:'Times New Roman';font-style:normal;font-variant:normal;font-weight:normal;font-size:7pt;line-height:normal;"></span></span>generare nuove risorse, modificarne o eliminarne di esistenti</li>
<li><!--[if !supportLists]--><span style="font-family:'Times New Roman';"></span>registrare nuovi utenti, modificarne o cancellarne di esistenti</li>
</ul>
<p class="MsoNormal">Sia gli utenti semplici che gli amministratori possono prenotare risorse o cancellare prenotazioni proprie. Infine gli utenti semplici possono accedere alle informazioni associate a sé stessi per modificarne il contenuto mentre gli amministratori possono modificare le specifiche di qualsiasi utente presente in archivio.</p>
<p class="MsoNormal">L’entità utente contiene informazioni come: nome e cognome, indirizzo, contatti di vario genere oltre che <i>login</i> e <i>password</i> indispensabili per identificarsi nell’ambito del sistema informativo.</p>
<p><b>Risorse</b></p>
<p class="MsoBodyTextIndent2">Le risorse sono caratterizzate principalmente dalla propria descrizione. La generalità del concetto di risorsa è resa, nell’ambito del sistema informativo che stiamo descrivendo, ad un livello di astrazione tale da potersi considerare slegata dal contesto previsto nell’ambito delle linee guida. Parlare di risorsa hardware di un dipartimento equivale in questo contesto ad una qualsiasi risorsa prenotabile in un qualsiasi altro contesto.</p>
<p class="MsoNormal">Oltre alla descrizione, la risorsa è caratterizzata da una lista di (massimo) tre intervalli temporali (almeno uno deve essere valorizzato) che consentono al sistema di identificare le fasce orare di prenotabilità della risorsa nell’ambito di tutti i giorni della settimana.</p>
<p class="MsoBodyTextIndent2">Si noti che in questo contesto si assume che la risorsa sia disponibile tutti i giorni senza alcuna limitazione sulla data (limitazione che avrebbe richiesto l’introduzione di numerose variazioni nella gestione del front-end del sistema informativo). E’ altresì consentito indicare gli orari di prenotabilità a livello di risorsa che saranno il punto di riferimento per la definizione della prenotabilità nell’ambito di ogni singola giornata.</p>
<p><b>Prenotazioni</b></p>
<p class="MsoBodyTextIndent2">Le prenotazioni rappresentano relazioni che legano gli utenti alle risorse. In quanto tali le prenotazioni dovranno contenere null’altro che le informazioni indispensabili per la loro identificazione temporale e cioè data, orario di inizio ed orario di fine oltre ai riferimenti a risorsa ed utente.</p>
<p class="MsoNormal">La possibilità di prenotare una risorsa in una specifica data ed in una specifica fascia oraria richiede una verifica della sua disponibilità (e pertanto anche della sua prenotabilità) nella data/ora della nuova prenotazione. La presenza di altre prenotazioni in quella stessa fascia oraria, infatti invalida una qualsiasi nuova prenotazione, e lo stesso vale se la scelta di un intervallo per quest’ultima non ricade perfettamente nell’ambito della prenotabilità della risorsa stessa.</p>
<p>Problema della modifica della disponibilità di una risorsa</p>
<p class="MsoBodyTextIndent2">Se nell’ambito di una risorsa vengono modificati gli intervalli di disponibilità della stessa lì dove questa è già stata coinvolta una o più prenotazioni, nasce il problema di dovere definire una politica di comportamento del sistema informativo che aggiri la possibilità di conflitto tra gli intervalli di prenotazioni già effettuate e quelli delle nuove fasce di prenotabilità.</p>
<p class="MsoNormal">La politica di risoluzione del problema va in realtà determinata nell’ambito delle esigenze specifiche di chi commissiona la realizzazione del progetto. Avendo in questo ambito la libertà di determinare il più opportuno funzionamento da parte del sistema, si è deciso di provvedere descrivendo una nuova entità che ha il nome di <i>giorno</i>.</p>
<p><b>Giorni</b></p>
<p class="MsoNormal">Ciascuna entità di questa specie registra la prenotabilità della risorsa nell’ambito di una specifica giornata del calendario. La singola entità giorno conterrà oltre ad una data (relativa ad un qualsiasi giorno della settimana o del mese) le informazioni riguardo le fasce orarie di prenotabilità della risorsa al momento in cui, in quella specifica giornata, la prenotabilità sia stata definita una volta e per sempre.</p>
<p class="MsoNormal">Infatti, al momento di una prenotazione il sistema informativo farà riferimento, per la verifica della prenotabilità di una risorsa in una specifica giornata, alla entità giorno relativa alla risorsa e che fa riferimento alla giornata in questione. Se questa entità non è presente in archivio, il sistema informativo si occuperà di generarla assegnandole come data la giornata in cui si desidera attuare la prenotazione e come fasce di disponibilità quelle della risorsa che si desidera prenotare, così come sono definite in quel momento.</p>
<p class="MsoBodyTextIndent2">Pertanto le prenotazioni non faranno riferimento direttamente alle fasce orarie come descritte nella entità risorsa ma a quelle descritte nella entità giorno relativa alla data visitata.</p>
<p class="MsoNormal">Il fatto che la modifica delle fasce orarie di prenotabilità di ogni risorsa non si modifichi la prenotabilità come descritta nei giorni relative alla risorsa stessa, fa sì che le prenotazioni restino consistenti. Ciò equivale a dire che: qualora una risorsa venisse prenotata in uno specifico giorno ed in una specifica fascia oraria, eventuali modifiche alle fasce di disponibilità non interesserebbero i giorni in cui già fossero state effettuate prenotazioni.</p>
<p><b>Note</b></p>
<p class="MsoNormal">Questa politica di risoluzione del conflitto tra prenotazioni e risorse è sicuramente una politica discutibile sotto numerosi aspetti: sia perché non consente di stabilire il giorno in cui debba entrare in vigore il nuovo orario della risorsa, sia perché il cambio di orario determina per un numero imprecisato di giorni una alternanza di orari vecchi e nuovi a seconda della presenza o meno di prenotazioni che facciano riferimento a quelle giornate.</p>
<p class="MsoNormal">Una possibile migliore risposta alla questione dei conflitti prenotazioni-risorse è l’introduzione di un sistema di storicizzazione della modifica delle fasce orarie delle risorse che consentisse di registrare il periodo di validità dei vecchi e nuovi orari.</p>
<p class="MsoNormal">Questa soluzione, come numerose altre, sono state scartate per motivi di tempo.</p>
<p><b>Strategia di progetto</b></p>
<p class="MsoNormal">Data la semplicità della struttura della base dati, non ha propriamente senso parlare di strategie implementative di tipo top-down o bottom-up anche se per questo progetto vale forse parlare di strategia inside-out.</p>
<p class="MsoNormal">Partendo dalla entità che rappresenta il nucleo centrale di tutto il progetto, l’entità <i>risorsa</i>, possiamo considerare le entità <i>utente</i> e <i>prenotazione</i> come introdotte immediatamente dopo ed al fine di rendere la funzionalità legata alla prenotazione delle risorse stesse. Infine l’entità <i>giorno</i> interviene per risolvere problemi di progettazione legati alla struttura del database.</p>
<p><b>Progettazione logica<br />
</b></p>
<p class="MsoNormal">Per quanto detto sopra, le tabelle saranno quindi le seguenti:</p>
<p style="text-align:center;" class="MsoNormal"><span style="font-variant:small-caps;">(Utenti, Risorse, Prenotazioni, Giorni)</span></p>
<p><b>Schema logico</b></p>
<p class="MsoNormal"><!--[if gte vml 1]&amp;gt;                                                                         &amp;lt;![endif]--><!--[if !vml]--><span></span></p>
<p>Ecco come appare la struttura sin qui descritta e realizzata logicamente mediante il case Embarcadero E/R Studio:</p>
<div style="text-align:center;"><img src="http://gianfrasoft.netsons.org/mysoftware/SchemaER.JPG" alt="Modello ER" height="325" width="595" /></div>
<div style="text-align:center;" align="left"></div>
<div style="text-align:center;" align="left"></div>
<p class="MsoNormal">In questo modello entità-relazione la strutturazione logica mostra le relazioni che legano la tabella delle prenotazioni da tutte le altre tabelle. La tabella dei giorni è in relazione con la sola tabella delle risorse mentre quella degli utenti è completamente indipendente dalle altre.</p>
<p class="MsoNormal">Uno schema tanto semplice è tale da coincidere quasi perfettamente con la struttura implementativa del database.</p>
<p class="MsoNormal">Si noti nel report la presenza di due tipi dato definiti per rendere omogeneo l’utilizzo di campi che fanno riferimento ad indirizzi e-mail (tipo definito: EMAIL) ed a numeri telefonici (tipo definito: NUMEROTEL).</p>
<p><b>Funzionalità trasparenti</b></p>
<p class="MsoNormal">Alcune funzionalità del database hanno lo scopo di preservare l’integrità dei dati o di fornire controlli di vario genere sulla qualità dei dati immessi.</p>
<p class="MsoNormal">Alcune di queste sono state implementate per mezzo di trigger, altre per mezzo di procedure (o funzioni database) opportunamente inserite nel codice richiamato dal client del sistema informatico.</p>
<p><b>Integrità a livello di prenotazione</b></p>
<p class="MsoNormal">La cancellazione di una risorsa o di un utente dalla relativa tabella determina la necessità di ripulire le tabelle dei giorni e delle prenotazioni da tutti gli elementi che fanno riferimento alla risorsa o all’utente stesso. Questo viene reso mediante l’uso di due trigger sulle tabelle delle risorse e degli utenti.</p>
<p><b>Storicizzazione delle risorse</b></p>
<p class="MsoNormal">Come accennato precedentemente, s’intende far corrispondere alla eliminazione di un elemento della tabella delle risorse l’aggiornamento del campo Storicizzazione al fine di tenere in archivio traccia della risorsa non più utilizzata.</p>
<p class="MsoNormal">Una simile storicizzazione può essere attuata anche a livello di aggiornamento (dove la modifica di un qualsiasi campo della tabella Risorse genera una copia del record come era prima della modifica e con una data di validità introdotta nel campo Storicizzazione). Questo tipo di impiego non è utile in questa fase anche se renderebbe possibile alcune migliorie nel funzionamento della base dati.</p>
<p class="MsoNormal">Nell’ambito della visualizzazione, nel client, della lista delle risorse disponibili in archivio vengono pertanto escluse nella query tutte le risorse con campo Storicizzazione non nullo.</p>
<p><b>Controllo della disponibilità di una risorsa</b></p>
<p class="MsoNormal">Alcune funzionalità, che non possono essere rese agevolmente mediante semplici query, devono essere affidare a procedure (o funzioni) apposite: è il caso dei controlli sulla disponibilità delle risorse nelle fasce orarie in cui è richiesto di aggiungere una prenotazione. Il sistema database deve essere blindato, nel senso di non consentire procedure di INSERT di prenotazioni dove non fesse consentito.</p>
<p class="MsoNormal">Questi controlli sono resi trasparenti dal client che interroga il database con una apposita stored procedure per verificare che non si stiano violando le regole fondamentali della prenotabilità delle risorse: qualora le regole fossero violare, a lui è riservato il compito di annullare la procedura di inserimento ed avvertire l’utente della non avvenuta operazione. Un ulteriore controllo a livello database, affidato ad un trigger e pertanto trasparente anche al client stesso potrebbe ritenersi opportuno ma attualmente appare superfluo.</p>
<p class="MsoNormal">Anche con l’introduzione nel front-end di un sistema guidato alla prenotazione, realizzato mediante l’uso delle procedure di cui ai paragrafi seguenti, è da ritenersi necessario il controllo appena descritto per non permettere di introdurre in alcun modo in archivio dati che renderebbero aleatorio tutto il contenuto delle tabelle destinate alle prenotazioni.</p>
<p><b>Controllo della presenza del giorno di prenotabilità</b></p>
<p class="MsoNormal">In fase di interrogazione del database, è necessario che, qualora non fosse definita la prenotabilità di una risorsa in una specifica giornata, che corrisponde alla assenza del record della tabella dei giorni che fa riferimento a quella risorsa e quella giornata, sarà necessario generare quel record in modo da riprodurre tutte le fasce orarie di disponibilità della risorsa stessa.</p>
<p class="MsoNormal">Le fasce orarie saranno quelle della risorsa al momento della creazione del record nella tabella Giorni; ad una procedura sarà affidato il controllo della presenza dello specifico record della tabella Giorni e l’eventuale sua generazione qualora non fosse presente.</p>
<p class="MsoNormal">NOTA: La generazione dei record della tabella Giorni avverranno pertanto già in fase di visitazione della tabella stessa. Questo comportamento rappresenta una approssimazione forse grossolana alla quale si potrebbe ovviare in molti modi ma che si assume adatto alle esigenze di questo progetto.</p>
<p><b>Funzionalità accessorie</b><br />
<b>Calcolo automatico dell’id di una nuova risorsa</b></p>
<p class="MsoNormal">E’ spesso opportuno rendere automatico il calcolo, da parte del sistema informatico, del nuovo valore del campo chiave della tabella delle risorse (uguale al valore massimo presente in tabella aumentato di uno). Metodi più evoluti, mediante tabella delle sequenze sarebbero opportuni per applicazioni web destinate ad un numero di connessioni contemporanee alto, ma in questo progetto si considerano non necessari.</p>
<p><b>Generazione di viste sulle fasce orarie di disponibilità delle risorse</b></p>
<p class="MsoNormal">Una particolare “funzione tabellare” (strumento in uso in MS-SQL Server 2000) restituirà in output una tabella ad uso della visualizzazione delle fasce orarie di prenotazione e di disponibilità delle risorse al fine di consentire, nel client, una visualizzazione grafica.</p>
<p class="MsoNormal">Nella visualizzazione grafica compariranno tanti elementi quanti sono i time-slice interessati dall’intervallo di prenotabilità della risorsa: ogni elemento corrisponderà ad un record della tabella dinamica generata dalla funzione tabellare. Un particolare campo di questa tabella servirà ad indicare se nella specifica fascia oraria la risorsa è non disponibile, prenotabile o già prenotata: a questi valori il client farà corrispondere in visualizzazione colori diversi che rendano più intuitiva la lettura.</p>
<p>Indicazione degli estremi di un intervallo di disponibilità</p>
<p class="MsoNormal">Sempre al fine di generare funzionalità utili alla visualizzazione grafica sul lato client delle informazioni relative alla disponibilità delle risorse nelle specifiche fasce orarie, una particolare procedura si occuperà di determinare l’inizio e la fine di un intervallo di disponibilità a partire da un qualsiasi orario contenuto all’interno dell’intervallo stesso.</p>
<p class="MsoNormal">In fase di visualizzazione da parte del client, l’utilità di questa procedura è di rendere possibile all’utente di sapere se in un intorno di uno specifico orario, selezionato sulla grafica descritta sopra, esiste la possibilità di prenotare una risorsa e quanto può essere al limite grande questo intervallo.</p>
<p><b><b>Altri controlli</b></b></p>
<p class="MsoNormal">Al client dovranno essere affidati numerosi altri controlli sulla qualità dei dati in fase di inserimento o di modifica dei record; ciò si attua al fine sia di evitare l’inserimento di dati aleatori per i quali non sono previsti controlli a livello di database, sia di evitare che il database restituisca errori non gestiti dallo stesso client.</p>
<p><b>Implementazione</b></p>
<p class="MsoNormal">Quello che segue è la descrizione dettagliata del file usato per la generazione delle entità del database oggetto di studio, oltre ai tipi definiti dall’utente, ai trigger ed alle procedure ad uso della gestione del sistema informatico.</p>
<p>Si noti che nel database reale i nomi dei campi e delle entità sono leggermente modificati rispetto a come compaiono nella strutturazione logica. In particolare gli spazi sono sostituiti da caratteri underscore (“_”) e le lettere minuscole sono sostituite da maiuscole; così che il campo “Disp dalle” diventa “DISP_DALLE”.<br />
<b>Tipi definiti</b><br />
<b>“EMAIL”</b></p>
<div style="border:1.5pt solid gray;padding:1pt 10pt;">
<p class="Codice">EXEC sp_addtype EMAIL, &#8220;varchar(100)&#8221;,&#8221;NULL&#8221;</p>
</div>
<p><b>“NUMEROTEL”</b></p>
<div style="border:1.5pt solid gray;padding:1pt 10pt;">
<p class="Codice">EXEC sp_addtype NUMEROTEL, &#8220;varchar(20)&#8221;,&#8221;NULL&#8221;</p>
</div>
<p><span style="font-size:10pt;font-family:Arial;">Questi tipi definiti sono introdotti per rendere omogeneo l’utilizzo dei campi relativi ad e-mail e numeri telefonici.</span><br />
<b>Entità</b></p>
<p class="MsoBodyTextIndent2">Le entità sono riportate nell’ordine logico con cui sono state concepite in fase di progettazione concettuale.</p>
<p><b>Risorse</b></p>
<div style="border:1.5pt solid gray;padding:1pt 10pt;">
<p class="Codice">CREATE TABLE RISORSE(</p>
<p class="Codice"><span>    </span>ID_RISORSA<span>         </span>int<span>            </span>NOT NULL,</p>
<p class="Codice"><span>    </span>NOME<span>               </span>varchar(30)<span>    </span>NOT NULL,</p>
<p class="Codice"><span>    </span>DISP_DALLE<span>         </span>datetime<span>     </span><span>  </span>NOT NULL,</p>
<p class="Codice"><span>    </span>DISP_ALLE<span>          </span>datetime<span>       </span>NOT NULL,</p>
<p class="Codice"><span>    </span>DISP2_DALLE<span>        </span>datetime<span>       </span>NULL,</p>
<p class="Codice"><span>    </span>DISP2_ALLE<span>         </span>datetime<span>       </span>NULL,</p>
<p class="Codice"><span>    </span>DISP3_DALLE<span>        </span>datetime<span>       </span>NULL,</p>
<p class="Codice"><span>    </span>DISP3_ALLE<span>         </span>datetime<span>       </span>NULL,</p>
<p class="Codice"><span>    </span>STORICIZZAZIONE <span>   </span>datetime<span>       </span>NULL,</p>
<p class="Codice"><span>    </span>PRIMARY KEY NONCLUSTERED (ID_RISORSA)</p>
<p class="Codice">)</p>
</div>
<p><b>Utenti</b></p>
<div style="border:1.5pt solid gray;padding:1pt 10pt;">
<p class="Codice">CREATE TABLE UTENTI(</p>
<p class="Codice"><span>    </span>LOGIN<span>            </span>varchar(20)<span>     </span>NOT NULL,</p>
<p class="Codice"><span>    </span>PASSWORD<span>         </span>varchar(20)<span>     </span>NOT NULL,</p>
<p class="Codice"><span>    </span>NOME<span>             </span>varchar(100)<span>    </span>NOT NULL,</p>
<p class="Codice"><span>    </span>COGNOME<span>        </span><span>  </span>varchar(100)<span>    </span>NOT NULL,</p>
<p class="Codice"><span>    </span>DOM_INDIRIZZO<span>    </span>varchar(200)<span>    </span>NULL,</p>
<p class="Codice"><span>    </span>DOM_CITTA<span>        </span>varchar(100)<span>    </span>NULL,</p>
<p class="Codice"><span>    </span>TELEFONO<span>         </span>NUMEROTEL<span>       </span>NULL,</p>
<p class="Codice"><span>    </span>CELLULARE<span>        </span>NUMEROTEL<span>       </span>NULL,</p>
<p class="Codice"><span>    </span>E_MAIL<span>           </span>EMAIL<span>           </span>NULL,</p>
<p class="Codice"><span>    </span>TIPO<span>     </span><span>        </span>char(1)<span>         </span>NULL,</p>
<p class="Codice"><span>    </span>PRIMARY KEY NONCLUSTERED (LOGIN)</p>
<p class="Codice">)</p>
</div>
<p><b>Giorni</b></p>
<div style="border:1.5pt solid gray;padding:1pt 10pt;">
<p class="Codice">CREATE TABLE GIORNI(</p>
<p class="Codice"><span>    </span>GIORNO<span>         </span>datetime<span>    </span>NOT NULL,</p>
<p class="Codice"><span>    </span>ID_RISORSA<span>     </span>int<span>         </span>NOT NULL,</p>
<p class="Codice"><span>    </span>DISP_DALLE<span>     </span>datetime<span>    </span>NOT NULL,</p>
<p class="Codice"><span>    </span>DISP_ALLE<span>      </span>datetime<span>    </span>NOT NULL,</p>
<p class="Codice"><span>    </span>DISP2_DALLE<span>    </span>datetime<span>    </span>NULL,</p>
<p class="Codice"><span>    </span>DISP2_ALLE<span>     </span>datetime<span>    </span>NULL,</p>
<p class="Codice"><span>    </span>DISP3_DALLE<span>    </span>datetime<span>    </span>NULL,</p>
<p class="Codice"><span>    </span>DISP3_ALLE<span>     </span>datetime<span>    </span>NULL,</p>
<p class="Codice"><span>    </span>PRIMARY KEY NONCLUSTERED (GIORNO,ID_RISORSA)</p>
<p class="Codice">)</p>
</div>
<p><b>Prenotazioni</b></p>
<div style="border:1.5pt solid gray;padding:1pt 10pt;">
<p class="Codice">CREATE TABLE PRENOTAZIONI(</p>
<p class="Codice"><span>    </span>GIORNO <span>       </span>datetime<span>       </span>NOT NULL,</p>
<p class="Codice"><span>    </span>DA_ORA<span>        </span>datetime<span>       </span>NOT NULL,</p>
<p class="Codice"><span>    </span>ID_RISORSA<span>    </span>int<span>            </span>NOT NULL,</p>
<p class="Codice"><span>    </span>A_ORA<span>         </span>datetime<span>       </span>NOT NULL,</p>
<p class="Codice"><span>    </span>LOGIN<span>         </span>varchar(20)<span>    </span>NULL,</p>
<p class="Codice"><span>    </span>PRIMARY KEY NONCLUSTERED (GIORNO,DA_ORA,ID_RISORSA)</p>
<p class="Codice">)</p>
</div>
<p><b>Chiavi alternative</b></p>
<p class="MsoNormal">E’ presente in archivio una sola chiave alternativa che consente di individuare una risorsa mediante il suo nome ed il valore di storicizzazione.</p>
<p><b>AK1_RISORSE</b></p>
<p class="MsoBodyTextIndent2">Il campo storicizzazione fa chiave univoca con il campo Nome al fine di consentire la reintroduzione di elementi precedentemente storicizzati con un nuovo id primario ma non di introdurre due risorse attuve (campo Storicizzazione nullo) con lo stesso nome.<span style="font-size:11pt;"></span></p>
<div style="border:1.5pt solid gray;padding:1pt 10pt;">
<p class="Codice">CREATE UNIQUE INDEX AK1_RISORSE ON RISORSE(NOME,STORICIZZAZIONE)</p>
</div>
<p><b>Chiavi esterne</b></p>
<p class="MsoNormal">Le foreign key vengono generate mediante il comando di ALTER TABLE al fine di non creare conflitti con le tabelle non ancora generate.</p>
<p><b>FK_RISORSE_DISPONIBILITA</b></p>
<p class="MsoNormal">Questa chiave mette in relazione la tabella Giorni con la tabella Risorse: individua pertanto la risorsa a cui fa riferimento lo specifico giorno.</p>
<div style="border:1.5pt solid gray;padding:1pt 10pt;">
<p class="Codice">ALTER TABLE GIORNI ADD CONSTRAINT FK_RISORSE_DISPONIBILITA</p>
<p class="Codice"><span>    </span>FOREIGN KEY (ID_RISORSA)</p>
<p class="Codice"><span>    </span>REFERENCES RISORSE(ID_RISORSA)</p>
</div>
<p><b>FK_GIORNI_PRENOTAZIONI</b></p>
<p class="MsoNormal">Questa chiave mette in relazione la tabella Prenotazioni con la tabella Giorni: individua a quale giorno fa riferimento la specifica prenotazione.</p>
<div style="border:1.5pt solid gray;padding:1pt 10pt;">
<p class="Codice">ALTER TABLE PRENOTAZIONI ADD CONSTRAINT FK_GIORNI_PRENOTAZIONI</p>
<p class="Codice"><span>    </span>FOREIGN KEY (GIORNO,ID_RISORSA)</p>
<p class="Codice"><span>    </span>REFERENCES GIORNI(GIORNO,ID_RISORSA)</p>
</div>
<p><b>FK_RISORSE_PRENOTAZIONI</b></p>
<p class="MsoNormal">Questa chiave mette in relazione la tabella Prenotazioni con la tabella Risorse: individua la risorsa alla quale fa riferimento la specifica prenotazione.</p>
<div style="border:1.5pt solid gray;padding:1pt 10pt;">
<p class="Codice">ALTER TABLE PRENOTAZIONI ADD CONSTRAINT FK_RISORSE_PRENOTAZIONI</p>
<p class="Codice"><span>    </span>FOREIGN KEY (ID_RISORSA)</p>
<p class="Codice"><span>    </span>REFERENCES RISORSE(ID_RISORSA)</p>
</div>
<p class="MsoNormal">Questa informazione è ridondante se si considera che ogni prenotazione fa riferimento ad un record della tabella Giorni e che quest’ultimo contiene già il riferiento alla risorsa prenotata. Ripetere questa informazione nella tabella delle prenotazioni consente comunque un risparmio in termini computazionali e di tempo di risposta del database poiché, in fase di interrogazione dello stesso, consentirà di fare uso di query semplificate. La spesa in termini di inserimento dell’informazione sulla risorsa nei record delle prenotazioni non ha alcun costo perché già disponibile nel client al momento in cui un utente desidera prenotare.</p>
<p><b>FK_UTENTI_PRENOTAZIONI</b></p>
<p class="MsoNormal">Questa chiave mette in relazione la tabella Prenotazioni con la tabella Utenti: individua l’utente che ha effettuato la specifica prenotazione.</p>
<div style="border:1.5pt solid gray;padding:1pt 10pt;">
<p class="Codice">ALTER TABLE PRENOTAZIONI ADD CONSTRAINT FK_UTENTI_PRENOTAZIONI</p>
<p class="Codice"><span>    </span>FOREIGN KEY (LOGIN)</p>
<p class="Codice"><span>    </span>REFERENCES UTENTI(LOGIN)</p>
</div>
<p><b>Trigger</b></p>
<p class="MsoNormal">Hanno tutti lo scopo di mantenere l’integrità del database.</p>
<p><b>OnDeleteRisorsa</b></p>
<p class="MsoNormal">Determina il comportamento del satabase al momento della eliminazione di una risorsa. E’ un trigger INSTEAD OF perché intende sostituire alla operazione di eliminazione l’aggiornamento del campo STORICIZZAZIONE.</p>
<div style="border:1.5pt solid gray;padding:1pt 10pt;">
<p class="Codice">CREATE TRIGGER OnDeleteRisorsa</p>
<p class="Codice">ON RISORSE</p>
<p class="Codice">INSTEAD OF DELETE</p>
<p class="Codice">AS</p>
<p class="Codice">BEGIN</p>
<p class="Codice"><span>  </span>DECLARE @IdRisorsa int</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><!--[if gte vml 1]&amp;gt;     &amp;lt;![endif]--><!--[if !vml]--><span style="position:absolute;z-index:0;left:0;margin-left:347px;margin-top:8px;width:224px;height:61px;"></span></p>
<p>&#8211;Il cursore RisorseEliminate serve ad enumerare tutti i record eliminati<br />
&#8211;(qualora l’eliminazione ne coinvolgesse piu di uno) e per essi attuare la stessa politica.<br />
DECLARE RisorseEliminate CURSOR FOR</p>
<p class="Codice"><span>    </span>SELECT ID_RISORSA FROM deleted</p>
<p class="Codice"><span>  </span>OPEN RisorseEliminate</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>  </span>FETCH NEXT FROM RisorseEliminate</p>
<p class="Codice"><span>  </span>INTO @IdRisorsa</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>  </span>WHILE @@FETCH_STATUS = 0</p>
<p class="Codice"><span>  </span>BEGIN</p>
<p class="Codice">&#8211;Elimina tutti i record della tabella PRENOTAZIONI collegati alla ciascuna risorsa eliminata.</p>
<p class="Codice">DELETE FROM PRENOTAZIONI</p>
<p class="Codice"><span>    </span>WHERE ID_RISORSA = @IdRisorsa<span>    </span></p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>    </span>UPDATE RISORSE SET</p>
<p class="Codice"><!--[if gte vml 1]&amp;gt;   &amp;lt;![endif]--><!--[if !vml]--><span style="position:absolute;z-index:2;left:0;margin-left:337px;margin-top:13px;width:234px;height:42px;"></span></p>
<p><!--[endif]-->&#8211; Alla operazione di DELETE sostituisce l’UPDATE del campo STORICIZZAZIONE.<span>    </span>STORICIZZAZIONE = getdate()</p>
<p class="Codice"><span>    </span>WHERE ID_RISORSA = @IdRisorsa<span>    </span></p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>    </span>FETCH NEXT FROM RisorseEliminate</p>
<p class="Codice"><span>    </span>INTO @IdRisorsa</p>
<p class="Codice"><span>  </span>END</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>  </span>CLOSE RisorseEliminate</p>
<p class="Codice"><span>  </span>DEALLOCATE RisorseEliminate</p>
<p class="Codice">END</p>
</div>
<p><b>OnDeleteRisorsa</b></p>
<p class="MsoNormal">Determina il comportamento del satabase al momento della eliminazione di un UTENTE. Anche questo è un trigger di tipo INSTEAD OF ma in questo caso avrebbe potuto essere anche di tipo AFTER: la sola condizione che si pone è che l’operazione di eliminazione dell’utente stesso non deve avvenire se non dopo l’eliminazione dei riferimenti ad esso nella tabella PRENOTAZIONI.</p>
<div style="border:1.5pt solid gray;padding:1pt 10pt;">
<p class="Codice">CREATE TRIGGER OnDeleteUtente</p>
<p class="Codice">ON UTENTI</p>
<p class="Codice">INSTEAD OF DELETE</p>
<p class="Codice">AS</p>
<p class="Codice">BEGIN</p>
<p class="Codice"><span>  </span>DECLARE @LoginUtente varchar(20)</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><!--[if gte vml 1]&amp;gt;&amp;lt;![endif]--><!--[if !vml]--><span style="position:absolute;z-index:3;left:0;margin-left:337px;margin-top:5px;width:224px;height:60px;"></span></p>
<p>&#8211; Il cursore UtentiEliminati serve ad enumerare tutti i record eliminati<br />
&#8211; (qualora l’eliminazione ne coinvolgesse piu di uno) e per essi attuare la stessa politica.</p>
<p>DECLARE UtentiEliminati CURSOR FOR</p>
<p class="Codice"><span>    </span>SELECT LOGIN FROM deleted</p>
<p class="Codice"><span>  </span>OPEN UtentiEliminati</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>  </span>FETCH NEXT FROM UtentiEliminati</p>
<p class="Codice"><span>  </span>INTO @LoginUtente</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><!--[if gte vml 1]&amp;gt;   &amp;lt;![endif]--><!--[if !vml]--><span style="position:absolute;z-index:4;left:0;margin-left:337px;margin-top:4px;width:186px;height:51px;"></span></p>
<p>&#8211; Elimina tutti i record della tabella PRENOTAZIONI collegati alla ciascun utente eliminato.<span>  </span>WHILE @@FETCH_STATUS = 0</p>
<p class="Codice"><span>  </span>BEGIN</p>
<p class="Codice"><span>    </span>DELETE FROM PRENOTAZIONI</p>
<p class="Codice"><span>    </span>WHERE LOGIN = @LoginUtente<span>    </span></p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><!--[if gte vml 1]&amp;gt;   &amp;lt;![endif]--><!--[if !vml]--><span style="position:absolute;z-index:5;left:0;margin-left:347px;margin-top:3px;width:214px;height:51px;"></span></p>
<p>&#8211; Elimina per ultimo tutti i record della tabella UTENTI come richiesto dalla operazione di DELETE.<br />
DELETE FROM UTENTI</p>
<p class="Codice"><span>    </span>WHERE LOGIN = @LoginUtente<span>    </span></p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>    </span>FETCH NEXT FROM UtentiEliminati</p>
<p class="Codice"><span>    </span>INTO @LoginUtente</p>
<p class="Codice"><span>  </span>END</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>  </span>CLOSE UtentiEliminati</p>
<p class="Codice"><span>  </span>DEALLOCATE UtentiEliminati</p>
<p class="Codice">END</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
</div>
<p><b>Stored procedure</b></p>
<p class="MsoNormal">Le procedure che seguono sono concepite per rendere i controlli e le funzionalità relative al calcolo delle fasce orarie di disponibilità delle risorse.</p>
<p><b>AbilitaPrenotabilitaRisorsa</b></p>
<p class="MsoNormal">Questa funzione verifica che per una specifica risorsa ed una specifica data sia prensente nella tabella GIORNI il record che ne consente la prenotazione, altrimenti lo genera.</p>
<div style="border:1.5pt solid gray;padding:1pt 10pt;">
<p class="Codice">CREATE PROCEDURE AbilitaPrenotabilitaRisorsa</p>
<p class="Codice"><span> </span>(@IdRisorsa int,</p>
<p class="Codice"><span>         </span>@Data datetime)</p>
<p class="Codice">AS</p>
<p class="Codice">BEGIN</p>
<p class="Codice"><!--[if gte vml 1]&amp;gt;   &amp;lt;![endif]--><!--[if !vml]--><span style="position:absolute;z-index:6;left:0;margin-left:424px;margin-top:3px;width:156px;height:80px;"></span></p>
<p>&#8211; Verifica chen non esista già in archivio un record in GIORNI che faccia riferimento alla<br />
&#8211; risorsa ed alla giornata dati per input.<br />
<!--[endif]--><span>  </span>IF NOT EXISTS (SELECT * FROM GIORNI</p>
<p class="Codice"><span>                 </span>WHERE ID_RISORSA = @IdRisorsa</p>
<p class="Codice"><span>                 </span>AND GIORNO = @Data)</p>
<p class="Codice"><span>  </span>BEGIN</p>
<p class="Codice"><span>    </span>INSERT INTO GIORNI (GIORNO, ID_RISORSA,</p>
<p class="Codice"><!--[if gte vml 1]&amp;gt;   &amp;lt;![endif]--><!--[if !vml]--><span style="position:absolute;z-index:7;left:0;margin-left:433px;margin-top:9px;width:138px;height:99px;"></span></p>
<p>&#8211; Se non esiste lo genera introducendo nei campi destinati a definire gli intervalli di<br />
&#8211; prenotabilità i valori contenuti nei campi omologhi della tabella delle risorse<br />
<!--[endif]--><span>                        </span>DISP_DALLE, DISP_ALLE,</p>
<p class="Codice"><span>                        </span>DISP2_DALLE, DISP2_ALLE,</p>
<p class="Codice"><span>                        </span>DISP3_DALLE, DISP3_ALLE)</p>
<p class="Codice"><span>      </span>SELECT @Data, ID_RISORSA,</p>
<p class="Codice"><span>             </span>DISP_DALLE, DISP_ALLE,</p>
<p class="Codice"><span>             </span>DISP2_DALLE, DISP2_ALLE,</p>
<p class="Codice"><span>             </span>DISP3_DALLE, DISP3_ALLE</p>
<p class="Codice"><span>      </span>FROM RISORSE</p>
<p class="Codice"><span>      </span>WHERE ID_RISORSA = @IdRisorsa</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>  </span>END</p>
<p class="Codice">END</p>
</div>
<p><b>TrovaInizioFineIntervallo</b></p>
<p class="MsoNormal">Questa procedura restituisce gli orari di inizio e di fine di un intervallo di prenotabilità riferito alla data ed all&#8217;ora passati come parametri di input.</p>
<div style="border:1.5pt solid gray;padding:1pt 10pt;">
<p class="Codice">CREATE PROCEDURE TrovaInizioFineIntervallo</p>
<p class="Codice"><span> </span>(@IdRisorsa int,</p>
<p class="Codice"><span>         </span>@Data datetime,</p>
<p class="Codice"><span>         </span>@Orario datetime,</p>
<p class="Codice"><span>         </span>@OraInizioIntervallo datetime OUTPUT,</p>
<p class="Codice"><span>  </span><span>       </span>@OraFineIntervallo datetime OUTPUT)</p>
<p class="Codice">AS</p>
<p class="Codice"><!--[if gte vml 1]&amp;gt;   &amp;lt;![endif]--><!--[if !vml]--><span style="position:absolute;z-index:8;left:0;margin-left:357px;margin-top:11px;width:214px;height:51px;"></span></p>
<p>&#8211; Se esiste una prenotazione che insiste sulla fascia oraria selezionata la procedura restituisce “2” ed esce.<br />
<!--[endif]-->BEGIN</p>
<p class="Codice"><span>  </span>&#8211; Errore codice 1</p>
<p class="Codice"><span>  </span>IF EXISTS (SELECT * FROM PRENOTAZIONI</p>
<p class="Codice"><span>             </span>WHERE GIORNO = @Data</p>
<p class="Codice"><span>             </span>AND ID_RISORSA = @IdRisorsa</p>
<p class="Codice"><span>             </span>AND DA_ORA &lt;= @Orario</p>
<p class="Codice"><span>             </span>AND A_ORA &gt; @Orario)</p>
<p class="Codice"><span>  </span>BEGIN</p>
<p class="Codice"><span>    </span>RETURN 2</p>
<p class="Codice"><span>  </span>END</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><!--[if gte vml 1]&amp;gt;   &amp;lt;![endif]--><!--[if !vml]--><span style="position:absolute;z-index:9;left:0;margin-left:376px;margin-top:9px;width:195px;height:140px;"></span></p>
<p>&#8211; Altrimenti genera una tabella temporanea #TempTable in cui introduce una serie di elementi che<br />
&#8211; servono a determinare in prima istanza il valore dell’estremo sinistro dell’intervallo di<br />
&#8211; prenotabilità (e quindi di disponibilità) della risorsa. In una seconda istanza consentirà di<br />
&#8211; determinare l’estremo destro dello stesso intervallo.<br />
<!--[endif]--><span>  </span>CREATE TABLE #TempTable (ALLE datetime)</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>  </span>INSERT INTO #TempTable</p>
<p class="Codice"><span>    </span>SELECT MAX(A_ORA) FROM PRENOTAZIONI</p>
<p class="Codice"><span>    </span>WHERE GIORNO = @Data</p>
<p class="Codice"><span>    </span>AND ID_RISORSA = @IdRisorsa</p>
<p class="Codice"><span>    </span>AND A_ORA &lt;= @Orario</p>
<p class="Codice"><span>    </span>UNION</p>
<p class="Codice"><span>    </span>SELECT MAX(DISP_DALLE) FROM GIORNI</p>
<p class="Codice"><span>    </span>WHERE GIORNO = @data</p>
<p class="Codice"><span>    </span>AND ID_RISORSA = @IdRisorsa</p>
<p class="Codice"><!--[if gte vml 1]&amp;gt;   &amp;lt;![endif]--><!--[if !vml]--><span style="position:relative;z-index:10;"><span style="position:absolute;left:405px;top:-1px;width:137px;height:147px;"></span></span></p>
<p>&#8211; Per determinare l’estremo sinistro, seleziona il massimo tra gli estremi destri degli intervalli<br />
&#8211; di prenotazione e degli estremi sinistri degli intervalli di disponibilità della risorsa<br />
&#8211; relativamente alla data selezionata.<br />
<!--[endif]--><span>    </span>AND DISP_DALLE &lt;= @Orario</p>
<p class="Codice"><span>    </span>UNION</p>
<p class="Codice"><span>    </span>SELECT MAX(DISP2_DALLE) FROM GIORNI</p>
<p class="Codice"><span>    </span>WHERE GIORNO = @data</p>
<p class="Codice"><span>    </span>AND ID_RISORSA = @IdRisorsa</p>
<p class="Codice"><span>    </span>AND DISP2_DALLE &lt;= @Orario</p>
<p class="Codice"><span>    </span>UNION</p>
<p class="Codice"><span>    </span>SELECT MAX(DISP3_DALLE) FROM GIORNI</p>
<p class="Codice"><span>    </span>WHERE GIORNO = @data</p>
<p class="Codice"><span>    </span>AND ID_RISORSA = @IdRisorsa</p>
<p class="Codice"><span>    </span>AND DISP3_DALLE &lt;= @Orario</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>  </span>SELECT @OraInizioIntervallo = MAX(ALLE) FROM #TempTable</p>
<p class="Codice"><span>    </span></p>
<p class="Codice"><span>  </span>DELETE FROM #TempTable</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><!--[if gte vml 1]&amp;gt;   &amp;lt;![endif]--><!--[if !vml]--><span style="position:absolute;z-index:11;left:0;margin-left:405px;margin-top:7px;width:108px;height:243px;"></span></p>
<p>&#8211; Per determinare l’estremo destro, seleziona il minimo tra gli estremi sisistri degli intervalli<br />
&#8211; di prenotazione e degli estremi destri degli intervalli di disponibilità della risorsa<br />
&#8211; relativamente alla data selezionata.<br />
<!--[endif]--><span>  </span>INSERT INTO #TempTable</p>
<p class="Codice"><span>    </span>SELECT MIN(DA_ORA) FROM PRENOTAZIONI</p>
<p class="Codice"><span>    </span>WHERE GIORNO = @Data</p>
<p class="Codice"><span>    </span>AND ID_RISORSA = @IdRisorsa</p>
<p class="Codice"><span>    </span>AND DA_ORA &gt;= @Orario</p>
<p class="Codice"><span>    </span>UNION</p>
<p class="Codice"><span>    </span>SELECT MIN(DISP_ALLE) FROM GIORNI</p>
<p class="Codice"><span>    </span>WHERE GIORNO = @data</p>
<p class="Codice"><span>    </span>AND ID_RISORSA = @IdRisorsa</p>
<p class="Codice"><span>    </span>AND DISP_ALLE &gt;= @Orario</p>
<p class="Codice"><span>    </span>UNION</p>
<p class="Codice"><span>    </span>SELECT MIN(DISP2_ALLE) FROM GIORNI</p>
<p class="Codice"><span>    </span>WHERE GIORNO = @data</p>
<p class="Codice"><span>    </span>AND ID_RISORSA = @IdRisorsa</p>
<p class="Codice"><span>    </span>AND DISP2_ALLE &gt;= @Orario</p>
<p class="Codice"><span>    </span>UNION</p>
<p class="Codice"><span>    </span>SELECT MIN(DISP3_ALLE) FROM GIORNI</p>
<p class="Codice"><span>    </span>WHERE GIORNO = @data</p>
<p class="Codice"><span>    </span>AND ID_RISORSA = @IdRisorsa</p>
<p class="Codice"><span>    </span>AND DISP3_ALLE &gt;= @Orario</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>  </span>SELECT @OraFineIntervallo = MIN(ALLE) FROM #TempTable</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>  </span>DROP TABLE #TempTable</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>  </span>PRINT @OraInizioIntervallo</p>
<p class="Codice"><span>  </span>PRINT @OraFineIntervallo</p>
<p class="Codice"><span>  </span>RETURN 0</p>
<p class="Codice">END</p>
<p class="Codice">GO</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
</div>
<p><b>VerificaPrenotabilitaRisorsa</b></p>
<p class="MsoNormal">Questa procedura verifica che una risorsa sia disponibile in una particolare fascia oraria. Essa restituisce un numero che può assumere i seguenti valori:</p>
<p class="MsoNormal">0: la risorsa è disponibile</p>
<p class="MsoNormal">1: la risorsa è prenotabile ma non disponibile</p>
<p class="MsoNormal">2: la risorsa non è prenotabile.</p>
<div style="border:1.5pt solid gray;padding:1pt 10pt;">
<p class="Codice">CREATE PROCEDURE VerificaPrenotabilitaRisorsa</p>
<p class="Codice"><span> </span>(@IdRisorsa int,</p>
<p class="Codice"><span>         </span>@Data datetime,</p>
<p class="Codice"><span>         </span>@OraDa datetime,</p>
<p class="Codice"><span>         </span>@OraA datetime)</p>
<p class="Codice">AS</p>
<p class="Codice">BEGIN</p>
<p class="Codice"><span>  </span>&#8211; CONTROLLO DELLE DISPONIBILITA&#8217; &#8211;</p>
<p class="Codice"><span>  </span>&#8211; Errore codice 3</p>
<p class="Codice"><!--[if gte vml 1]&amp;gt;   &amp;lt;![endif]--><!--[if !vml]--><span style="position:absolute;z-index:12;left:0;margin-left:222px;margin-top:7px;width:330px;height:41px;"></span></p>
<p>&#8211; Il primo controllo di questa procedura riguarda la qualità dei dati immessi. Se i dati sono<br />
&#8211; inconsistenti restituisce 3 ed esce.<br />
<!--[endif]--><span>  </span>IF @OraDa &gt;= @OraA</p>
<p class="Codice"><span>  </span>BEGIN</p>
<p class="Codice"><span>    </span>RETURN 3</p>
<p class="Codice"><span>  </span>END</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>  </span>&#8211; Errore codice 2</p>
<p class="Codice"><!--[if gte vml 1]&amp;gt;   &amp;lt;![endif]--><!--[if !vml]--><span style="position:absolute;z-index:13;left:0;margin-left:424px;margin-top:0;width:89px;height:274px;"></span></p>
<p><!--[endif]-->&#8211; Verifica che sia presente in archivio almeno un intervallo di prenotabilità che racchiuda<br />
&#8211; completamente l’intervallo dato in input. Se non esiste restituisce 2 ed esce.<br />
<span></span>IF NOT EXISTS<span>  </span>(SELECT * FROM GIORNI</p>
<p class="Codice"><span>                  </span>WHERE GIORNO = @Data</p>
<p class="Codice"><span>                  </span>AND ID_RISORSA = @IdRisorsa</p>
<p class="Codice"><span>                  </span>AND DISP_DALLE &lt;= @OraDa</p>
<p class="Codice"><span>                  </span>AND DISP_ALLE &gt;= @OraDa</p>
<p class="Codice"><span>                  </span>AND DISP_DALLE &lt;= @OraA</p>
<p class="Codice"><span>                  </span>AND DISP_ALLE &gt;= @OraA)</p>
<p class="Codice"><span>  </span>AND NOT EXISTS (SELECT * FROM GIORNI</p>
<p class="Codice"><span>                  </span>WHERE GIORNO = @Data</p>
<p class="Codice"><span>                  </span>AND ID_RISORSA = @IdRisorsa</p>
<p class="Codice"><span>                  </span>AND DISP2_DALLE &lt;= @OraDa</p>
<p class="Codice"><span>                  </span>AND DISP2_ALLE &gt;= @OraDa</p>
<p class="Codice"><span>                  </span>AND DISP2_DALLE &lt;= @OraA</p>
<p class="Codice"><span>                  </span>AND DISP2_ALLE &gt;= @OraA)</p>
<p class="Codice"><span>  </span>AND NOT EXISTS (SELECT * FROM GIORNI</p>
<p class="Codice"><span>                  </span>WHERE GIORNO = @Data</p>
<p class="Codice"><span>                  </span>AND ID_RISORSA = @IdRisorsa</p>
<p class="Codice"><span>                  </span>AND DISP3_DALLE &lt;= @OraDa</p>
<p class="Codice"><span>                  </span>AND DISP3_ALLE &gt;= @OraDa</p>
<p class="Codice"><span>  </span><span>                </span>AND DISP3_DALLE &lt;= @OraA</p>
<p class="Codice"><span>                  </span>AND DISP3_ALLE &gt;= @OraA)</p>
<p class="Codice"><span>  </span>BEGIN</p>
<p class="Codice"><span>    </span>RETURN 2</p>
<p class="Codice"><span>  </span>END</p>
<p class="Codice"><!--[if gte vml 1]&amp;gt;   &amp;lt;![endif]--><!--[if !vml]--><span></span></p>
<p><!--[endif]--><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>  </span>&#8211; CONTROLLO DELLE PRENOTAZIONI &#8211;</p>
<p class="Codice"><span>  </span>&#8211; Errore codice 1</p>
<p class="Codice">&#8211; Verifica che non ci siano in archivio prenotazioni che s’intreccino con l’intervallo dato in input.<br />
&#8211; Se sì restituisce 1 ed esce.<br />
<span></span>IF EXISTS (SELECT * FROM PRENOTAZIONI</p>
<p class="Codice"><span>             </span>WHERE GIORNO = @Data</p>
<p class="Codice"><span>           </span><span>  </span>AND ID_RISORSA = @IdRisorsa</p>
<p class="Codice"><span>             </span>AND DA_ORA &lt; @OraA</p>
<p class="Codice"><span>             </span>AND A_ORA &gt;= @OraA)</p>
<p class="Codice"><span>  </span>BEGIN</p>
<p class="Codice"><span>    </span>RETURN 1</p>
<p class="Codice"><span>  </span>END</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>  </span>&#8211; Errore codice 1</p>
<p class="Codice"><span>  </span>IF EXISTS (SELECT * FROM PRENOTAZIONI</p>
<p class="Codice"><span>             </span>WHERE GIORNO = @Data</p>
<p class="Codice"><span>             </span>AND ID_RISORSA = @IdRisorsa</p>
<p class="Codice"><span>             </span>AND DA_ORA &lt;= @OraDa</p>
<p class="Codice"><span>             </span>AND A_ORA &gt; @OraDa)</p>
<p class="Codice"><span>  </span>BEGIN</p>
<p class="Codice"><span>    </span>RETURN 1</p>
<p class="Codice"><span>  </span>END</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>  </span>RETURN 0</p>
<p class="Codice">END</p>
</div>
<p><b>Function</b></p>
<p class="MsoNormal">Le funzioni sono una prerogativa specifica del MS-SQL Server 2000. Quelle qui descritte sono concepite per in massima parte per rendere i controlli e le funzionalità relative al calcolo delle fasce orarie di disponibilità delle risorse, ma anche per altre funzionalità.</p>
<p><b>ImmaginePrenotazioni</b></p>
<p class="MsoNormal">Questa funzione restituisce una tabella strutturata in maniera tale da indicare per ciascuna data e per uno specifico time-slice. Questo particolare tipo di funzione è detto “Funzione tabellare”.</p>
<p class="MsoNormal">L’obiettivo di questa funzione è di fornire al client una stuttura fondamentale sulla quale poggiare per la realizzazione della grafica riguardante la disponibilità di una risorsa in un particolare giorno.</p>
<p class="MsoNormal">Il parametro di input @TimeSliceInMin determina la precisione nella rappresentazione delle prenotazioni e degli intervalli di prenotabilità: una piccola modifica nell’ambito del programma client può agire in maniera da passare un valore numerico differente ed avere una rappresentazione grafica migliore.</p>
<p class="MsoNormal">Il campo STATO della tabella @TabellaPrenotazioni indica lo stato del time slice e per esso i valori possibili sono:</p>
<p class="MsoNormal">&#8216;F&#8217;: time-slice disponibile</p>
<p class="MsoNormal">&#8216;O&#8217;: time-slice prenotabile ma occupato</p>
<p class="MsoNormal">&#8216;N&#8217;: time-slice non prenotabile</p>
<p class="MsoNormal">Il parametro @ErrorCode serve ad indicare se si sono verificati degli errori.</p>
<p class="MsoNormal">NOTA: Questa procedura lavora su record della tabella Giorni dando per scontato che essi esistano. Infatti il client non permette di accedere alle funzionalità offerte da questa funzione se non dopo avere lanciato almeno una volta pa procedura AbilitPrenotabilitaRisorsa.</p>
<div style="border:1.5pt solid gray;padding:1pt 10pt;">
<p class="Codice">CREATE FUNCTION ImmaginePrenotazioni</p>
<p class="Codice"><span> </span>(@IdRisorsa int,</p>
<p class="Codice"><span>         </span>@StartDate datetime,</p>
<p class="Codice"><span> </span><span> </span>@EndDate datetime,</p>
<p class="Codice"><span>         </span>@TimeSliceInMin int)</p>
<p class="Codice"><!--[if gte vml 1]&amp;gt;   &amp;lt;![endif]--><!--[if !vml]--><span style="position:absolute;z-index:15;left:0;margin-left:337px;margin-top:2px;width:195px;height:36px;"></span></p>
<p><!--[endif]-->&#8211; La tabella @TabellaPrenotazioni costituisce l’output della funzione.<br />
RETURNS @TabellaPrenotazioni TABLE</p>
<p class="Codice"><span> </span>(Data datetime,</p>
<p class="Codice"><span> </span><span> </span>Orario datetime,</p>
<p class="Codice"><span>         </span>Stato char)</p>
<p class="Codice">AS</p>
<p class="Codice">BEGIN</p>
<p class="Codice"><span>  </span>&#8211; Errore codice 1</p>
<p class="Codice"><!--[if gte vml 1]&amp;gt;   &amp;lt;![endif]--><!--[if !vml]--><span style="position:absolute;z-index:16;left:0;margin-left:453px;margin-top:10px;width:60px;height:127px;"></span></p>
<p><!--[endif]-->&#8211; Effettua alcuni controlli sui dati di input. Se vanno male esce.<br />
<span> </span>if @EndDate &lt; @StartDate</p>
<p class="Codice"><span>  </span>BEGIN</p>
<p class="Codice"><span>    </span>RETURN</p>
<p class="Codice"><span>  </span>END</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>  </span>&#8211; Errore codice 2</p>
<p class="Codice"><span>  </span>if @TimeSliceInMin &lt; 00 OR @TimeSliceInMin &gt; 60</p>
<p class="Codice"><span>  </span>BEGIN</p>
<p class="Codice"><span>    </span>RETURN</p>
<p class="Codice"><span>  </span>END</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>  </span>DECLARE @TempDate datetime</p>
<p class="Codice"><span>  </span>DECLARE @EndTempDate datetime</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>  </span>DECLARE @DispDalle datetime</p>
<p class="Codice"><span>  </span>DECLARE @DispAlle datetime</p>
<p class="Codice"><span>  </span>DECLARE @Disp2Dalle datetime</p>
<p class="Codice"><span>  </span>DECLARE @Disp2Alle datetime</p>
<p class="Codice"><span>  </span>DECLARE @Disp3Dalle datetime</p>
<p class="Codice"><span>  </span>DECLARE @Disp3Alle datetime</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>  </span>DECLARE @TempTime datetime</p>
<p class="Codice"><span>  </span>DECLARE @Stato char</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><!--[if gte vml 1]&amp;gt;   &amp;lt;![endif]--><!--[if !vml]--><span style="position:absolute;z-index:17;left:0;margin-left:376px;margin-top:12px;width:166px;height:166px;"></span></p>
<p><!--[endif]-->&#8211; Genera un cursore, GiorniIntervallo, che consente alla procedura di funzionare anche se nei parametri<br />
&#8211; d’ingresso è presente un intervallo di date invece che una data sola. Nell’ambito del progetto questa<br />
&#8211; funzionalità non è sfruttata ma la generalità della procedura serve a rendere l’architettura aperta.<br />
<span></span>DECLARE GiorniIntervallo CURSOR FOR</p>
<p class="Codice"><span>    </span>SELECT GIORNO,</p>
<p class="Codice"><span>           </span>DISP_DALLE,</p>
<p class="Codice"><span>           </span>DISP_ALLE,</p>
<p class="Codice"><span>           </span>DISP2_DALLE,</p>
<p class="Codice"><span>           </span>DISP2_ALLE,</p>
<p class="Codice"><span>      </span><span>     </span>DISP3_DALLE,</p>
<p class="Codice"><span>           </span>DISP3_ALLE</p>
<p class="Codice"><span>    </span>FROM GIORNI</p>
<p class="Codice"><span>    </span>WHERE ID_RISORSA = @IdRisorsa</p>
<p class="Codice"><span>    </span>AND GIORNO &gt;= @StartDate</p>
<p class="Codice"><span>    </span>AND GIORNO &lt;= @EndDate</p>
<p class="Codice"><!--[if gte vml 1]&amp;gt;   &amp;lt;![endif]--><!--[if !vml]--><span style="position:absolute;z-index:18;left:0;margin-left:318px;margin-top:3px;width:262px;height:61px;"></span></p>
<p><!--[endif]--><span>  </span>&#8211; La variabile @TempTime serve a scandire i time slice ed il suo valore viene incrementato ad<br />
&#8211; ogni ciclo di una quantità pari al valore del parametro @TimeSliceInMin.<br />
OPEN GiorniIntervallo</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>  </span>FETCH NEXT FROM GiorniIntervallo</p>
<p class="Codice"><span>  </span>INTO @TempDate,</p>
<p class="Codice"><span>       </span>@DispDalle,</p>
<p class="Codice"><span>       </span>@DispAlle,</p>
<p class="Codice"><!--[if gte vml 1]&amp;gt;   &amp;lt;![endif]--><!--[if !vml]--><span style="position:absolute;z-index:19;left:0;margin-left:318px;margin-top:9px;width:262px;height:108px;"></span></p>
<p><!--[endif]-->&#8211; L’innesto di funzioni ISNULL presente qui sotto è un artificio che serve a determinare il massimo<br />
&#8211; tra i valori contenuti nelle variabili coinvolte escludendo i valori nulli. Questo artificio è<br />
&#8211; possibile perché si assume che i valori presenti nei campi @DispAlle, @Disp2Alle e @Disp3Alle siano<br />
&#8211; crescenti mentre almeno il campo @DispAlle deve per definizione essere non nullo.<br />
<span> </span>@Disp2Dalle,</p>
<p class="Codice"><span>       </span>@Disp2Alle,</p>
<p class="Codice"><span>       </span>@Disp3Dalle,</p>
<p class="Codice"><span>       </span>@Disp3Alle</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>  </span>WHILE @@FETCH_STATUS = 0</p>
<p class="Codice"><span>  </span>BEGIN</p>
<p class="Codice"><span>    </span>SELECT @TempTime = @DispDalle</p>
<p class="Codice"><span>    </span>SELECT @EndTempDate = ISNULL(@Disp3Alle, ISNULL(@Disp2Alle, @DispAlle))</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>    </span>WHILE @TempTime &lt; @EndTempDate</p>
<p class="Codice"><span>    </span>BEGIN</p>
<p class="Codice"><span>      </span>IF (@TempTime &gt;= @DispDalle) AND (@TempTime &lt; @DispAlle)</p>
<p class="Codice"><span>      </span>OR (@TempTime &gt;= @Disp2Dalle) AND (@TempTime &lt; @Disp2Alle)</p>
<p class="Codice"><span>      </span>OR (@TempTime &gt;= @Disp3Dalle) AND (@TempTime &lt; @Disp3Alle)</p>
<p class="Codice"><!--[if gte vml 1]&amp;gt;   &amp;lt;![endif]--><!--[if !vml]--><span style="position:absolute;z-index:20;left:0;margin-left:261px;margin-top:5px;width:339px;height:61px;"></span></p>
<p><!--[endif]--><span>        </span>&#8211; Il primo controllo riguarda la prenotabilità della risorsa. Se va a buon fine lo stato del<br />
&#8211; time-slice viene posto momentaneamente a “F” (free) ad indicare che la risorsa è prenotabile e libera,<br />
&#8211; altrimenti viene posto a “N” (non prenotabile) ad indicare che non è prenotabile.<br />
SELECT @Stato = &#8216;F&#8217;</p>
<p class="Codice"><span>      </span>ELSE</p>
<p class="Codice"><span> </span><span>       </span>SELECT @Stato = &#8216;N&#8217;</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><!--[if gte vml 1]&amp;gt;   &amp;lt;![endif]--><!--[if !vml]--><span style="position:absolute;z-index:21;left:0;margin-left:414px;margin-top:12px;width:186px;height:109px;"></span></p>
<p><!--[endif]-->&#8211; Il secondo controllo è sulle prenotazioni e viene effettuato solo se lo stato del time-slice<br />
&#8211; dopo il primo controllo è posto a “F”. Infatti, se esiste una qualche prenotazione che lo coinvolge<br />
&#8211; il suo valore viene cambiato e diventa “O” (occupato).<br />
<span> </span>IF @Stato = &#8216;F&#8217;</p>
<p class="Codice"><span>        </span>IF EXISTS (SELECT * FROM PRENOTAZIONI</p>
<p class="Codice"><span>                   </span>WHERE GIORNO = @TempDate</p>
<p class="Codice"><span>                   </span>AND ID_RISORSA = @IdRisorsa</p>
<p class="Codice"><span>                   </span>AND DA_ORA &lt;= @TempTime</p>
<p class="Codice"><span>                   </span>AND A_ORA &gt; @TempTime)</p>
<p class="Codice"><span>          </span>SELECT @Stato = &#8216;O&#8217;</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>      </span>INSERT INTO @TabellaPrenotazioni VALUES (@TempDate, @TempTime, @Stato)</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>      </span>SELECT @TempTime = DATEADD(minute, @TimeSliceInMin, @TempTime)</p>
<p class="Codice"><span>    </span>END</p>
<p class="Codice"><span>    </span></p>
<p class="Codice"><span>    </span>FETCH NEXT FROM GiorniIntervallo</p>
<p class="Codice"><span>    </span>INTO @TempDate,</p>
<p class="Codice"><span>         </span>@DispDalle,</p>
<p class="Codice"><span>         </span>@DispAlle,</p>
<p class="Codice"><span>         </span>@Disp2Dalle,</p>
<p class="Codice"><span>         </span>@Disp2Alle,</p>
<p class="Codice"><span>         </span>@Disp3Dalle,</p>
<p class="Codice"><span>         </span>@Disp3Alle</p>
<p class="Codice"><span>  </span>END</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>  </span>CLOSE GiorniIntervallo</p>
<p class="Codice"><span>  </span>DEALLOCATE GiorniIntervallo</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>  </span>RETURN</p>
<p class="Codice">END</p>
</div>
<p><b>ImmaginePrenotazioniUtente</b></p>
<p class="MsoNormal">Questa funzione restituisce una tabella strutturata in maniera tale da indicare per l&#8217;utente selezionato tutta la lista delle prenotazioni effettuate sulle risorse in archivio.</p>
<p class="MsoNormal">Questa funzione fornisce al client la base per la visualizzazione delle prenotazioni, lista dalla quale selezionare le eventuali prenotazioni da cancellare.</p>
<div style="border:1.5pt solid gray;padding:1pt 10pt;">
<p class="Codice">CREATE FUNCTION ImmaginePrenotazioniUtente</p>
<p class="Codice"><span> </span>(@Login varchar(20))</p>
<p class="Codice"><!--[if gte vml 1]&amp;gt;   &amp;lt;![endif]--><!--[if !vml]--><span style="position:absolute;z-index:22;left:0;margin-left:357px;margin-top:7px;width:185px;height:61px;"></span></p>
<p>&#8211; Il parametro di output @TabellaPrenotazioni conterrà la lista delle prenotazioni effettuate da uno specifico utente,RETURNS @TabellaPrenotazioni TABLE</p>
<p class="Codice"><span> </span>(Data datetime,</p>
<p class="Codice"><span> </span><span> </span>DaOra datetime,</p>
<p class="Codice"><span> </span><span> </span>AOra datetime,</p>
<p class="Codice"><span>         </span>IdRisorsa int,</p>
<p class="Codice"><span>         </span>NomeRisorsa varchar(30))</p>
<p class="Codice">AS</p>
<p class="Codice">BEGIN</p>
<p class="Codice"><span>  </span>INSERT INTO @TabellaPrenotazioni (Data, DaOra, AOra, IdRisorsa, NomeRisorsa)</p>
<p class="Codice"><!--[if gte vml 1]&amp;gt;   &amp;lt;![endif]--><!--[if !vml]--><span style="position:absolute;z-index:23;left:0;margin-left:337px;margin-top:14px;width:224px;height:61px;"></span></p>
<p>&#8211;La query che alimenta la tabella @TabellaPrenotazioni è una semplice join tra la tabelle&#8211;delle prenotazioni e quella delle risorse.</p>
<p><span>    </span>SELECT PRENOTAZIONI.GIORNO,</p>
<p class="Codice"><span>           </span>PRENOTAZIONI.DA_ORA,</p>
<p class="Codice"><span>           </span>PRENOTAZIONI.A_ORA,</p>
<p class="Codice"><span>           </span>PRENOTAZIONI.ID_RISORSA,</p>
<p class="Codice"><span>           </span>RISORSE.NOME</p>
<p class="Codice"><span>    </span>FROM PRENOTAZIONI</p>
<p class="Codice"><span>    </span>INNER JOIN RISORSE</p>
<p class="Codice"><span>      </span>ON RISORSE.ID_RISORSA = PRENOTAZIONI.ID_RISORSA</p>
<p class="Codice"><span>    </span>WHERE LOGIN = @Login</p>
<p class="Codice"><span>    </span>ORDER BY PRENOTAZIONI.GIORNO,</p>
<p class="Codice"><span>             </span>PRENOTAZIONI.DA_ORA</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>  </span>RETURN</p>
<p class="Codice">END</p>
</div>
<p><b>NuovoIdRisorse</b></p>
<p class="MsoNormal">Questa funzione serve a determinare il valore del campo ID_RISORSA per una nuova risorsa appena introdotta in archivio.</p>
<div style="border:1.5pt solid gray;padding:1pt 10pt;">
<p class="Codice">CREATE FUNCTION NuovoIdRisorse ()</p>
<p class="Codice">RETURNS int</p>
<p class="Codice"><!--[if gte vml 1]&amp;gt;   &amp;lt;![endif]--><!--[if !vml]--><span style="position:absolute;z-index:24;left:0;margin-left:251px;margin-top:1px;width:320px;height:51px;"></span></p>
<p>&#8211;La query che determina il nuovo valore per il campo ID_RISORSA calcola il massimo&#8211;valore del campo e lo aumenta di uno; se il valore è nullo restituisce 1.</p>
<p>AS</p>
<p class="Codice">BEGIN</p>
<p class="Codice"><span>  </span>DECLARE @NuovoId int</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>  </span>SELECT @NuovoId = ISNULL(MAX(ID_RISORSA), 0) + 1 FROM RISORSE</p>
<p class="Codice"><!--[if !supportEmptyParas]--> <!--[endif]--></p>
<p class="Codice"><span>  </span>RETURN @NuovoId</p>
<p class="Codice">END</p>
</div>
<p><b>INSERT</b></p>
<p class="MsoNormal">Per concludere la generazione del database è necessario introdurre un utente standard, di tipo amministratore, che sia la base di partenza per il funzionamento di tutto il sistema informatico. Questo utente avrà un login ed una password noti (entrambi uguali ad “sa”).</p>
<div style="border:1.5pt solid gray;padding:1pt 10pt;">
<p class="Codice">INSERT INTO UTENTI (LOGIN, PASSWORD, NOME, COGNOME, TIPO)</p>
<p class="Codice"><span>          </span><span>  </span>VALUES (&#8216;sa&#8217;, &#8216;sa&#8217;, &#8216;Amministratore&#8217;, &#8216;Standard&#8217;, &#8216;A&#8217;)</p>
</div>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/gianfrasoft.wordpress.com/11/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/gianfrasoft.wordpress.com/11/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/gianfrasoft.wordpress.com/11/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/gianfrasoft.wordpress.com/11/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/gianfrasoft.wordpress.com/11/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/gianfrasoft.wordpress.com/11/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/gianfrasoft.wordpress.com/11/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/gianfrasoft.wordpress.com/11/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/gianfrasoft.wordpress.com/11/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/gianfrasoft.wordpress.com/11/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/gianfrasoft.wordpress.com/11/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/gianfrasoft.wordpress.com/11/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/gianfrasoft.wordpress.com/11/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/gianfrasoft.wordpress.com/11/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/gianfrasoft.wordpress.com/11/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/gianfrasoft.wordpress.com/11/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gianfrasoft.wordpress.com&amp;blog=2822728&amp;post=11&amp;subd=gianfrasoft&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://gianfrasoft.wordpress.com/2008/02/24/realizzazione-di-un-servizio-di-prenotazione-risorse-on-line-in-sql/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/905a08842a0c78883ed66254de5fc75a?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">gianfrasoft</media:title>
		</media:content>

		<media:content url="http://gianfrasoft.netsons.org/mysoftware/SchemaER.JPG" medium="image">
			<media:title type="html">Modello ER</media:title>
		</media:content>
	</item>
		<item>
		<title>Mini Master Mind</title>
		<link>http://gianfrasoft.wordpress.com/2008/02/17/mini-master-mind/</link>
		<comments>http://gianfrasoft.wordpress.com/2008/02/17/mini-master-mind/#comments</comments>
		<pubDate>Sun, 17 Feb 2008 11:13:09 +0000</pubDate>
		<dc:creator>gianfrasoft</dc:creator>
				<category><![CDATA[My Software]]></category>

		<guid isPermaLink="false">http://gianfrasoft.wordpress.com/?p=9</guid>
		<description><![CDATA[Classico gioco del Master Mind in cui è consentito all&#8217;utente sia di giocare che di osservare il programma che individua una combinazione elaborata dall&#8217;utente stesso. Ralizzato in maniera da riprodurrela grafica del classico Mini Master Mind in commercio in Italia negli anni &#8217;80. Per scaricare il programma free, cliccare qui. Il gioco richiede l&#8217;utilizzo del [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gianfrasoft.wordpress.com&amp;blog=2822728&amp;post=9&amp;subd=gianfrasoft&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<div style="text-align:center;"><img src="http://img45.imageshack.us/img45/8809/splashmasterminduf7.jpg" alt="mastermind" /></div>
<p>Classico gioco del Master Mind in cui è consentito all&#8217;utente sia di giocare che di osservare il programma che individua una combinazione elaborata dall&#8217;utente stesso. Ralizzato in maniera da riprodurrela grafica del classico Mini Master Mind in commercio in Italia negli anni &#8217;80.</p>
<p><span id="more-9"></span>Per scaricare il programma <em>free</em>, cliccare <a title="Mini Master Mind" href="http://rapidshare.com/files/159878494/MiniMasterMind.zip">qui</a>.</p>
<p>Il gioco richiede l&#8217;utilizzo del mouse per trascinare i pioli colorati sullo schema principale:</p>
<p align="center"><img src="http://img369.imageshack.us/img369/3007/mastermindmainsl9.jpg" alt="master mind" /> <img src="http://img384.imageshack.us/img384/9976/mastermindplayvt2.jpg" alt="master mind paly" /></p>
<p>Nel caso in cui sia il programma a dover individuare la combinazione, i pioli colorati saranno il bianco ed il nero:</p>
<div style="text-align:center;"><img src="http://img255.imageshack.us/img255/7895/mastermindplay2wl9.jpg" alt="master mind play" /></div>
<p>Il programma è realizzato in linguaggio Delphi 7 per Windows; l&#8217;algorimo per la risoluzione è basato sulla enumerazione totale delle soluzioni, che vengono poi scartate man mano che l&#8217;utente indica coi pioli bianchi e neri quelle errate.</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/gianfrasoft.wordpress.com/9/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/gianfrasoft.wordpress.com/9/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/gianfrasoft.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/gianfrasoft.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/gianfrasoft.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/gianfrasoft.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/gianfrasoft.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/gianfrasoft.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/gianfrasoft.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/gianfrasoft.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/gianfrasoft.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/gianfrasoft.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/gianfrasoft.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/gianfrasoft.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/gianfrasoft.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/gianfrasoft.wordpress.com/9/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gianfrasoft.wordpress.com&amp;blog=2822728&amp;post=9&amp;subd=gianfrasoft&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://gianfrasoft.wordpress.com/2008/02/17/mini-master-mind/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/905a08842a0c78883ed66254de5fc75a?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">gianfrasoft</media:title>
		</media:content>

		<media:content url="http://img45.imageshack.us/img45/8809/splashmasterminduf7.jpg" medium="image">
			<media:title type="html">mastermind</media:title>
		</media:content>

		<media:content url="http://img369.imageshack.us/img369/3007/mastermindmainsl9.jpg" medium="image">
			<media:title type="html">master mind</media:title>
		</media:content>

		<media:content url="http://img384.imageshack.us/img384/9976/mastermindplayvt2.jpg" medium="image">
			<media:title type="html">master mind paly</media:title>
		</media:content>

		<media:content url="http://img255.imageshack.us/img255/7895/mastermindplay2wl9.jpg" medium="image">
			<media:title type="html">master mind play</media:title>
		</media:content>
	</item>
		<item>
		<title>One Million Sudoku</title>
		<link>http://gianfrasoft.wordpress.com/2008/02/16/one-million-sudoku/</link>
		<comments>http://gianfrasoft.wordpress.com/2008/02/16/one-million-sudoku/#comments</comments>
		<pubDate>Sat, 16 Feb 2008 15:59:50 +0000</pubDate>
		<dc:creator>gianfrasoft</dc:creator>
				<category><![CDATA[My Software]]></category>
		<category><![CDATA[One Million Sudoku generate solve genera risolvi free]]></category>

		<guid isPermaLink="false">http://gianfrasoft.wordpress.com/?p=8</guid>
		<description><![CDATA[One Million Sudoku è un programma completamente free orientato a quanti scrivono sudoku per mestiere. Esso consente di risolvere e quindi di verificare la risolvibilità di sudoku introdotti dall&#8217;utente, individuando quelli che non risolvibili e quelli che possiedono più di una soluzione; su richiesta dell&#8217;utente ne genera di propri. Per scaricare una copia del programma [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gianfrasoft.wordpress.com&amp;blog=2822728&amp;post=8&amp;subd=gianfrasoft&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<div style="text-align:center;"><img src="http://img99.imageshack.us/img99/6934/splashsudokuhb3.jpg" alt="sudoku" /></div>
<p>One Million Sudoku è un programma completamente <em>free</em> orientato a quanti scrivono sudoku per mestiere. Esso consente di risolvere e quindi di verificare la risolvibilità di sudoku introdotti dall&#8217;utente, individuando quelli che non risolvibili e quelli che possiedono più di una soluzione; su richiesta dell&#8217;utente ne genera di propri.</p>
<p><span id="more-8"></span>Per scaricare una copia del programma click <a title="One Million Sudoku - free" href="http://rapidshare.com/files/159879524/OneMillionSudoku.zip">qui</a></p>
<p><!--more--></p>
<p>Il programma può anche servire da sorgente infinita di gioco per quanti amano affrontare e risolvere questo tipo di rompicapo.</p>
<p>Nella finestra principale del programma sono presenti due schemi di sudoku: uno schema principale ed uno schema della soluzione (più piccolo a sinistra):</p>
<div style="text-align:center;"><img src="http://img220.imageshack.us/img220/7301/sudokuplayji6.jpg" alt="sudoku" /></div>
<p>E&#8217; possibile, appena lanciato il programma, introdurre i numeri nello schema principale mediante l&#8217;utilizzo del mouse ed interagire col menù per verificare i risultati. Le voci principali sono due:</p>
<ul>
<li>Game</li>
<li>Options</li>
</ul>
<p>Game attiva le operazioni:</p>
<ol>
<li><em>create your own sudoku</em>: abilita alla scrittura di sudoku nello schema principale;</li>
<li><em>solve the sudoku</em>: verifica l&#8217;esistenza di una soluzione univoca per il sudoku descritto nello schema principal. Se la trova la riporta nello schema secondario;</li>
<li><em>auto-generate a new sudoku</em>: senza perder tempo genera automaticamente e randomicamente un nuovo sudoku nello schema principaleriportandone la soluzione nello schema secondario.</li>
</ol>
<p>La voce Options permette di attivare il <em>diagonal filter</em> che impone a tutti i sudoku in lavorazione che anche la sequenza di numeri sulle diagonali rispetti l&#8217;univocità di ciascun numero.<!--more--></p>
<p>Qualche dettaglio tecnico: questo programma è scritto in linguaggio Delphi 7 per Windows. L&#8217;algoritmo per la risoluzione dei sudoku è un algoritmo di backtracking.</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/gianfrasoft.wordpress.com/8/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/gianfrasoft.wordpress.com/8/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/gianfrasoft.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/gianfrasoft.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/gianfrasoft.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/gianfrasoft.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/gianfrasoft.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/gianfrasoft.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/gianfrasoft.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/gianfrasoft.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/gianfrasoft.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/gianfrasoft.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/gianfrasoft.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/gianfrasoft.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/gianfrasoft.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/gianfrasoft.wordpress.com/8/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gianfrasoft.wordpress.com&amp;blog=2822728&amp;post=8&amp;subd=gianfrasoft&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://gianfrasoft.wordpress.com/2008/02/16/one-million-sudoku/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/905a08842a0c78883ed66254de5fc75a?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">gianfrasoft</media:title>
		</media:content>

		<media:content url="http://img99.imageshack.us/img99/6934/splashsudokuhb3.jpg" medium="image">
			<media:title type="html">sudoku</media:title>
		</media:content>

		<media:content url="http://img220.imageshack.us/img220/7301/sudokuplayji6.jpg" medium="image">
			<media:title type="html">sudoku</media:title>
		</media:content>
	</item>
		<item>
		<title>PHP &#8211; Ispezione delle strutture complesse (array e oggetti)</title>
		<link>http://gianfrasoft.wordpress.com/2008/02/09/php-ispezione-delle-strutture-complesse-array-e-oggetti/</link>
		<comments>http://gianfrasoft.wordpress.com/2008/02/09/php-ispezione-delle-strutture-complesse-array-e-oggetti/#comments</comments>
		<pubDate>Sat, 09 Feb 2008 16:56:29 +0000</pubDate>
		<dc:creator>gianfrasoft</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[array]]></category>
		<category><![CDATA[ispezione]]></category>
		<category><![CDATA[PHP array ispezione di strutture complesse XML]]></category>
		<category><![CDATA[strutture complesse]]></category>
		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://gianfrasoft.wordpress.com/?p=5</guid>
		<description><![CDATA[Consideriamo di dover accedere ad un array associativo di cui non si conosce la reale struttura. L&#8217;array può contenere, in ciascuna locazione, informazioni di qualsiasi tipo: esso può contenere contemporaneamente stringhe, interi o anche altri array associativi. In PHP è facile accedere al contenuto di un array associativo anche se non se ne conosce la [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gianfrasoft.wordpress.com&amp;blog=2822728&amp;post=5&amp;subd=gianfrasoft&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Consideriamo di dover accedere ad un array associativo di cui non si conosce la reale struttura. L&#8217;array può contenere, in ciascuna locazione, informazioni di qualsiasi tipo: esso può contenere contemporaneamente stringhe, interi o anche altri array associativi.</p>
<p>In PHP è facile accedere al contenuto di un array associativo anche se non se ne conosce la struttura interna. Per far ciò basta effettuare un semplice ciclo &#8220;foreach<em>&#8221; </em>come descritto di seguito:</p>
<p align="center"><strong>foreach($array as $name =&gt; $value)</strong></p>
<p>dove la variabile $array contiene l&#8217;array che vogliamo esaminare e le variabili $name e $value conterranno, ad ogni ciclo, il nome ed il valore di ciascun elemento dell&#8217;array.</p>
<p>Ad ogni ciclo, per stabilire se l&#8217;elemento dell&#8217;array associativo che stiamo esaminando è a sua volta un array, basta far riferimento alla funzione <em>is_array</em> del PHP: in caso positivo si può richiamare la stessa funzione ricorsivamente perché esamini il contenuto del nuovo array.</p>
<p>Generiamo, quindi, una struttura XML che in corrispondenza di ogni array produce un nodo XML che indicheremo con &lt;bag&gt; ed in corrispondenza di ciascun elemento semplice produca un nodo XML &lt;item&gt; contenente tra gli attributi il nome ed il tipo dello stesso:</p>
<pre><span id="more-5"></span>function inspect_array($array, $indent, $string)
{
  foreach($array as $name =&gt; $value)
  {
    if (is_array($value))
    {
      $string = $string.$indent."&lt;"."bag"."name=\"$name\""." phpType=\"array\"&gt;\n";</pre>
<pre>      // ricorsione
      $string = inspect_array($value, $indent.' ', $string);
      $string = $string.$indent."&lt;/"."bag"."&gt;\n";
    }
    else
    {
      $string = $string.$indent."&lt;"."item"."name=\"$name\""." phpType=\"".
      gettype($value)."\"&gt;".htmlspecialchars($value)."&lt;/"."item"."&gt;\n";
    }
  }
  return $string;
}</pre>
<pre>$params = array_map_deep($_REQUEST["params"]);
$xmlstring = "&lt;?xml version=\"1.0\"?&gt;\n";
$xmlstring = $xmlstring."&lt;resultString&gt;\n";
$xmlstring = $xmlstring." &lt;"."bag name=\"result\"phpType=\"object\"&gt;\n";
$xmlstring = inspect_obj_array($params, ' ', $xmlstring);
$xmlstring = $xmlstring." &lt;/"."bag"."&gt;\n";
$xmlstring = $xmlstring."&lt;/resultString&gt;\n";</pre>
<p><!--more-->Sotto è riportato come esempio il risultato del processamento di un array contenente alcuni dati anagrafici: l&#8217;indirizzo è a sua volta un array contenente tre elementi semplici.</p>
<pre><!--more-->&lt;?xml version="1.0" ?&gt;
  &lt;resultString&gt;
    &lt;bag name="result" phpType="object"&gt;
      &lt;item name="nominativo" phpType="string"&gt;Gianfranco Fedele &lt;/item&gt;
      &lt;item name="eta" phpType="integer"&gt;31&lt;/item&gt;
      &lt;bag name="indirizzo" phpType="array"&gt;
        &lt;item name="via" phpType="string"&gt;via del Maratoneta&lt;/item&gt;
        &lt;item name="civico" phpType="integer"&gt;8&lt;/item&gt;
        &lt;item name="citta" phpType="string"&gt;Napoli&lt;/item&gt;
      &lt;/bag&gt;
    &lt;/bag&gt;
  &lt;/resultString&gt;</pre>
<p><!--more-->Nel caso in cui s&#8217;intenda esaminare oggetti (array contenenti oggetti o oggetti contenenti array), il PHP mette a disposizione una importante funzione che consente di esaminare il contenuto di un oggetto come fosse un array associativo. La funzione di chiama get_object_vars.<br />
Pertanto, volendo estendere la funzione al caso dell&#8217;ispezione, oltre che degli array associativi, anche degli oggetti, dovremo scrivere:</p>
<pre><!--more-->function inspect_obj_array($array, $indent, $string)
{
  foreach($array as $name =&gt; $value)</pre>
<pre>  {
    if (is_array($value))
    {
      $string = $string.$indent."&lt;"."bag"." name=\"$name\""." phpType=\"array\"&gt;\n";
      // ricorsione
      $string = inspect_obj_array($value, $indent.' ', $string);
      $string = $string.$indent."&lt;/"."bag"."&gt;\n";
    }</pre>
<pre>    if (is_object($value))
    {
      $string = $string.$indent."&lt;"."bag"." name=\"$name\""." phpType=\"object\"&gt;\n";</pre>
<pre>      // ricorsione
      $vars = get_object_vars($value);
      $string = inspect_obj_array($vars, $indent.' ', $string);</pre>
<pre>      $string = $string.$indent."&lt;/"."bag"."&gt;\n";</pre>
<pre>    }
    if (!(is_array($value)) &amp;&amp; (!is_object($value)))
    {
      $string = $string.$indent."&lt;"."item"." name=\"$name\""." phpType=\"".
      gettype($value)."\"&gt;".htmlspecialchars($value)."&lt;/"."item"."&gt;\n";
    }
  }
  return $string;
}</pre>
<pre>$params = array_map_deep($_REQUEST["params"]);$xmlstring = "&lt;?xml version=\"1.0\"?&gt;\n";
$xmlstring = $xmlstring."&lt;resultString&gt;\n";
$xmlstring = $xmlstring." &lt;"."bag name=\"result\" phpType=\"object\"&gt;\n";
$xmlstring = inspect_obj_array($params, ' ', $xmlstring);
$xmlstring = $xmlstring." &lt;/"."bag"."&gt;\n";
$xmlstring = $xmlstring."&lt;/resultString&gt;\n";</pre>
<p><!--more--></p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/gianfrasoft.wordpress.com/5/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/gianfrasoft.wordpress.com/5/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/gianfrasoft.wordpress.com/5/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/gianfrasoft.wordpress.com/5/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/gianfrasoft.wordpress.com/5/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/gianfrasoft.wordpress.com/5/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/gianfrasoft.wordpress.com/5/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/gianfrasoft.wordpress.com/5/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/gianfrasoft.wordpress.com/5/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/gianfrasoft.wordpress.com/5/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/gianfrasoft.wordpress.com/5/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/gianfrasoft.wordpress.com/5/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/gianfrasoft.wordpress.com/5/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/gianfrasoft.wordpress.com/5/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/gianfrasoft.wordpress.com/5/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/gianfrasoft.wordpress.com/5/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gianfrasoft.wordpress.com&amp;blog=2822728&amp;post=5&amp;subd=gianfrasoft&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://gianfrasoft.wordpress.com/2008/02/09/php-ispezione-delle-strutture-complesse-array-e-oggetti/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/905a08842a0c78883ed66254de5fc75a?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">gianfrasoft</media:title>
		</media:content>
	</item>
		<item>
		<title>PHP &#8211; Passaggio di parametri organizzati gerarchicamente</title>
		<link>http://gianfrasoft.wordpress.com/2008/02/09/php-passaggio-di-parametri-organizzati-gerarchicamente/</link>
		<comments>http://gianfrasoft.wordpress.com/2008/02/09/php-passaggio-di-parametri-organizzati-gerarchicamente/#comments</comments>
		<pubDate>Sat, 09 Feb 2008 16:15:39 +0000</pubDate>
		<dc:creator>gianfrasoft</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[dinamici]]></category>
		<category><![CDATA[input]]></category>
		<category><![CDATA[parametri]]></category>
		<category><![CDATA[PHP input parametri dinamici array_map_deep]]></category>

		<guid isPermaLink="false">http://gianfrasoft.wordpress.com/?p=4</guid>
		<description><![CDATA[Consideriamo un form che chiede all&#8217;utente di introdurre i propri dati anagrafici allo scopo di organizzarli in una struttura del tipo: dati_personali nominativo età indirizzo via civico città E&#8217; facile individuare in questa struttura dati l&#8217;albero delle informazioni che pone le proprie radici nel nodo dati_personali e che realizza tre livelli di profondità. Questo albero [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gianfrasoft.wordpress.com&amp;blog=2822728&amp;post=4&amp;subd=gianfrasoft&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Consideriamo un form che chiede all&#8217;utente di introdurre i propri dati anagrafici allo scopo di organizzarli in una struttura del tipo:</p>
<ul>
<li>dati_personali
<ul>
<li>nominativo</li>
<li>età</li>
<li>indirizzo
<ul>
<li>via</li>
<li>civico</li>
<li>città</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>E&#8217; facile individuare in questa struttura dati        l&#8217;albero delle informazioni che pone le proprie radici nel nodo <span class="charsStrong">dati_personali</span> e che realizza tre livelli di profondità. Questo albero contiene        in totale 7 nodi organizzati in 3 livelli.</p>
<p>In questo articolo esamineremo come sia possibile costruire una pagina dinamica in PHP che sia in grado di raccogliere le informazioni introdotte dall&#8217;utente nell&#8217;ambito di un form, e di elaborarle nel pieno rispetto della loro struttura gerarchica, qualunque sia in form. Nella fattispecie, la pagina dinamica recupererà le informazioni        introdotte dall&#8217;utente riorganizzandole nell&#8217;ambito una struttura ricorsiva        composta da array associativi: ad ogni livello dell&#8217;albero verrà        associato un array ottenendo, nel caso descritto sopra, tre array:</p>
<p>il primo array conterrà tre informazioni:        <span class="charsStrong">nominativo</span> di tipo stringa, <span class="charsStrong">età</span> di tipo intero ed un array associativo relativo all&#8217;<span class="charsStrong">indirizzo</span>;        l&#8217;array dell&#8217;<span class="charsStrong">indirizzo</span> conterrà        a sua volta tre informazioni: <span class="charsStrong">via</span> di tipo        stringa, <span class="charsStrong">civico</span> di tipo intero e <span class="charsStrong">città</span> anch&#8217;esso di tipo stringa.</p>
<p>Per prima cosa va fissata una rappresentazione          delle informazioni nell&#8217;ambito del form HTML che dia modi di stabilire il tipo e la gerarchia dei dati introdotti dall&#8217;utente, ciò perché possano          essere correttamente processati dalla pagina PHP. Un modo per effettuare          questa rappresentazione è quello di strutturare i nomi delle etichette          di input in modo che contengano sia il nome del parametro di input che          il tipo dello stesso separati da un carattere speciale, ad esempio:</p>
<p align="center"><strong>string%nominativo</strong></p>
<p>inoltre, per rendere possibile la gerarchia        delle informazioni, verranno introdotti nei nomi delle etichette &lt;input&gt;        una coppia di parentesi quadre per ogni livello di annidamento dell&#8217;informazione        associando al livello il particolare tipo <em>array</em>. Nel caso delle        informazioni anagrafiche descritte nella pagina precedente avremo infatti:</p>
<p>dati_personali[string%nominativo]<br />
dati_personali[int%eta]<br />
dati_personali[array%indirizzo][string%via]<br />
dati_personali[array%indirizzo][int%civico]<br />
dati_personali[array%indirizzo][string%citta]</p>
<p>Dalle informazioni riportate sopra possiamo        dedurre che:</p>
<ul>
<li>i tipi <em>string</em>, <em>int</em> ed <em>array</em> non devono necessariamente corrispondere ai tipi del PHP; essi rappresentano        semplicemente un protocollo per la trasmissione di informazioni sul tipo        dei dati e servono per un controllo dell&#8217;integrità da parte della        pagina PHP;</li>
<li>ai dati che rappresentano dei &#8220;contenitori&#8221;        di informazioni veine associato il tipo <em>array</em>;</li>
<li>le parentesi quadre aiutano a definire i        differenti livelli di annidamento.</li>
</ul>
<p>Ecco quindi come compare il testo della        form HTML:</p>
<p><span id="more-4"></span></p>
<pre><span class="chars">&lt;form action="wsquery.php"&gt;
&lt;p&gt;&lt;font size="+2"&gt;&lt;b&gt;Lettura dei parametri:&lt;/b&gt;&lt;/font&gt;&lt;/p&gt;
</span><span class="chars">&lt;table cellpadding="2" cellspacing="2"          border="1" width="100%"&gt;
&lt;tr&gt;&lt;td&gt;Nominativo
&lt;input type="text" name="dati_personali[string%nominativo]"&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Età
&lt;input type="text</span><span class="chars">" </span><span class="chars">name="dati_personali[int%eta]"&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Indirizzo / via
&lt;input type="text</span><span class="chars">" </span><span class="chars">name="dati_personali[array%indirizzo][string%via]"&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Indirizzo / civico
&lt;input type="text</span><span class="chars">" </span><span class="chars">name="dati_personali[array%indirizzo][int%civico]"&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Indirizzo / città
&lt;input type="text</span><span class="chars">" </span><span class="chars">name="dati_personali[array%indirizzo][string%citta]"&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;
&lt;input type="submit</span><span class="chars">" </span><span class="chars">name="button" value="Submit"&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;/form&gt; </span></pre>
<p><!--more-->Nel form HTML appena descritto compare il nome        della pagina dinamica &#8220;wsquery.php&#8221; che è proprio la pagina        PHP che si occuperà del processamento dei dati.</p>
<p>La pagina &#8220;wsquery.php&#8221; sarà        infatti caratterizzata dalla funzione principale <em>array_map_deep</em> riportata di seguito:</p>
<pre><!--more--><span class="chars">function array_map_deep($in_array)
{
</span><span class="chars">  </span><span class="chars">$out_array = array();
</span><span class="chars">  </span><span class="chars">if ($in_array != array())
</span><span class="chars">  </span><span class="chars">{
</span><span class="chars">  </span><span class="chars">  </span><span class="chars">foreach ($in_array as $key =&gt; $value)
</span><span class="chars">  </span><span class="chars">  </span><span class="chars">{
</span><span class="chars">  </span><span class="chars">  </span><span class="chars">  </span><span class="chars">// se il valore dell'array e' a sua volta un array attua la ricorsione
</span><span class="chars">  </span><span class="chars">  </span><span class="chars">  </span><span class="chars">if (is_array($value))
</span><span class="chars">  </span><span class="chars">  </span><span class="chars">  </span><span class="chars">{
</span><span class="chars">  </span><span class="chars">  </span><span class="chars">  </span><span class="chars">  </span><span class="chars">// elabora l'array contenuto "ricorsivamente"
</span><span class="chars">  </span><span class="chars">  </span><span class="chars">  </span><span class="chars">  </span><span class="chars">$temp = array_map_deep($value);</span></pre>
<pre><span class="chars">  </span><span class="chars">  </span><span class="chars">  </span><span class="chars">  </span>// carica l'elaborazione nell'array di uscita
<span class="chars">  </span><span class="chars">  </span><span class="chars">  </span><span class="chars">  </span>$out_array[get_name($key)] = $temp;
<span class="chars">  </span><span class="chars">  </span><span class="chars">  </span>}
<span class="chars">  </span><span class="chars">  </span><span class="chars">  </span>else
<span class="chars">  </span><span class="chars">  </span><span class="chars">  </span>{
<span class="chars">  </span><span class="chars">  </span><span class="chars">  </span><span class="chars">  </span>// ricava il tipo dell'elemento nell'array in ingresso, fa il
<span class="chars">  </span><span class="chars">  </span><span class="chars">  </span><span class="chars">  </span>// cast del valore in esso contenuto e lo carica nell'array di uscita
<span class="chars">  </span><span class="chars">  </span><span class="chars">  </span><span class="chars">  </span>$out_array[get_name($key)] = set_the_type($value, get_schema_type($key));
<span class="chars">  </span><span class="chars">  </span><span class="chars">  </span>}
<span class="chars">  </span><span class="chars">  </span>}
<span class="chars">  </span>}
<span class="chars">  </span>return $out_array;
}</pre>
<p><!--more-->La funzione appena descritta è una funzione        ricorsiva che, a partire da una array associativo contenente una lista di        valori caratterizzati da nomi definiti come descritto sopra, restituisce        un secondo array caratterizzato da una struttura ricorsiva dove ad ogni        livello di profondità corrisponde un nuovo array associativo. Nel        caso in esempio si avrà un array denominato <span class="charsStrong">dati_personali</span> contenente una stringa (<span class="charsStrong">nominativo</span>), un        intero (<span class="charsStrong">eta</span>) ed un array (<span class="charsStrong">indirizzo</span>);        quest&#8217;ultimo array conterrà due stinghe (<span class="charsStrong">via</span> e <span class="charsStrong">citta</span>) ed un intero (<span class="charsStrong">civico</span>).</p>
<p>E&#8217; facile immaginare che l&#8217;array in input a        questa funzione sarà proprio</p>
<p align="center"><strong>$_REQUEST["dati_personali"]</strong></p>
<p><span class="chars">In questo modo la funzione <em>array_map_deep</em> si occuperà di esaminare tutti i parametri provenienti dall’interfaccia        utente riferiti alla struttura dati_personali, esplorando ricorsivamente        il contenuto dei parametri con struttura complessa (che nel linguaggio PHP        sono univocamente rappresentati mediante array associativi).</span></p>
<p>Quando la funzione <em>array_map_deep</em> individua un tipo semplice, essa ne ricava il tipo mediante la funzione        <em>get_schema_type</em>, e il nome mediante la funzione <em>get_name</em> semplicemente scomponendo la stringa contenuta nel nome del componente HTML        &lt;input&gt; nella sottostringa che precede e che segue il carattere &#8220;%&#8221;:</p>
<pre><!--more-->function get_name($str)
{
<span class="chars">  </span>$i = strpos ($str, "%");
<span class="chars">  </span>return substr (substr ($str, $i ++), 1);
}</pre>
<pre>function get_schema_type($str)
{
<span class="chars">  </span>$i = strpos ($str, "%");
<span class="chars">  </span>return substr ($str, 0, $i);
}</pre>
<p><!--more-->Successivamente effettua la sua conversione        nel tipo PHP corrispondente attraverso la funzione <em>set_the_type</em>.        La funzione <em>set_the_type</em> individua una corrispondenza tra i tipi        definiti come <em>array</em>, <em>string,int</em> e <em>boolean</em> e i        tipi PHP veri e propri ed effettua la conversione del valore contenuto nel        parametro.</p>
<pre><!--more-->function set_the_type($var, $schema_type)
{
<span class="chars">  </span>switch ($schema_type)
<span class="chars">  </span>{
<span class="chars">  </span><span class="chars">  </span>case "int":
<span class="chars">  </span><span class="chars">  </span>return (integer)$var;
<span class="chars">  </span><span class="chars">  </span>break;
<span class="chars">  </span><span class="chars">  </span>case "boolean":
<span class="chars">  </span><span class="chars">  </span>return (boolean)$var;
<span class="chars">  </span><span class="chars">  </span>break;
<span class="chars">  </span><span class="chars">  </span>case "string":
<span class="chars">  </span><span class="chars">  </span>return (string)$var;
<span class="chars">  </span><span class="chars">  </span>break;
<span class="chars">  </span><span class="chars">  </span>default:
<span class="chars">  </span><span class="chars">  </span>return (string)$var;
<span class="chars">  </span><span class="chars">  </span>break;
<span class="chars">  </span>}
}</pre>
<p><!--more--> Infine, per testare l&#8217;accesso alla struttura        gerarchizzata possiamo usare il seguente codice che incolonna, nell&#8217;ambito        di un file di testo, le informazioni trasferite dal form HTML alla pagina        PHP:</p>
<pre><!--more-->$dati_personali = array_map_deep($_REQUEST["dati_personali"]);</pre>
<pre>echo $dati_personali['nominativo']." ";
echo $dati_personali['eta']." ";
echo $dati_personali['indirizzo']['via']." ";
echo $dati_personali['indirizzo']['civico']." ";
echo $dati_personali['indirizzo']['citta']." ";</pre>
<p><!--more--> L&#8217;array <span class="charsStrong">$dati_personali</span> mantiene la gerarchia delle informazioni così come l&#8217;avevamo definita        nel form chiamante. Notiamo infine che qualsiasi modifica alla gerarchia        dei dati viene automaticamente assimilata dalla pagina dinamica PHP.</p>
<p>Infine, il codice PHP contenuto in questo articolo        può essere combinato con il codice dell&#8217;articolo &#8220;PHP &#8211; Ispezione        delle strutture complesse (array e oggetti)&#8221; in modo da automatizzare        l&#8217;accesso ai dati provenienti dal form HTML senza conoscerne la struttura.</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/gianfrasoft.wordpress.com/4/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/gianfrasoft.wordpress.com/4/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/gianfrasoft.wordpress.com/4/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/gianfrasoft.wordpress.com/4/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/gianfrasoft.wordpress.com/4/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/gianfrasoft.wordpress.com/4/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/gianfrasoft.wordpress.com/4/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/gianfrasoft.wordpress.com/4/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/gianfrasoft.wordpress.com/4/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/gianfrasoft.wordpress.com/4/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/gianfrasoft.wordpress.com/4/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/gianfrasoft.wordpress.com/4/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/gianfrasoft.wordpress.com/4/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/gianfrasoft.wordpress.com/4/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/gianfrasoft.wordpress.com/4/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/gianfrasoft.wordpress.com/4/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gianfrasoft.wordpress.com&amp;blog=2822728&amp;post=4&amp;subd=gianfrasoft&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://gianfrasoft.wordpress.com/2008/02/09/php-passaggio-di-parametri-organizzati-gerarchicamente/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/905a08842a0c78883ed66254de5fc75a?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">gianfrasoft</media:title>
		</media:content>
	</item>
	</channel>
</rss>
