<?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/"
	>

<channel>
	<title>El Blog de Albert Mata &#187; MySQL</title>
	<atom:link href="http://www.albertmata.net/category/mysql/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.albertmata.net</link>
	<description>// anotaciones de análisis y programación en mi día a día como consultor de software</description>
	<lastBuildDate>Mon, 03 Aug 2009 19:22:21 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Miniacertijo en MySQL.</title>
		<link>http://www.albertmata.net/2009/06/miniacertijo-en-mysql/#utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=miniacertijo-en-mysql</link>
		<comments>http://www.albertmata.net/2009/06/miniacertijo-en-mysql/#comments</comments>
		<pubDate>Tue, 23 Jun 2009 16:07:20 +0000</pubDate>
		<dc:creator>Albert Mata</dc:creator>
				<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://www.albertmata.net/?p=256</guid>
		<description><![CDATA[Esta mañana he estado un rato alucinando con unos resultados que me estaba dando el servidor de MySQL ante unas instrucciones de lo más simples cuyos resultados esperados eran a priori evidentes. Es probable que estuviera bajo los influjos de demasiado café, quién sabe, pero el caso es que durante unos buenos minutos no podía [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-full wp-image-257" title="mysql_question" src="http://www.albertmata.net/public/uploads/2009/06/mysql_question.png" alt="" width="279" height="160" />Esta mañana he estado un rato alucinando con unos resultados que me estaba dando el servidor de MySQL ante unas instrucciones de lo más simples cuyos resultados esperados eran a priori evidentes. Es probable que estuviera bajo los influjos de demasiado café, quién sabe, pero el caso es que durante unos buenos minutos no podía dar crédito a lo que estaba viendo. He aquí la secuencia de consultas llevadas a cabo:<br />
<br/><br/><br/><br/></p>
<pre class="code">mysql&gt; select count(*) from t;
+----------+
| count(*) |
+----------+
|       73 |
+----------+
1 row in set (0.00 sec)

mysql&gt; update t set f = null;
Query OK, 73 rows affected (0.00 sec)
Rows matched: 73  Changed: 73  Warnings: 0

mysql&gt; select count(*) from t where not isnull(f);
+----------+
| count(*) |
+----------+
|        4 |
+----------+
1 row in set (0.00 sec)</pre>
<p>Ahí al final, por supuesto, esperaba recibir un 0. Pero no...</p>
<p>He llegado a pensar que MySQL se había vuelto loco, que el servidor había cascado... qué se yo, tonterías. Al final he descubierto qué estaba pasando. ¿Alguien se anima a especular? De hecho con el nivelillo de algunos de los que a veces comentáis, estoy seguro que mientras leíais este post ya se os ha ocurrido qué estaba pasando, así que más que la solución, os propongo que comentéis cuánto rato os ha llevado dar con ella.</p>
<div class="title">Resolución.</div>
<p>Pues el ganador por aproximación ha sido <a href="http://cambrico.net" target="_blank">Pedro Cambra</a> que ha comentado <em>"que la tabla tenga algún tipo de clave foránea, un trigger o mucha actividad y según hayas hecho el update se hayan modificado datos"</em>. Efectivamente, en su día creé dos triggers sobre la tabla en cuestión, uno sobre inserciones (irrelevante en este caso) y otro para actualizaciones. Los dos hacían lo mismo: si al insertar o modificar un registro el campo g tenía un valor concreto 'x', el campo f tomaría otro valor concreto 'y' independientemente del que el usuario hubiera introducido. Esto estaba haciendo ahora que para 4 registros concretos (los que cumplián la condición para el campo g) el trigger impidiera que f tomara valor NULL para pasar a tomar el valor que en el trigger estaba previsto que tomara. Pero claro, había olvidado que esta tabla tenía estos triggers y de ahí vinieron esos minutos de incredulidad...</p>
]]></content:encoded>
			<wfw:commentRss>http://www.albertmata.net/2009/06/miniacertijo-en-mysql/feed/</wfw:commentRss>
		<slash:comments>22</slash:comments>
		</item>
		<item>
		<title>Report in .NET using Crystal Reports and MySQL database.</title>
		<link>http://www.albertmata.net/2008/12/report-in-net-using-crystal-reports-and-mysql-database/#utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=report-in-net-using-crystal-reports-and-mysql-database</link>
		<comments>http://www.albertmata.net/2008/12/report-in-net-using-crystal-reports-and-mysql-database/#comments</comments>
		<pubDate>Tue, 09 Dec 2008 06:00:08 +0000</pubDate>
		<dc:creator>Albert Mata</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Crystal Reports]]></category>
		<category><![CDATA[English]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[bases de datos]]></category>
		<category><![CDATA[connection string]]></category>
		<category><![CDATA[dataset]]></category>
		<category><![CDATA[datatable]]></category>
		<category><![CDATA[informe]]></category>
		<category><![CDATA[odbc]]></category>
		<category><![CDATA[report]]></category>
		<category><![CDATA[xml]]></category>

		<guid isPermaLink="false">http://www.albertmata.net/?p=148</guid>
		<description><![CDATA[This is just the first of some English posts that I'll publish by translating most popular posts in this blog. Original version (in Spanish) is here.
First of all, I must asume that creating reports is one of that things I like worst in programming. But it's quite obvious that few serious applications don't need them, [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-full wp-image-74" title="xmlreport" src="http://www.albertmata.net/public/uploads/2008/07/xmlreport.jpg" alt="" width="230" height="227" />This is just the first of some English posts that I'll publish by translating most popular posts in this blog. Original version (in Spanish) is <a href="http://www.albertmata.net/2008/07/informe-en-net-con-crystal-reports-y-base-de-datos-mysql/" target="_blank">here</a>.</p>
<p>First of all, I must asume that creating reports is one of that things I like worst in programming. But it's quite obvious that few serious applications don't need them, and the one I'm developing now isn't an exception to this rule. So I've been creating some reports recently and I've discovered a new way to do it. And that's what I explain in this post.</p>
<p>As I've said sometimes before in previous posts, I develop with VisualBasic.NET and MySQL database. And I use Crystal Reports to create reports, as this tool is integrated in VisualStudio.NET. Since now, I used to use an ODBC connection configured in each PC to connect to MySQL server. But I didn't like this system much, because actually I'm not working just with one database but with some with different names. They have the same structure, tables and data, but just one is the good one, as the rest are just for developing purposes. It's really easy to use one or other connection string to make the application connect with one or other database, but with reports it isn't so easy as they take data using that ODBC connection (and it just can connect with one database).</p>
<p>But now I've discovered how to create reports with just a DataTable and an XML schema, needing nothing else. Actually it's possible to use a DataSet instead of a DataTable as well. So I'm going to explain it with an easy example and some images.</p>
<p>I'll work with two tables in my MySQL database where I'll keep information about bills. First table is the one with information about headers and has this data:</p>
<div class="code">&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;blh&#95;num&#160;&#124;&#160;blh&#95;dat&#160;&#160;&#160;&#160;&#124;&#160;blh&#95;cus&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1&#160;&#124;&#160;2008&#45;07&#45;30&#160;&#124;&#160;CERAMICAS&#160;PEPE&#44;&#160;S&#46;A&#46;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;2&#160;&#124;&#160;2008&#45;07&#45;30&#160;&#124;&#160;TALLERES&#160;GOMEZ&#44;&#160;S&#46;L&#46;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;3&#160;&#124;&#160;2008&#45;07&#45;31&#160;&#124;&#160;DEPORTES&#160;DAMIAN&#44;&#160;S&#46;L&#46;&#160;&#160;&#160;&#124;<br />
&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;4&#160;&#124;&#160;2008&#45;07&#45;31&#160;&#124;&#160;SOFTWARE&#160;ALBERTMATA&#46;NET&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;</div>
<p>Second table is the one with information about positions and has this rows:</p>
<div class="code">&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;blp&#95;num&#160;&#124;&#160;blp&#95;pos&#160;&#124;&#160;blp&#95;art&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;blp&#95;pri&#160;&#124;&#160;blp&#95;qty&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1&#160;&#124;&#160;RATON&#160;LOGITECH&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;15&#46;95&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1&#160;&#124;<br />
&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;2&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1&#160;&#124;&#160;MONITOR&#160;LG&#160;19&#160;PULGADAS&#160;&#124;&#160;&#160;&#160;210&#46;5&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1&#160;&#124;<br />
&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;3&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1&#160;&#124;&#160;ROUTER&#160;DLINK&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;56&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1&#160;&#124;<br />
&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;4&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1&#160;&#124;&#160;RATON&#160;LOGITECH&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;15&#46;95&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;2&#160;&#124;<br />
&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;4&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;2&#160;&#124;&#160;TECLADO&#160;LOGITECH&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;12&#46;95&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1&#160;&#124;<br />
&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;4&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;3&#160;&#124;&#160;RECEPTOR&#160;GPS&#160;ZAPPA&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;59&#46;95&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1&#160;&#124;<br />
&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;4&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;4&#160;&#124;&#160;PAQUETE&#160;500&#160;FOLIOS&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;3&#46;7&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;4&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;</div>
<p>It's something really simple and not <a href="http://en.wikipedia.org/wiki/Database_normalization" target="_blank">normalized</a>, but will be enough for this example, as we're going to create a report that will be the inovice for purchase number 4 (the one with customer SOFTWARE ALBERTMATA.NET). Obviously, we'll need information about both tables but I just want to work with one DataTable, so first of all I'm going to create a MySQL view with this sentence:</p>
<div class="code">CREATE&#160;VIEW&#160;zbl&#95;bill2print&#160;AS&#160;<br />
&#40;<br />
SELECT<br />
&#160;&#160;&#160;&#160;blh&#95;num&#160;AS&#160;BILL&#95;NUMBER&#44;<br />
&#160;&#160;&#160;&#160;blh&#95;dat&#160;AS&#160;BILL&#95;DATE&#44;<br />
&#160;&#160;&#160;&#160;blh&#95;cus&#160;AS&#160;BILL&#95;CUSTOMER&#44;<br />
&#160;&#160;&#160;&#160;blp&#95;pos&#160;AS&#160;LINE&#95;NUMBER&#44;<br />
&#160;&#160;&#160;&#160;blp&#95;art&#160;AS&#160;LINE&#95;ARTICLE&#44;<br />
&#160;&#160;&#160;&#160;blp&#95;pri&#160;AS&#160;LINE&#95;UNITPRICE&#44;<br />
&#160;&#160;&#160;&#160;blp&#95;qty&#160;AS&#160;LINE&#95;UNITS&#44;<br />
&#160;&#160;&#160;&#160;blp&#95;pri&#160;&#42;&#160;blp&#95;qty&#160;AS&#160;LINE&#95;TOTALPRICE<br />
FROM<br />
&#160;&#160;&#160;&#160;blh&#95;billheader&#160;LEFT&#160;JOIN&#160;blp&#95;billposits&#160;ON&#160;blh&#95;num&#160;&#61;&#160;blp&#95;num<br />
WHERE<br />
&#160;&#160;&#160;&#160;blh&#95;num&#160;&#61;&#160;4<br />
&#41;&#59;</div>
<p>So, from now on the report will be created using this zbl_bill2print view. Let's go with the .NET part.</p>
<div class="subtitle">Step 1. Creating XML file containing table/view structure.</div>
<p>Along this post we'll work with these three things:</p>
<p>1) a Windows form (frmMain) where we'll have the report viewer object.<br />
2) a class (clsReportCreator) we're going to create right now.<br />
3) a report (rptBill) that will be the invoice we want to print.</p>
<p>So let's start creating clsReportCreator class. It'll have only one attribute (the name of the table or view), one constructor method, one method to load DataTable object and one last method to generate the XML file. Here is the full code for this class:</p>
<div class="code">&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#39;&#160;Author&#58;&#160;&#160;&#160;&#160;&#160;&#160;Albert&#160;Mata&#160;&#40;www&#46;albertmata&#46;net&#41;<br />
&#39;&#160;Date&#58;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;20080731<br />
&#39;&#160;Needs&#58;&#160;&#160;&#160;&#160;&#160;&#160;&#160;MySQL&#46;Data&#160;reference&#46;<br />
&#39;&#160;Description&#58;&#160;Class&#160;to&#160;create&#160;a&#160;report&#160;using&#160;just&#160;an&#160;XML&#160;file&#46;&#160;<br />
&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
Imports&#160;MySql&#46;Data&#46;MySqlClient</p>
<p>Public&#160;Class&#160;clsReportCreator</p>
<p>&#160;&#160;&#160;&#160;&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#160;&#160;&#160;&#160;&#39;&#160;Attributes&#46;<br />
&#160;&#160;&#160;&#160;&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#160;&#160;&#160;&#160;Private&#160;TableOrView&#160;As&#160;String</p>
<p>&#160;&#160;&#160;&#160;&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#160;&#160;&#160;&#160;&#39;&#160;Constructor&#160;method&#46;<br />
&#160;&#160;&#160;&#160;&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#160;&#160;&#160;&#160;Public&#160;Sub&#160;New&#40;ByVal&#160;TableOrView&#160;As&#160;String&#41;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Me&#46;TableOrView&#160;&#61;&#160;TableOrView<br />
&#160;&#160;&#160;&#160;End&#160;Sub</p>
<p>&#160;&#160;&#160;&#160;&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#160;&#160;&#160;&#160;&#39;&#160;Returns&#160;DataTable&#160;corresponding&#160;to&#160;TableOrView&#46;<br />
&#160;&#160;&#160;&#160;&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#160;&#160;&#160;&#160;Public&#160;Function&#160;GetDataTable&#40;&#41;&#160;As&#160;DataTable<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Dim&#160;DA&#160;As&#160;MySqlDataAdapter<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Dim&#160;DS&#160;As&#160;New&#160;DataSet<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Dim&#160;DT&#160;As&#160;DataTable<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Dim&#160;ConnectionString&#160;As&#160;String<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Dim&#160;SQL&#160;As&#160;String</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Setting&#160;connection&#160;string&#160;to&#160;connect&#160;to&#160;MySQL&#160;database&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;ConnectionString&#160;&#61;&#160;&#34;Database&#160;&#61;&#160;blog&#59;&#160;&#34;&#160;&#95;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#38;&#160;&#34;Data&#160;Source&#160;&#61;&#160;localhost&#59;&#160;&#34;&#160;&#95;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#38;&#160;&#34;User&#160;ID&#160;&#61;&#160;root&#59;&#160;&#34;&#160;&#95;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#38;&#160;&#34;Password&#160;&#61;&#160;mypassword&#34;</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Setting&#160;SQL&#160;string&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;SQL&#160;&#61;&#160;&#34;SELECT&#160;&#42;&#160;FROM&#160;&#34;&#160;&#38;&#160;Me&#46;TableOrView</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Getting&#160;data&#160;and&#160;filling&#160;DataSet&#160;and&#160;DataTable&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;DA&#160;&#61;&#160;New&#160;MySqlDataAdapter&#40;SQL&#44;&#160;ConnectionString&#41;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;DA&#46;Fill&#40;DS&#44;&#160;Me&#46;TableOrView&#41;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;DT&#160;&#61;&#160;DS&#46;Tables&#40;Me&#46;TableOrView&#41;</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Returning&#160;DataTable&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Return&#160;DT<br />
&#160;&#160;&#160;&#160;End&#160;Function</p>
<p>&#160;&#160;&#160;&#160;&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#160;&#160;&#160;&#160;&#39;&#160;Creates&#160;XML&#160;file&#160;in&#160;desired&#160;path&#46;<br />
&#160;&#160;&#160;&#160;&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#160;&#160;&#160;&#160;Public&#160;Sub&#160;CreateXMLFile&#40;ByVal&#160;FilePath&#160;As&#160;String&#41;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Dim&#160;DT&#160;As&#160;DataTable</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Creating&#160;DataTable&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;DT&#160;&#61;&#160;Me&#46;GetDataTable&#40;&#41;</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Writting&#160;XML&#160;file&#160;in&#160;desired&#160;path&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;DT&#46;WriteXmlSchema&#40;FilePath&#160;&#38;&#160;Me&#46;TableOrView&#160;&#38;&#160;&#34;&#46;xml&#34;&#41;<br />
&#160;&#160;&#160;&#160;End&#160;Sub</p>
<p>End&#160;Class</p></div>
<p>And we also create frmMain form, which only code by the moment will be this:</p>
<div class="code">&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#39;&#160;Author&#58;&#160;&#160;&#160;&#160;&#160;&#160;Albert&#160;Mata&#160;&#40;www&#46;albertmata&#46;net&#41;<br />
&#39;&#160;Date&#58;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;20080731<br />
&#39;&#160;Description&#58;&#160;Form&#160;to&#160;show&#160;how&#160;to&#160;create&#160;a&#160;report&#160;using&#160;just&#160;an&#160;XML<br />
&#39;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;file&#46;&#160;<br />
&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
Public&#160;Class&#160;frmMain</p>
<p>&#160;&#160;&#160;&#160;&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#160;&#160;&#160;&#160;&#39;&#160;As&#160;a&#160;first&#160;step&#44;&#160;creates&#160;XML&#160;file&#46;<br />
&#160;&#160;&#160;&#160;&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#160;&#160;&#160;&#160;Private&#160;Sub&#160;frmMain&#95;Load&#40;ByVal&#160;sender&#160;As&#160;System&#46;Object&#44;&#160;&#95;<br />
&#160;&#160;&#160;&#160;ByVal&#160;e&#160;As&#160;System&#46;EventArgs&#41;&#160;Handles&#160;MyBase&#46;Load<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Creating&#160;XML&#160;file&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Dim&#160;RC&#160;As&#160;New&#160;clsReportCreator&#40;&#34;zbl&#95;bill2print&#34;&#41;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;RC&#46;CreateXMLFile&#40;&#34;C&#58;&#92;&#34;&#41;<br />
&#160;&#160;&#160;&#160;End&#160;Sub</p>
<p>End&#160;Class</p></div>
<p>Right now we have a first application. If we execute it we'll get C:\zbl_bill2print.xml file with the structure of zbl_bill2print view. So we run it and get <a href="http://www.albertmata.net/files/zbl_bill2print.xml" target="_blank">that file</a>.</p>
<div class="subtitle">Step 2. Creating report and loading data source.</div>
<p>First, we add a report to our project and give it a name like rptBill.rpt. We create it choosing empty report option, so desestimating any templates.</p>
<p>Now we go to Fields explorer menu and right-click the first option (Database fields). In new contextual menu we click on Database assistant option.</p>
<p style="text-align: center;"><img class="alignnone size-full wp-image-75" title="blog_020_1" src="http://www.albertmata.net/public/uploads/2008/07/blog_020_1.jpg" alt="" width="224" height="147" /></p>
<p>After this we get the Available data source menu, where we choose Create new connection and after that ADO.NET option.</p>
<p style="text-align: center;"><img class="alignnone size-full wp-image-76" title="blog_020_2" src="http://www.albertmata.net/public/uploads/2008/07/blog_020_2.jpg" alt="" width="232" height="305" /></p>
<p>Making this, we'll see a new form where we'll be asked about File's path. In this point we have to find XML file we've created before (in my example C:\zbl_bill2print.xml) and then press Finish. We have NewDataSet option including our just added zbl_bill2print in Available data source menu now. </p>
<p style="text-align: center;"><img class="alignnone size-full wp-image-77" title="blog_020_3" src="http://www.albertmata.net/public/uploads/2008/07/blog_020_3.jpg" alt="" width="232" height="305" /></p>
<p>So we select it and press button to move it to Selected tables menu. Done this, it's time to click on Accept.</p>
<p style="text-align: center;"><img class="alignnone size-full wp-image-78" title="blog_020_4" src="http://www.albertmata.net/public/uploads/2008/07/blog_020_4.jpg" alt="" width="231" height="305" /></p>
<p>With all this stuff we've gotten that zbl_bill2print structure available in Fields explorer menu with all its fields, as shown in image below:</p>
<p style="text-align: center;"><img class="alignnone size-full wp-image-79" title="blog_020_5" src="http://www.albertmata.net/public/uploads/2008/07/blog_020_5.jpg" alt="" width="224" height="311" /></p>
<div class="subtitle">Step 3. Designing report.</div>
<p>Nothing special to say here. Just adding fields from Fields explorer menu, inserting text objects where needed, sums, text formats, images and so on...</p>
<p>I've just created a very simple design like this:</p>
<p style="text-align: center;"><img class="alignnone size-full wp-image-80" title="blog_020_6" src="http://www.albertmata.net/public/uploads/2008/07/blog_020_6.jpg" alt="" width="399" height="313" /></p>
<div class="subtitle">Step 4. Last actions to get the invoice.</div>
<p>Finally we're going to create the bill. To do that, we add a CrystalReportViewer object in frmMain form. I call it crvBill. After that it's necessary to modify frmMain source code to make it look like this:</p>
<div class="code">&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#39;&#160;Author&#58;&#160;&#160;&#160;&#160;&#160;&#160;Albert&#160;Mata&#160;&#40;www&#46;albertmata&#46;net&#41;<br />
&#39;&#160;Date&#58;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;20080731<br />
&#39;&#160;Description&#58;&#160;Form&#160;to&#160;show&#160;how&#160;to&#160;create&#160;a&#160;report&#160;using&#160;just&#160;an&#160;XML<br />
&#39;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;file&#46;&#160;<br />
&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
Imports&#160;CrystalDecisions&#46;CrystalReports&#46;Engine</p>
<p>Public&#160;Class&#160;frmMain</p>
<p>&#160;&#160;&#160;&#160;&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#160;&#160;&#160;&#160;&#39;&#160;Creates&#160;XML&#160;file&#160;&#40;just&#160;once&#41;&#160;and&#160;creates&#160;and&#160;loads&#160;a&#160;report&#46;<br />
&#160;&#160;&#160;&#160;&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#160;&#160;&#160;&#160;Private&#160;Sub&#160;frmMain&#95;Load&#40;ByVal&#160;sender&#160;As&#160;System&#46;Object&#44;&#160;&#95;<br />
&#160;&#160;&#160;&#160;ByVal&#160;e&#160;As&#160;System&#46;EventArgs&#41;&#160;Handles&#160;MyBase&#46;Load<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Creating&#160;XML&#160;file&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Dim&#160;RC&#160;As&#160;New&#160;clsReportCreator&#40;&#34;zbl&#95;bill2print&#34;&#41;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;RC&#46;CreateXMLFile&#40;&#34;C&#58;&#92;&#34;&#41;</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Creating&#160;report&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Dim&#160;RD&#160;As&#160;ReportDocument&#160;&#61;&#160;New&#160;rptBill&#40;&#41;</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Setting&#160;data&#160;source&#160;for&#160;report&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Dim&#160;DT&#160;As&#160;DataTable&#160;&#61;&#160;RC&#46;GetDataTable&#40;&#41;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;RD&#46;SetDataSource&#40;DT&#41;</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Setting&#160;data&#160;source&#160;for&#160;possible&#160;subreports&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;For&#160;Each&#160;SR&#160;As&#160;ReportDocument&#160;In&#160;RD&#46;Subreports<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;If&#160;SR&#46;Database&#46;Tables&#46;Count&#160;&#62;&#160;0&#160;Then<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;SR&#46;SetDataSource&#40;DT&#41;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;End&#160;If<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Next</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Setting&#160;recently&#160;created&#160;report&#160;must&#160;be&#160;shown&#160;in&#160;viewer&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Me&#46;crvBill&#46;ReportSource&#160;&#61;&#160;RD<br />
&#160;&#160;&#160;&#160;End&#160;Sub</p>
<p>End&#160;Class</p></div>
<p>It's important to note that the line where the XML file is created is commented now, as we just need to create this file once to use it to create the source data, but from now on we don't need to generate it every time.</p>
<p>What we're mainly doing in this code is:</p>
<p>1) creating a report object same kind we've designed in step 3,<br />
2) getting a DataTable with data we want to show (in this example and according to the way we've defined MySQL view, we want to show invoice number 4),<br />
3) setting this DataTable as the report's source data,<br />
4) asking CrystalReportViewer to show this report.</p>
<p>We execute the application again and get desired invoice:</p>
<p style="text-align: center;"><img class="alignnone size-full wp-image-81" title="blog_020_7" src="http://www.albertmata.net/public/uploads/2008/07/blog_020_7.jpg" alt="" width="484" height="416" /></p>
<p>Of course there should be quite more information, images and legal texts in a real invoice, but this is just an easy example of how to do the report itself.</p>
<p>So we've seen how to create a report in VisualBasic.NET just using an XML file. Of course there are plenty of things to improve, as optimizing how database connection is done, or avoiding WHERE condition directly in MySQL view and so on... but what I was looking for with this example was just a very minimum guide to show the process.</p>
<p>PS. Some menu and option names can be different as I develope in VisualStudio Spanish version and I've just translated them as I've thought they could appear in English version. Sorry about that!</p>
<div class="subtitle">Update.</div>
<p> There is a second part for this post <a href="http://www.albertmata.net/2008/10/pasando-parametros-al-informe-en-net-con-crystal-reports/" target="_blank">explaining how to pass parameters from form to report</a>, but it's still only in Spanish.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.albertmata.net/2008/12/report-in-net-using-crystal-reports-and-mysql-database/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>MySQL no admite TRANSFORM PIVOT (pero se pueden obtener resultados parecidos).</title>
		<link>http://www.albertmata.net/2008/11/mysql-no-admite-transform-pivot-pero-se-pueden-obtener-resultados-parecidos/#utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=mysql-no-admite-transform-pivot-pero-se-pueden-obtener-resultados-parecidos</link>
		<comments>http://www.albertmata.net/2008/11/mysql-no-admite-transform-pivot-pero-se-pueden-obtener-resultados-parecidos/#comments</comments>
		<pubDate>Thu, 27 Nov 2008 12:48:09 +0000</pubDate>
		<dc:creator>Albert Mata</dc:creator>
				<category><![CDATA[Access]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[bases de datos]]></category>
		<category><![CDATA[referencias cruzadas]]></category>
		<category><![CDATA[transform pivot]]></category>

		<guid isPermaLink="false">http://www.albertmata.net/?p=145</guid>
		<description><![CDATA[Estos últimas días he estado mirando un tema que me preocupaba porque iba a necesitarlo en la aplicación que ando desarrollando... y tras no haber encontrado nada, finalmente me he tenido que poner a fondo con ello hasta sacarlo de una u otra manera. El tema consiste en hacer una consulta de referencias cruzadas en [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.albertmata.net/public/uploads/2008/11/transformpivot.jpg" alt="" title="transformpivot" width="162" height="229" class="alignleft size-full wp-image-146" />Estos últimas días he estado mirando un tema que me preocupaba porque iba a necesitarlo en la aplicación que ando desarrollando... y tras no haber encontrado nada, finalmente me he tenido que poner a fondo con ello hasta sacarlo de una u otra manera. El tema consiste en hacer una consulta de referencias cruzadas en MySQL y, como digo, tras bastante investigar he descubierto que en realidad MySQL no admite esta clase de consultas. Para explicar mejor lo que pretendía hacer voy a basarme en un ejemplo consistente en la siguiente tabla sfc_salefrcast:</p>
<div class="code">&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;sfc&#95;cus&#160;&#124;&#160;sfc&#95;mat&#160;&#124;&#160;sfc&#95;mth&#160;&#160;&#160;&#160;&#124;&#160;sfc&#95;qty&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;12345&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1&#160;&#124;&#160;2008&#45;11&#45;01&#160;&#124;&#160;&#160;&#160;&#160;1200&#160;&#124;<br />
&#124;&#160;12345&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;3&#160;&#124;&#160;2008&#45;11&#45;01&#160;&#124;&#160;&#160;&#160;&#160;1500&#160;&#124;<br />
&#124;&#160;54321&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;2&#160;&#124;&#160;2008&#45;11&#45;01&#160;&#124;&#160;&#160;&#160;&#160;2500&#160;&#124;<br />
&#124;&#160;54321&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;3&#160;&#124;&#160;2008&#45;12&#45;01&#160;&#124;&#160;&#160;&#160;&#160;3500&#160;&#124;<br />
&#124;&#160;54321&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;3&#160;&#124;&#160;2009&#45;03&#45;01&#160;&#124;&#160;&#160;&#160;&#160;4500&#160;&#124;<br />
&#124;&#160;54321&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;3&#160;&#124;&#160;2009&#45;07&#45;01&#160;&#124;&#160;&#160;&#160;&#160;4500&#160;&#124;<br />
&#124;&#160;99999&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;4&#160;&#124;&#160;2009&#45;02&#45;01&#160;&#124;&#160;&#160;&#160;&#160;2000&#160;&#124;<br />
&#124;&#160;99999&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;4&#160;&#124;&#160;2009&#45;04&#45;01&#160;&#124;&#160;&#160;&#160;&#160;4000&#160;&#124;<br />
&#124;&#160;99999&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;4&#160;&#124;&#160;2009&#45;06&#45;01&#160;&#124;&#160;&#160;&#160;&#160;6000&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;</div>
<p>Es una tabla de previsiones de ventas en donde sfc_cus es el código del cliente, sfc_mat el código del material, sfc_mth el mes representado por su primer día y sfc_qty la cantidad que prevemos que vamos a venderle de dicho material a dicho cliente dicho mes (y dichosos nosotros si acertamos).</p>
<p>Bien, pues a partir de esta tabla pretendía conseguir una tabla (o vista... un conjunto de registros, vamos) en la que en cada registro se me mostrara una combinación de cliente y material, y a partir de aquí una columna para cada mes con la cantidad correspondiente. Algo del estilo de lo siguiente...</p>
<div class="code">&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;sfc&#95;cus&#160;&#124;&#160;sfc&#95;mat&#160;&#124;&#160;M0&#160;&#160;&#160;&#124;&#160;M1&#160;&#160;&#160;&#124;&#160;M2&#160;&#160;&#160;&#124;&#160;M3&#160;&#160;&#160;&#124;&#160;M4&#160;&#160;&#160;&#124;&#160;M5&#160;&#160;&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;12345&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1&#160;&#124;&#160;1200&#160;&#124;&#160;&#160;&#160;&#160;0&#160;&#124;&#160;&#160;&#160;&#160;0&#160;&#124;&#160;&#160;&#160;&#160;0&#160;&#124;&#160;&#160;&#160;&#160;0&#160;&#124;&#160;&#160;&#160;&#160;0&#160;&#124;<br />
&#124;&#160;12345&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;3&#160;&#124;&#160;1500&#160;&#124;&#160;&#160;&#160;&#160;0&#160;&#124;&#160;&#160;&#160;&#160;0&#160;&#124;&#160;&#160;&#160;&#160;0&#160;&#124;&#160;&#160;&#160;&#160;0&#160;&#124;&#160;&#160;&#160;&#160;0&#160;&#124;<br />
&#124;&#160;54321&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;2&#160;&#124;&#160;2500&#160;&#124;&#160;&#160;&#160;&#160;0&#160;&#124;&#160;&#160;&#160;&#160;0&#160;&#124;&#160;&#160;&#160;&#160;0&#160;&#124;&#160;&#160;&#160;&#160;0&#160;&#124;&#160;&#160;&#160;&#160;0&#160;&#124;<br />
&#124;&#160;54321&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;3&#160;&#124;&#160;&#160;&#160;&#160;0&#160;&#124;&#160;3500&#160;&#124;&#160;&#160;&#160;&#160;0&#160;&#124;&#160;&#160;&#160;&#160;0&#160;&#124;&#160;4500&#160;&#124;&#160;&#160;&#160;&#160;0&#160;&#124;<br />
&#124;&#160;99999&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;4&#160;&#124;&#160;&#160;&#160;&#160;0&#160;&#124;&#160;&#160;&#160;&#160;0&#160;&#124;&#160;&#160;&#160;&#160;0&#160;&#124;&#160;2000&#160;&#124;&#160;&#160;&#160;&#160;0&#160;&#124;&#160;4000&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;</div>
<p>...en donde M0 es el mes actual (2008-11-01), M1 es el mes próximo, M2 el siguiente, etc.</p>
<p>Pues bien, si estuviéramos trabajando en Microsoft Access podríamos hacer algo simple como...</p>
<div class="code">TRANSFORM&#160;SUM&#40;sfc&#95;qty&#41;&#160;<br />
&#160;&#160;&#160;&#160;SELECT&#160;sfc&#95;cus&#44;&#160;sfc&#95;mat<br />
&#160;&#160;&#160;&#160;FROM&#160;sfc&#95;salefrcast<br />
&#160;&#160;&#160;&#160;GROUP&#160;BY&#160;sfc&#95;cus&#44;&#160;sfc&#95;mat<br />
PIVOT&#160;sfc&#95;mth&#59;</div>
<p>...y obtendríamos algo muy parecido al resultado deseado. Simplemente no nos mostraría las columnas donde no haya ningún valor que mostrar (como M2), pero sería un problema muy menor que solventaríamos sin dificultad. En Microsoft Excel también sería sencillísimo obtener esos resultados a través de una tabla dinámica.</p>
<p>No obstante, trabajo con MySQL. Y por desgracia MySQL no admite TRANSFORM-PIVOT. De hecho no he encontrado ninguna alternativa atractiva para resolver mi problema, de modo que he tenido que rascar un poquito y crear una a medida, que me ha quedado así:</p>
<div class="code">SELECT<br />
&#160;&#160;&#160;&#160;sfc&#95;cus&#44;<br />
&#160;&#160;&#160;&#160;sfc&#95;mat&#44;<br />
&#160;&#160;&#160;&#160;SUM&#40;IF&#40;MID&#40;sfc&#95;mth&#44;&#160;1&#44;&#160;7&#41;&#160;&#61;&#160;MID&#40;NOW&#40;&#41;&#44;&#160;1&#44;&#160;7&#41;&#44;&#160;sfc&#95;qty&#44;&#160;0&#41;&#41;&#160;AS&#160;M0&#44;<br />
&#160;&#160;&#160;&#160;SUM&#40;IF&#40;MID&#40;sfc&#95;mth&#44;&#160;1&#44;&#160;7&#41;&#160;&#61;&#160;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;MID&#40;DATE&#95;ADD&#40;NOW&#40;&#41;&#44;INTERVAL&#160;1&#160;MONTH&#41;&#44;&#160;1&#44;&#160;7&#41;&#44;&#160;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;sfc&#95;qty&#44;&#160;0&#41;&#41;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;AS&#160;M1&#44;<br />
&#160;&#160;&#160;&#160;SUM&#40;IF&#40;MID&#40;sfc&#95;mth&#44;&#160;1&#44;&#160;7&#41;&#160;&#61;&#160;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;MID&#40;DATE&#95;ADD&#40;NOW&#40;&#41;&#44;INTERVAL&#160;2&#160;MONTH&#41;&#44;&#160;1&#44;&#160;7&#41;&#44;&#160;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;sfc&#95;qty&#44;&#160;0&#41;&#41;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;AS&#160;M2&#44;<br />
&#160;&#160;&#160;&#160;SUM&#40;IF&#40;MID&#40;sfc&#95;mth&#44;&#160;1&#44;&#160;7&#41;&#160;&#61;&#160;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;MID&#40;DATE&#95;ADD&#40;NOW&#40;&#41;&#44;INTERVAL&#160;3&#160;MONTH&#41;&#44;&#160;1&#44;&#160;7&#41;&#44;&#160;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;sfc&#95;qty&#44;&#160;0&#41;&#41;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;AS&#160;M3&#44;<br />
&#160;&#160;&#160;&#160;SUM&#40;IF&#40;MID&#40;sfc&#95;mth&#44;&#160;1&#44;&#160;7&#41;&#160;&#61;&#160;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;MID&#40;DATE&#95;ADD&#40;NOW&#40;&#41;&#44;INTERVAL&#160;4&#160;MONTH&#41;&#44;&#160;1&#44;&#160;7&#41;&#44;&#160;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;sfc&#95;qty&#44;&#160;0&#41;&#41;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;AS&#160;M4&#44;<br />
&#160;&#160;&#160;&#160;SUM&#40;IF&#40;MID&#40;sfc&#95;mth&#44;&#160;1&#44;&#160;7&#41;&#160;&#61;&#160;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;MID&#40;DATE&#95;ADD&#40;NOW&#40;&#41;&#44;INTERVAL&#160;5&#160;MONTH&#41;&#44;&#160;1&#44;&#160;7&#41;&#44;&#160;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;sfc&#95;qty&#44;&#160;0&#41;&#41;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;AS&#160;M5<br />
FROM<br />
&#160;&#160;&#160;&#160;sfc&#95;salefrcast<br />
GROUP&#160;BY&#160;<br />
&#160;&#160;&#160;&#160;sfc&#95;cus&#44;&#160;sfc&#95;mat&#59;</div>
<p>(Ver actualización 1.)</p>
<p>Al no utilizar directamente fechas sino estar jugando con NOW() y la función DATE_ADD, obtenemos siempre resultados para el mes corriente y los siguientes N meses, independientemente de cuando solicitemos esa información a la base de datos.</p>
<p>Ignoro si hay alguna manera más directa de hacerlo (y si la hay y la conoces, estaré encantadísimo de leerla), pero por lo pronto lo he solucionado así... </p>
<div class="subtitle">Actualización.</div>
<p>1. Siguiendo el consejo -uno de ellos- de <a href="http://www.luismedel.com/" target="_blank">Luís Medel</a> en los comentarios, he cambiado la versión original que había publicado para dejar esta más simplificada al realizar en un solo paso el sumatorio y el filtrado. Además, Luís propone utilizar CASE WHEN THEN ELSE END en lugar de IF.</p>
<p>2. <a href="http://cambrico.net" target="_blank">Pedro Cambra</a> facilita en los comentarios un link a la página de <a href="http://rpbouman.blogspot.com/2005/10/creating-crosstabs-in-mysql.html" target="_blank">Roland Bouman</a> donde se expone un método para hacerlo de forma dinámica utilizando procedimientos almacenados.</p>
<p>3. <a href="http://cambrico.net" target="_blank">Pedro Cambra</a> comenta también que MySQL dispone de la función EXTRACT con el parámetro YEAR_MONTH que efectivamente se podría utilizar para mejorar el apartado del MID(fecha,1,7). Más información en <a href="http://dev.mysql.com/doc/refman/5.0/en/date-and-time-functions.html#function_extract" target="_blank">el manual de referencia de MySQL</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.albertmata.net/2008/11/mysql-no-admite-transform-pivot-pero-se-pueden-obtener-resultados-parecidos/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Correspondencia entre tipos de datos en MySQL, en VisualBasic.NET y en .NET Framework.</title>
		<link>http://www.albertmata.net/2008/11/correspondencia-entre-tipos-de-datos-en-mysql-en-visualbasicnet-y-en-net-framework/#utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=correspondencia-entre-tipos-de-datos-en-mysql-en-visualbasicnet-y-en-net-framework</link>
		<comments>http://www.albertmata.net/2008/11/correspondencia-entre-tipos-de-datos-en-mysql-en-visualbasicnet-y-en-net-framework/#comments</comments>
		<pubDate>Sun, 02 Nov 2008 05:35:45 +0000</pubDate>
		<dc:creator>Albert Mata</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[bigint]]></category>
		<category><![CDATA[byte]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[int]]></category>
		<category><![CDATA[integer]]></category>
		<category><![CDATA[long]]></category>
		<category><![CDATA[mediumint]]></category>
		<category><![CDATA[short]]></category>
		<category><![CDATA[smallint]]></category>
		<category><![CDATA[tinyint]]></category>
		<category><![CDATA[tipos datos]]></category>
		<category><![CDATA[visual basic]]></category>

		<guid isPermaLink="false">http://www.albertmata.net/?p=139</guid>
		<description><![CDATA[Estos últimos días he estado liado programando una clase que tira intensamente de reflexión (me refiero a System.Reflection, no a que haya estado reflexionando intensamente, que también) para relacionar un objeto de una clase determinada (la que sea) con una tabla en la base de datos. Así, utilizando esa clase auxiliar podemos decirle que cargue [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.albertmata.net/public/uploads/2008/10/mysql_visualstudio.jpg" alt="" title="mysql_visualstudio" width="165" height="131" class="alignleft size-full wp-image-140" />Estos últimos días he estado liado programando una clase que tira intensamente de reflexión (me refiero a System.Reflection, no a que haya estado reflexionando intensamente, que también) para relacionar un objeto de una clase determinada (la que sea) con una tabla en la base de datos. Así, utilizando esa clase auxiliar podemos decirle que cargue un objeto a partir de un registro de una tabla o que lo guarde en ella. Y sirve para cualquier clase que tenga una tabla relacionada en la base de datos. Quizá otro día cuelgo esa clase... Pero el caso es que mientras lo desarrollaba he tenido algunos problemillas por no encajarme exactamente los tipos de datos que me devolvía MySQL y los que esperaba .NET, así que tras haber estado buscando cuáles son las equivalencias exactas, paso a exponer la tabla de correspondencias entre tipos de datos tanto en MySQL como en VisualBasic.NET como en el .NET Framework.</p>
<div class="code">&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;MYSQL&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;VB&#46;NET&#160;&#160;&#124;&#160;&#46;NET&#160;Framework&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;TINYINT&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;SByte&#160;&#160;&#160;&#160;&#124;&#160;SByte&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;TINYINT&#160;UNSIGNED&#160;&#160;&#160;&#124;&#160;Byte&#160;&#160;&#160;&#160;&#160;&#124;&#160;Byte&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;SMALLINT&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;Short&#160;&#160;&#160;&#160;&#124;&#160;Int16&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;SMALLINT&#160;UNSIGNED&#160;&#160;&#124;&#160;UShort&#160;&#160;&#160;&#124;&#160;UInt16&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;MEDIUMINT&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;Integer&#160;&#160;&#124;&#160;Int32&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;MEDIUMINT&#160;UNSIGNED&#160;&#124;&#160;UInteger&#160;&#124;&#160;UInt32&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;INT&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;Integer&#160;&#160;&#124;&#160;Int32&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;INT&#160;UNSIGNED&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;UInteger&#160;&#124;&#160;UInt32&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;BIGINT&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;Long&#160;&#160;&#160;&#160;&#160;&#124;&#160;Int64&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;BIGINT&#160;UNSIGNED&#160;&#160;&#160;&#160;&#124;&#160;ULong&#160;&#160;&#160;&#160;&#124;&#160;UInt64&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;</div>
<p>Teniendo en cuenta estas relaciones, todo funciona a las mil maravillas... <img src='http://www.albertmata.net/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.albertmata.net/2008/11/correspondencia-entre-tipos-de-datos-en-mysql-en-visualbasicnet-y-en-net-framework/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Claves foráneas vs UNIQUE en MySQL.</title>
		<link>http://www.albertmata.net/2008/10/claves-foraneas-vs-unique-en-mysql/#utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=claves-foraneas-vs-unique-en-mysql</link>
		<comments>http://www.albertmata.net/2008/10/claves-foraneas-vs-unique-en-mysql/#comments</comments>
		<pubDate>Sun, 05 Oct 2008 04:24:28 +0000</pubDate>
		<dc:creator>Albert Mata</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[bases de datos]]></category>
		<category><![CDATA[claves foráneas]]></category>
		<category><![CDATA[claves primarias]]></category>
		<category><![CDATA[foreign key]]></category>
		<category><![CDATA[primary key]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[unique]]></category>

		<guid isPermaLink="false">http://www.albertmata.net/?p=112</guid>
		<description><![CDATA[Cuando diseñamos una tabla en MySQL (y en general en cualquier otro SGBD) solemos prestar mucha más importancia a las claves primarias que a las foráneas. Sin embargo las claves foráneas son también muy importantes principalmente por un doble motivo. Por un lado permiten mantener la integridad de la base de datos ante posibles modificaciones [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.albertmata.net/public/uploads/2008/10/mysql_unique.jpg" alt="" title="mysql_unique" width="210" height="210" class="alignleft size-full wp-image-113" />Cuando diseñamos una tabla en <a href="http://www.mysql.com" target="_blank">MySQL</a> (y en general en cualquier otro <a href="http://es.wikipedia.org/wiki/DBMS" target="_blank">SGBD</a>) solemos prestar mucha más importancia a las claves primarias que a las foráneas. Sin embargo las claves foráneas son también muy importantes principalmente por un doble motivo. Por un lado permiten mantener la integridad de la base de datos ante posibles modificaciones o eliminación de datos. Por otro lado aceleran enormemente determinadas combinaciones (<a href="http://es.wikipedia.org/wiki/Join" target="_blank">joins</a>) de tablas. No obstante, si estamos utilizando MySQL este segundo tema no depende estrictamente de las claves foráneas sino de la unicidad de las claves. Son temas parecidos pero no iguales, ya que para que una campo pueda ser referenciado por la clave foránea de otra tabla debe cumplir el criterio de unicidad, pero que lo cumpla no obliga a que alguna clave foránea tenga que referenciarlo. De esto es de lo que va a tratar este post.</p>
<p>Como el tema va a ser algo complicado de explicar sin unas tablas de datos a las que sujetarnos, voy a partir de tres tablas con las que desarrollaré toda la explicación. Estas tres tablas son las que paso a explicar a continuación.</p>
<div class="subtitle">Tabla de materiales vendidos.</div>
<div class="code">mysql&#62;&#160;DESCRIBE&#160;mat&#95;materialsx&#59;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;Field&#160;&#160;&#160;&#124;&#160;Type&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;Null&#160;&#124;&#160;Key&#160;&#124;&#160;Default&#160;&#124;&#160;Extra&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;mat&#95;ped&#160;&#124;&#160;varchar&#40;6&#41;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;NO&#160;&#160;&#160;&#124;&#160;PRI&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;mat&#95;pos&#160;&#124;&#160;smallint&#40;5&#41;&#160;unsigned&#160;&#124;&#160;NO&#160;&#160;&#160;&#124;&#160;PRI&#160;&#124;&#160;0&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;mat&#95;typ&#160;&#124;&#160;varchar&#40;6&#41;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;YES&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#124;&#160;NULL&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;mat&#95;fin&#160;&#124;&#160;varchar&#40;2&#41;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;YES&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#124;&#160;NULL&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;mat&#95;qty&#160;&#124;&#160;double&#160;unsigned&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;YES&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#124;&#160;NULL&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
5&#160;rows&#160;in&#160;set&#160;&#40;0&#46;01&#160;sec&#41;</div>
<p>Es una tabla que recoge todos los materiales que se han vendido en algún momento a lo largo de la trayectoria de una empresa. Los campos mat_ped y mat_pos son la clave primaria e identifican el número de pedido de venta y la posición dentro de dicho pedido. No afectarán en nada a nuestro desarrollo, así que podemos olvidarnos de ellos. En cambio los restantes campos serán importantes: mat_typ indica el tipo de material, mat_fin indica el acabado de ese material y mat_qty indica el número de kilos vendidos en ese pedido y posición.</p>
<p>Quedará más claro viendo algunos datos que puede contener esta tabla:</p>
<div class="code">mysql&#62;&#160;SELECT&#160;&#42;&#160;FROM&#160;mat&#95;materialsx&#160;LIMIT&#160;5&#59;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;mat&#95;ped&#160;&#124;&#160;mat&#95;pos&#160;&#124;&#160;mat&#95;typ&#160;&#124;&#160;mat&#95;fin&#160;&#124;&#160;mat&#95;qty&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;100023&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1&#160;&#124;&#160;430&#160;&#160;&#160;&#160;&#160;&#124;&#160;XP&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;800&#160;&#124;<br />
&#124;&#160;A09085&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1&#160;&#124;&#160;430&#160;&#160;&#160;&#160;&#160;&#124;&#160;BA&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;3000&#160;&#124;<br />
&#124;&#160;A09086&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1&#160;&#124;&#160;430&#160;&#160;&#160;&#160;&#160;&#124;&#160;BA&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;7380&#160;&#124;<br />
&#124;&#160;A09138&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1&#160;&#124;&#160;409&#160;&#160;&#160;&#160;&#160;&#124;&#160;2B&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;538&#160;&#124;<br />
&#124;&#160;A09139&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1&#160;&#124;&#160;409&#160;&#160;&#160;&#160;&#160;&#124;&#160;2B&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;539&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
5&#160;rows&#160;in&#160;set&#160;&#40;0&#46;00&#160;sec&#41;</div>
<p>Lo he limitado a 5 resultados pero en realidad en esta tabla es donde estará el enorme volumen de datos, ya que la tabla entera contendrá...</p>
<div class="code">mysql&#62;&#160;SELECT&#160;COUNT&#40;&#42;&#41;&#160;FROM&#160;mat&#95;materialsx&#59;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;COUNT&#40;&#42;&#41;&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;&#160;&#160;177047&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
1&#160;row&#160;in&#160;set&#160;&#40;0&#46;06&#160;sec&#41;</div>
<p>El objetivo final que querremos conseguir (para lo cual necesitaremos llevar a cabo una consulta) es una agrupación de esos 177.047 materiales vendidos. Para ello agruparemos tanto los tipos de material como los acabados a través de unas tablas de parametrización en las que le diremos qué tipo de material o qué acabado agrupado corresponden a cada tipo de material o acabado original. Estas dos tablas son las que ahora vemos. Primero la de tipos de material.</p>
<div class="subtitle">Tabla de agregación de tipos de material.</div>
<div class="code">mysql&#62;&#160;DESCRIBE&#160;typ&#95;alltypesx&#59;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;Field&#160;&#160;&#160;&#124;&#160;Type&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;Null&#160;&#124;&#160;Key&#160;&#124;&#160;Default&#160;&#124;&#160;Extra&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;typ&#95;bas&#160;&#124;&#160;varchar&#40;6&#41;&#160;&#124;&#160;NO&#160;&#160;&#160;&#124;&#160;PRI&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;typ&#95;agg&#160;&#124;&#160;varchar&#40;6&#41;&#160;&#124;&#160;NO&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
2&#160;rows&#160;in&#160;set&#160;&#40;0&#46;01&#160;sec&#41;</div>
<p>Es una tabla extremadamente simple donde sólo consta el tipo de material básico (el original, el que aparece en los pedidos) y el tipo de material agrupado que le corresponde a cada tipo de material básico.</p>
<p>Algunos datos de los que consta son los siguientes:</p>
<div class="code">mysql&#62;&#160;SELECT&#160;&#42;&#160;FROM&#160;typ&#95;alltypesx&#160;LIMIT&#160;5&#59;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;typ&#95;bas&#160;&#124;&#160;typ&#95;agg&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;14462&#160;&#160;&#160;&#124;&#160;524&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;202&#160;&#160;&#160;&#160;&#160;&#124;&#160;202&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;301PK&#160;&#160;&#160;&#124;&#160;524&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;304&#160;&#160;&#160;&#160;&#160;&#124;&#160;304&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;304&#47;L&#160;&#160;&#160;&#124;&#160;304&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
5&#160;rows&#160;in&#160;set&#160;&#40;0&#46;00&#160;sec&#41;</div>
<p>Así, los materiales 14462 y 301PK quedarán agrupados como material 524. Los 304 y 304/L quedarán como 304. Y así para un total de unos 70 materiales.</p>
<div class="subtitle">Tabla de agregación de acabados.</div>
<div class="code">mysql&#62;&#160;DESCRIBE&#160;fin&#95;allfinish&#59;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;Field&#160;&#160;&#160;&#124;&#160;Type&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;Null&#160;&#124;&#160;Key&#160;&#124;&#160;Default&#160;&#124;&#160;Extra&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;fin&#95;bas&#160;&#124;&#160;varchar&#40;2&#41;&#160;&#124;&#160;NO&#160;&#160;&#160;&#124;&#160;PRI&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;fin&#95;agg&#160;&#124;&#160;varchar&#40;2&#41;&#160;&#124;&#160;NO&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
2&#160;rows&#160;in&#160;set&#160;&#40;0&#46;01&#160;sec&#41;</div>
<p>También es una tabla extremadamente simple donde sólo consta el acabado básico (el original, el que aparece en los pedidos) y el acabado agrupado que le corresponde a cada acabado básico.</p>
<p>Algunos datos de los que consta son los siguientes:</p>
<div class="code">mysql&#62;&#160;SELECT&#160;&#42;&#160;FROM&#160;fin&#95;allfinish&#160;LIMIT&#160;5&#59;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;fin&#95;bas&#160;&#124;&#160;fin&#95;agg&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;1&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;1&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;1D&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;1&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;1P&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;K3&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;2B&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;2B&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;2C&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;2B&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
5&#160;rows&#160;in&#160;set&#160;&#40;0&#46;00&#160;sec&#41;</div>
<p>Así, los acabados 1 y 1D quedarán agrupados como acabado 1. El 2B y el 2C quedarán agrupados como acabado 2B. Y así para un total de 94 acabados.</p>
<div class="subtitle">Primera consulta de agrupación.</div>
<p>Tenemos pues las tres tablas presentadas. Vamos a llevar a cabo una primera ejecución de la consulta de combinación y agrupación que necesitaremos para obtener el resultado deseado y evaluaremos cuánto tiempo ha tardado MySQL en devolvernos el resultado:</p>
<div class="code">mysql&#62;&#160;SELECT&#160;typ&#95;agg&#160;AS&#160;type&#44;&#160;<br />
&#160;&#160;&#160;&#160;&#45;&#62;&#160;fin&#95;agg&#160;AS&#160;finish&#44;&#160;<br />
&#160;&#160;&#160;&#160;&#45;&#62;&#160;SUM&#40;mat&#95;qty&#41;&#160;AS&#160;quantity<br />
&#160;&#160;&#160;&#160;&#45;&#62;&#160;FROM&#160;<br />
&#160;&#160;&#160;&#160;&#45;&#62;&#160;&#40;&#40;mat&#95;materialsx&#160;LEFT&#160;JOIN&#160;typ&#95;alltypesx&#160;ON&#160;mat&#95;typ&#160;&#61;&#160;typ&#95;bas&#41;&#160;<br />
&#160;&#160;&#160;&#160;&#45;&#62;&#160;LEFT&#160;JOIN&#160;fin&#95;allfinish&#160;ON&#160;mat&#95;fin&#160;&#61;&#160;fin&#95;bas&#41;<br />
&#160;&#160;&#160;&#160;&#45;&#62;&#160;GROUP&#160;BY&#160;typ&#95;agg&#44;&#160;fin&#95;agg&#59;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;type&#160;&#160;&#124;&#160;finish&#160;&#124;&#160;quantity&#160;&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;202&#160;&#160;&#160;&#124;&#160;2B&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;7217&#160;&#124;<br />
&#124;&#160;202&#160;&#160;&#160;&#124;&#160;BA&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;31140&#160;&#124;<br />
&#124;&#160;430&#160;&#160;&#160;&#124;&#160;1&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;994298&#160;&#124;<br />
&#124;&#160;430&#160;&#160;&#160;&#124;&#160;2B&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;11621394&#160;&#124;<br />
&#124;&#160;430&#160;&#160;&#160;&#124;&#160;BA&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;22678569&#160;&#124;<br />
&#124;&#160;430&#160;&#160;&#160;&#124;&#160;K3&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;546858&#160;&#124;<br />
&#124;&#160;441&#160;&#160;&#160;&#124;&#160;2B&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;2862123&#160;&#124;<br />
&#124;&#160;441&#160;&#160;&#160;&#124;&#160;K3&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;55160&#160;&#124;<br />
&#124;&#160;524&#160;&#160;&#160;&#124;&#160;1&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;4930442&#160;&#124;<br />
&#124;&#160;524&#160;&#160;&#160;&#124;&#160;2B&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;23379844&#160;&#124;<br />
&#124;&#160;524&#160;&#160;&#160;&#124;&#160;BA&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;4499020&#160;&#124;<br />
&#124;&#160;524&#160;&#160;&#160;&#124;&#160;K3&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;652620&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
12&#160;rows&#160;in&#160;set&#160;&#40;0&#46;95&#160;sec&#41;</div>
<p>No está nada mal. En apenas un segundo ha hecho los correspondientes joins y las agregaciones de los 177.047 registros para devolvernos lo que deseábamos obtener. Entonces... ¿si estoy defendiendo la importancia de las claves foráneas y sobretodo de la unicidad, no es un contrasentido haber obtenido unos resultados tan buenos? No, no lo es. Tiene una explicación. Fijémonos que estamos haciendo las combinaciones con los cambos typ_bas y fin_bas que son claves principales en sus respectivas tablas y que por tanto son campos únicos en ellas. Dicho de otro modo, MySQL no necesita estrictamente que existan claves foráneas (en este caso serían mat_typ y mat_fin) referenciando a estas claves primarias para ejecutar la consulta rápidamente. Lo que sí necesita es que exista ese unicidad.</p>
<p>Bien, vamos a complicarlo y se entenderá mejor -espero-. Imaginemos que no estamos trabajando con datos de una sola empresa sino que formamos parte de un pequeño grupo de empresas que comparten base de datos. Así, en las tablas de parametrización de tipos de material y acabados, la clave principal no es únicamente el tipo de material y el acabado, sino que incorporamos también el código de la empresa en cuestión, ya que el material 304/L en una empresa se agrupará como 304 mientras que en otra se agrupará como 524 (es un decir).</p>
<p>De este modo las dos tablas quedarán ahora así.</p>
<div class="subtitle">Tabla de agregación de tipos de material.</div>
<div class="code">mysql&#62;&#160;describe&#160;typ&#95;alltypesx&#59;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;Field&#160;&#160;&#160;&#124;&#160;Type&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;Null&#160;&#124;&#160;Key&#160;&#124;&#160;Default&#160;&#124;&#160;Extra&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;typ&#95;cpy&#160;&#124;&#160;varchar&#40;3&#41;&#160;&#124;&#160;NO&#160;&#160;&#160;&#124;&#160;PRI&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;typ&#95;bas&#160;&#124;&#160;varchar&#40;6&#41;&#160;&#124;&#160;NO&#160;&#160;&#160;&#124;&#160;PRI&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;typ&#95;agg&#160;&#124;&#160;varchar&#40;6&#41;&#160;&#124;&#160;NO&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
3&#160;rows&#160;in&#160;set&#160;&#40;0&#46;01&#160;sec&#41;</div>
<p>Con unos datos como estos (AMG es el código de una de las empresas, concretamente de la que nos interesará, ya que pondremos absolutamente todos los datos con este código de empresa):</p>
<div class="code">mysql&#62;&#160;SELECT&#160;&#42;&#160;FROM&#160;typ&#95;alltypesx&#160;LIMIT&#160;5&#59;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;typ&#95;cpy&#160;&#124;&#160;typ&#95;bas&#160;&#124;&#160;typ&#95;agg&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;AMG&#160;&#160;&#160;&#160;&#160;&#124;&#160;14462&#160;&#160;&#160;&#124;&#160;524&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;AMG&#160;&#160;&#160;&#160;&#160;&#124;&#160;202&#160;&#160;&#160;&#160;&#160;&#124;&#160;202&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;AMG&#160;&#160;&#160;&#160;&#160;&#124;&#160;301PK&#160;&#160;&#160;&#124;&#160;524&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;AMG&#160;&#160;&#160;&#160;&#160;&#124;&#160;304&#160;&#160;&#160;&#160;&#160;&#124;&#160;304&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;AMG&#160;&#160;&#160;&#160;&#160;&#124;&#160;304&#47;L&#160;&#160;&#160;&#124;&#160;304&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
5&#160;rows&#160;in&#160;set&#160;&#40;0&#46;00&#160;sec&#41;</div>
<div class="subtitle">Tabla de agregación de acabados.</div>
<div class="code">mysql&#62;&#160;describe&#160;fin&#95;allfinish&#59;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;Field&#160;&#160;&#160;&#124;&#160;Type&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;Null&#160;&#124;&#160;Key&#160;&#124;&#160;Default&#160;&#124;&#160;Extra&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;fin&#95;cpy&#160;&#124;&#160;varchar&#40;3&#41;&#160;&#124;&#160;NO&#160;&#160;&#160;&#124;&#160;PRI&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;fin&#95;bas&#160;&#124;&#160;varchar&#40;2&#41;&#160;&#124;&#160;NO&#160;&#160;&#160;&#124;&#160;PRI&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;fin&#95;agg&#160;&#124;&#160;varchar&#40;2&#41;&#160;&#124;&#160;NO&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
3&#160;rows&#160;in&#160;set&#160;&#40;0&#46;01&#160;sec&#41;</div>
<p>Con unos datos como estos:</p>
<div class="code">mysql&#62;&#160;SELECT&#160;&#42;&#160;FROM&#160;fin&#95;allfinish&#160;LIMIT&#160;5&#59;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;fin&#95;cpy&#160;&#124;&#160;fin&#95;bas&#160;&#124;&#160;fin&#95;agg&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;AMG&#160;&#160;&#160;&#160;&#160;&#124;&#160;1&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;1&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;AMG&#160;&#160;&#160;&#160;&#160;&#124;&#160;1D&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;1&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;AMG&#160;&#160;&#160;&#160;&#160;&#124;&#160;1P&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;K3&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;AMG&#160;&#160;&#160;&#160;&#160;&#124;&#160;2B&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;2B&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;AMG&#160;&#160;&#160;&#160;&#160;&#124;&#160;2C&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;2B&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
5&#160;rows&#160;in&#160;set&#160;&#40;0&#46;00&#160;sec&#41;</div>
<div class="subtitle">Segunda consulta de agrupación.</div>
<p>Tenemos pues de nuevo las tres tablas presentadas, sólo que ahora las dos últimas han sufrido un pequeño cambio, aunque aparentemente no demasiado importante puesto que sólo hemos añadido un campo adicional, pero no hemos tocado los que ya había y siguen siendo claves primarias los que lo eran anteriormente. Vamos a llevar a cabo la segunda ejecución de la consulta de combinación y agrupación y evaluaremos cuánto tiempo ha tardado esta vez MySQL en devolvernos el resultado:</p>
<div class="code">mysql&#62;&#160;SELECT&#160;typ&#95;agg&#160;AS&#160;type&#44;&#160;<br />
&#160;&#160;&#160;&#160;&#45;&#62;&#160;fin&#95;agg&#160;AS&#160;finish&#44;&#160;<br />
&#160;&#160;&#160;&#160;&#45;&#62;&#160;SUM&#40;mat&#95;qty&#41;&#160;AS&#160;quantity<br />
&#160;&#160;&#160;&#160;&#45;&#62;&#160;FROM&#160;<br />
&#160;&#160;&#160;&#160;&#45;&#62;&#160;&#40;&#40;mat&#95;materialsx&#160;LEFT&#160;JOIN&#160;typ&#95;alltypesx&#160;ON&#160;mat&#95;typ&#160;&#61;&#160;typ&#95;bas&#41;&#160;<br />
&#160;&#160;&#160;&#160;&#45;&#62;&#160;LEFT&#160;JOIN&#160;fin&#95;allfinish&#160;ON&#160;mat&#95;fin&#160;&#61;&#160;fin&#95;bas&#41;<br />
&#160;&#160;&#160;&#160;&#45;&#62;&#160;GROUP&#160;BY&#160;typ&#95;agg&#44;&#160;fin&#95;agg&#59;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;type&#160;&#160;&#124;&#160;finish&#160;&#124;&#160;quantity&#160;&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;202&#160;&#160;&#160;&#124;&#160;2B&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;7217&#160;&#124;<br />
&#124;&#160;202&#160;&#160;&#160;&#124;&#160;BA&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;31140&#160;&#124;<br />
&#124;&#160;430&#160;&#160;&#160;&#124;&#160;1&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;994298&#160;&#124;<br />
&#124;&#160;430&#160;&#160;&#160;&#124;&#160;2B&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;11621394&#160;&#124;<br />
&#124;&#160;430&#160;&#160;&#160;&#124;&#160;BA&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;22678569&#160;&#124;<br />
&#124;&#160;430&#160;&#160;&#160;&#124;&#160;K3&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;546858&#160;&#124;<br />
&#124;&#160;441&#160;&#160;&#160;&#124;&#160;2B&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;2862123&#160;&#124;<br />
&#124;&#160;441&#160;&#160;&#160;&#124;&#160;K3&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;55160&#160;&#124;<br />
&#124;&#160;524&#160;&#160;&#160;&#124;&#160;1&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;4930442&#160;&#124;<br />
&#124;&#160;524&#160;&#160;&#160;&#124;&#160;2B&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;23379844&#160;&#124;<br />
&#124;&#160;524&#160;&#160;&#160;&#124;&#160;BA&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;4499020&#160;&#124;<br />
&#124;&#160;524&#160;&#160;&#160;&#124;&#160;K3&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;652620&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
12&#160;rows&#160;in&#160;set&#160;&#40;21&#46;02&#160;sec&#41;</div>
<p>Nada menos que 21 segundos. Una barbaridad. De acuerdo que tiene que combinar y agrupar 177.047 registros, pero tampoco son tantos... ¿qué pasará cuando sean millones? El problema que nos ha aparecido es ni más ni menos que la unicidad. Antes los campos typ_bas y fin_bas que se utilizan para los joins eran únicos. Ahora ya no lo son. Vamos a intentar solucionarlo.</p>
<div class="subtitle">Establecimiento de unicidad.</div>
<p>Para ello ejecutaremos las siguientes sentencias:</p>
<div class="code">mysql&#62;&#160;ALTER&#160;TABLE&#160;typ&#95;alltypesx&#160;<br />
&#160;&#160;&#160;&#160;&#45;&#62;&#160;CHANGE&#160;typ&#95;bas&#160;typ&#95;bas&#160;VARCHAR&#40;6&#41;&#160;UNIQUE&#59;<br />
Query&#160;OK&#44;&#160;70&#160;rows&#160;affected&#160;&#40;0&#46;03&#160;sec&#41;<br />
Records&#58;&#160;70&#160;&#160;Duplicates&#58;&#160;0&#160;&#160;Warnings&#58;&#160;0</p>
<p>mysql&#62;&#160;DESCRIBE&#160;typ&#95;alltypesx&#59;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;Field&#160;&#160;&#160;&#124;&#160;Type&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;Null&#160;&#124;&#160;Key&#160;&#124;&#160;Default&#160;&#124;&#160;Extra&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;typ&#95;cpy&#160;&#124;&#160;varchar&#40;3&#41;&#160;&#124;&#160;NO&#160;&#160;&#160;&#124;&#160;PRI&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;typ&#95;bas&#160;&#124;&#160;varchar&#40;6&#41;&#160;&#124;&#160;NO&#160;&#160;&#160;&#124;&#160;PRI&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;typ&#95;agg&#160;&#124;&#160;varchar&#40;6&#41;&#160;&#124;&#160;NO&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
3&#160;rows&#160;in&#160;set&#160;&#40;0&#46;01&#160;sec&#41;</p>
<p>mysql&#62;&#160;ALTER&#160;TABLE&#160;fin&#95;allfinish&#160;<br />
&#160;&#160;&#160;&#160;&#45;&#62;&#160;CHANGE&#160;fin&#95;bas&#160;fin&#95;bas&#160;VARCHAR&#40;2&#41;&#160;UNIQUE&#59;<br />
Query&#160;OK&#44;&#160;94&#160;rows&#160;affected&#160;&#40;0&#46;03&#160;sec&#41;<br />
Records&#58;&#160;94&#160;&#160;Duplicates&#58;&#160;0&#160;&#160;Warnings&#58;&#160;0</p>
<p>mysql&#62;&#160;DESCRIBE&#160;fin&#95;allfinish&#59;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;Field&#160;&#160;&#160;&#124;&#160;Type&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;Null&#160;&#124;&#160;Key&#160;&#124;&#160;Default&#160;&#124;&#160;Extra&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;fin&#95;cpy&#160;&#124;&#160;varchar&#40;3&#41;&#160;&#124;&#160;NO&#160;&#160;&#160;&#124;&#160;PRI&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;fin&#95;bas&#160;&#124;&#160;varchar&#40;2&#41;&#160;&#124;&#160;NO&#160;&#160;&#160;&#124;&#160;PRI&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;fin&#95;agg&#160;&#124;&#160;varchar&#40;2&#41;&#160;&#124;&#160;NO&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
3&#160;rows&#160;in&#160;set&#160;&#40;0&#46;01&#160;sec&#41;</p></div>
<p>Aparentemente las tablas no han cambiado. Al menos no nos muestra cambios en el <a href="http://dev.mysql.com/doc/refman/5.0/en/describe.html" target="_blank">DESCRIBE</a>. Sin embargo sí que lo han hecho, ya que le hemos establecido que los campos typ_bas y fin_bas además de formar parte de claves primarias, son en sí mismos únicos. Si quisiéramos que claves foráneas de otras tablas hicieran referencia a estos campos ahora podríamos hacerlo (antes no habríamos podido ya que MySQL nos habría devuelto un error), pero en realidad para evaluar la velocidad de la consulta no nos es estrictamente necesario. Ya he comentado antes que para la velocidad a la hora de combinar y agrupar MySQL requiere unicidad, no necesariamente claves foráneas. Vamos a verlo.</p>
<div class="subtitle">Tercera consulta de agrupación.</div>
<p>Respecto a la ejecución anterior sólo hemos cambiado que ahora las dos tablas de parametrización han visto como sus campos clave utilizados en los joins se han hecho únicos. Veamos cómo va la tercera ejecución de la consulta de combinación y agrupación y evaluaremos cuánto tiempo ha tardado ahora MySQL en devolvernos el resultado:</p>
<div class="code">mysql&#62;&#160;SELECT&#160;typ&#95;agg&#160;AS&#160;type&#44;&#160;<br />
&#160;&#160;&#160;&#160;&#45;&#62;&#160;fin&#95;agg&#160;AS&#160;finish&#44;&#160;<br />
&#160;&#160;&#160;&#160;&#45;&#62;&#160;SUM&#40;mat&#95;qty&#41;&#160;AS&#160;quantity<br />
&#160;&#160;&#160;&#160;&#45;&#62;&#160;FROM&#160;<br />
&#160;&#160;&#160;&#160;&#45;&#62;&#160;&#40;&#40;mat&#95;materialsx&#160;LEFT&#160;JOIN&#160;typ&#95;alltypesx&#160;ON&#160;mat&#95;typ&#160;&#61;&#160;typ&#95;bas&#41;&#160;<br />
&#160;&#160;&#160;&#160;&#45;&#62;&#160;LEFT&#160;JOIN&#160;fin&#95;allfinish&#160;ON&#160;mat&#95;fin&#160;&#61;&#160;fin&#95;bas&#41;<br />
&#160;&#160;&#160;&#160;&#45;&#62;&#160;GROUP&#160;BY&#160;typ&#95;agg&#44;&#160;fin&#95;agg&#59;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;type&#160;&#160;&#124;&#160;finish&#160;&#124;&#160;quantity&#160;&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;202&#160;&#160;&#160;&#124;&#160;2B&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;7217&#160;&#124;<br />
&#124;&#160;202&#160;&#160;&#160;&#124;&#160;BA&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;31140&#160;&#124;<br />
&#124;&#160;430&#160;&#160;&#160;&#124;&#160;1&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;994298&#160;&#124;<br />
&#124;&#160;430&#160;&#160;&#160;&#124;&#160;2B&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;11621394&#160;&#124;<br />
&#124;&#160;430&#160;&#160;&#160;&#124;&#160;BA&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;22678569&#160;&#124;<br />
&#124;&#160;430&#160;&#160;&#160;&#124;&#160;K3&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;546858&#160;&#124;<br />
&#124;&#160;441&#160;&#160;&#160;&#124;&#160;2B&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;2862123&#160;&#124;<br />
&#124;&#160;441&#160;&#160;&#160;&#124;&#160;K3&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;55160&#160;&#124;<br />
&#124;&#160;524&#160;&#160;&#160;&#124;&#160;1&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;4930442&#160;&#124;<br />
&#124;&#160;524&#160;&#160;&#160;&#124;&#160;2B&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;23379844&#160;&#124;<br />
&#124;&#160;524&#160;&#160;&#160;&#124;&#160;BA&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;4499020&#160;&#124;<br />
&#124;&#160;524&#160;&#160;&#160;&#124;&#160;K3&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;652620&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
12&#160;rows&#160;in&#160;set&#160;&#40;1&#46;43&#160;sec&#41;</div>
<p>Genial. Hemos pasado de 21 segundos a apenas uno y medio. La mejora es espectacular... ¿Qué ocurriría ahora si aprovechamos que esos campos ya son únicos para hacer que también sean el destino de claves foráneas en la tabla principal? Veámoslo.</p>
<div class="subtitle">Establecimiento de claves foráneas.</div>
<div class="code">mysql&#62;&#160;ALTER&#160;TABLE&#160;mat&#95;materialsx&#160;<br />
&#160;&#160;&#160;&#160;&#45;&#62;&#160;ADD&#160;FOREIGN&#160;KEY&#40;mat&#95;typ&#41;&#160;REFERENCES&#160;typ&#95;alltypesx&#40;typ&#95;bas&#41;&#59;<br />
Query&#160;OK&#44;&#160;177047&#160;rows&#160;affected&#160;&#40;3&#46;71&#160;sec&#41;<br />
Records&#58;&#160;177047&#160;&#160;Duplicates&#58;&#160;0&#160;&#160;Warnings&#58;&#160;0</p>
<p>mysql&#62;&#160;ALTER&#160;TABLE&#160;mat&#95;materialsx&#160;<br />
&#160;&#160;&#160;&#160;&#45;&#62;&#160;ADD&#160;FOREIGN&#160;KEY&#40;mat&#95;fin&#41;&#160;REFERENCES&#160;fin&#95;allfinish&#40;fin&#95;bas&#41;&#59;<br />
Query&#160;OK&#44;&#160;177047&#160;rows&#160;affected&#160;&#40;4&#46;10&#160;sec&#41;<br />
Records&#58;&#160;177047&#160;&#160;Duplicates&#58;&#160;0&#160;&#160;Warnings&#58;&#160;0</p></div>
<div class="subtitle">Cuarta consulta de agrupación.</div>
<p>¿Habremos mejorado algo al incorporar estas claves foráneas? Veamos, veamos...</p>
<div class="code">mysql&#62;&#160;SELECT&#160;typ&#95;agg&#160;AS&#160;type&#44;&#160;<br />
&#160;&#160;&#160;&#160;&#45;&#62;&#160;fin&#95;agg&#160;AS&#160;finish&#44;&#160;<br />
&#160;&#160;&#160;&#160;&#45;&#62;&#160;SUM&#40;mat&#95;qty&#41;&#160;AS&#160;quantity<br />
&#160;&#160;&#160;&#160;&#45;&#62;&#160;FROM&#160;<br />
&#160;&#160;&#160;&#160;&#45;&#62;&#160;&#40;&#40;mat&#95;materialsx&#160;LEFT&#160;JOIN&#160;typ&#95;alltypesx&#160;ON&#160;mat&#95;typ&#160;&#61;&#160;typ&#95;bas&#41;&#160;<br />
&#160;&#160;&#160;&#160;&#45;&#62;&#160;LEFT&#160;JOIN&#160;fin&#95;allfinish&#160;ON&#160;mat&#95;fin&#160;&#61;&#160;fin&#95;bas&#41;<br />
&#160;&#160;&#160;&#160;&#45;&#62;&#160;GROUP&#160;BY&#160;typ&#95;agg&#44;&#160;fin&#95;agg&#59;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;type&#160;&#160;&#124;&#160;finish&#160;&#124;&#160;quantity&#160;&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;202&#160;&#160;&#160;&#124;&#160;2B&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;7217&#160;&#124;<br />
&#124;&#160;202&#160;&#160;&#160;&#124;&#160;BA&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;31140&#160;&#124;<br />
&#124;&#160;430&#160;&#160;&#160;&#124;&#160;1&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;994298&#160;&#124;<br />
&#124;&#160;430&#160;&#160;&#160;&#124;&#160;2B&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;11621394&#160;&#124;<br />
&#124;&#160;430&#160;&#160;&#160;&#124;&#160;BA&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;22678569&#160;&#124;<br />
&#124;&#160;430&#160;&#160;&#160;&#124;&#160;K3&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;546858&#160;&#124;<br />
&#124;&#160;441&#160;&#160;&#160;&#124;&#160;2B&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;2862123&#160;&#124;<br />
&#124;&#160;441&#160;&#160;&#160;&#124;&#160;K3&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;55160&#160;&#124;<br />
&#124;&#160;524&#160;&#160;&#160;&#124;&#160;1&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;4930442&#160;&#124;<br />
&#124;&#160;524&#160;&#160;&#160;&#124;&#160;2B&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;23379844&#160;&#124;<br />
&#124;&#160;524&#160;&#160;&#160;&#124;&#160;BA&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;4499020&#160;&#124;<br />
&#124;&#160;524&#160;&#160;&#160;&#124;&#160;K3&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;652620&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
12&#160;rows&#160;in&#160;set&#160;&#40;1&#46;45&#160;sec&#41;</div>
<p>En este caso la respuesta es que no. Nos hemos quedado exactamente igual. No obstante con todo esto no quiero decir que las claves foráneas no sean necesarias, ya que como he dicho al comenzamiento del post, nos sirven para mantener la integridad de la base de datos (¡aspecto fundamental!). Lo único que pretendo con este post es dejar claro que MySQL no las necesita estrictamente para combinar eficientemente distintas tablas, ya que es capaz de hacerlo igual de bien simplemente con que los campos que utilizamos para los joins sean únicos.</p>
<div class="subtitle">Nota importante.</div>
<p>A lo largo de todo el ejemplo es básico ir borrando la caché de consultas de MySQL para no obtener resultados distorsionados. Para ello he utilizado la sentencia:</p>
<div class="code">mysql&#62;&#160;RESET&#160;QUERY&#160;CACHE&#59;<br />
Query&#160;OK&#44;&#160;0&#160;rows&#160;affected&#160;&#40;0&#46;00&#160;sec&#41;</div>
<p>De lo contrario nos encontraremos con tiempos de respuesta maravillosos de 0.00 sec... <img src='http://www.albertmata.net/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.albertmata.net/2008/10/claves-foraneas-vs-unique-en-mysql/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Pasando parámetros al informe en .NET con Crystal Reports.</title>
		<link>http://www.albertmata.net/2008/10/pasando-parametros-al-informe-en-net-con-crystal-reports/#utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=pasando-parametros-al-informe-en-net-con-crystal-reports</link>
		<comments>http://www.albertmata.net/2008/10/pasando-parametros-al-informe-en-net-con-crystal-reports/#comments</comments>
		<pubDate>Wed, 01 Oct 2008 20:51:43 +0000</pubDate>
		<dc:creator>Albert Mata</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Crystal Reports]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[datatable]]></category>
		<category><![CDATA[parameter]]></category>
		<category><![CDATA[report]]></category>
		<category><![CDATA[view]]></category>

		<guid isPermaLink="false">http://www.albertmata.net/?p=104</guid>
		<description><![CDATA[Hace unas semanas publiqué el post Informe en .NET con Crystal Reports y base de datos MySQL, que se convirtió rápidamente en el post más visitado de este blog. También en el que más comentarios ha recibido, y precisamente de uno de ellos ha surgido este apéndice a dicho post.
Recordemos que en él enseñábamos cómo [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-full wp-image-105" title="question" src="http://www.albertmata.net/public/uploads/2008/10/question.jpg" alt="" width="205" height="185" />Hace unas semanas publiqué el post <a href="http://www.albertmata.net/2008/07/informe-en-net-con-crystal-reports-y-base-de-datos-mysql" target="_blank">Informe en .NET con Crystal Reports y base de datos MySQL</a>, que se convirtió rápidamente en el post más visitado de este blog. También en el que más comentarios ha recibido, y precisamente de uno de ellos ha surgido este apéndice a dicho post.</p>
<p>Recordemos que en él enseñábamos cómo crear un informe con Crystal Reports utilizando un archivo XML y un DataTable (también servía un DataSet). En éste vamos a ver cómo podemos pasar parámetros al informe creado, por ejemplo para enviar el valor de un TextBox (aunque en mi ejemplo utilizaré una constante) y mostrarlo en el informe o bien utilizarlo para filtrar qué registros se tienen que mostrar y cuáles no.</p>
<p>Vamos a meternos pues en faena.</p>
<div class="subtitle">Paso 1. Recopilatorio de lo que teníamos.</div>
<p>Partíamos de un par de tablas de MySQL y una vista que se había establecido así:</p>
<div class="code">CREATE&#160;VIEW&#160;zbl&#95;bill2print&#160;AS&#160;<br />
&#40;<br />
SELECT<br />
&#160;&#160;&#160;&#160;blh&#95;num&#160;AS&#160;BILL&#95;NUMBER&#44;<br />
&#160;&#160;&#160;&#160;blh&#95;dat&#160;AS&#160;BILL&#95;DATE&#44;<br />
&#160;&#160;&#160;&#160;blh&#95;cus&#160;AS&#160;BILL&#95;CUSTOMER&#44;<br />
&#160;&#160;&#160;&#160;blp&#95;pos&#160;AS&#160;LINE&#95;NUMBER&#44;<br />
&#160;&#160;&#160;&#160;blp&#95;art&#160;AS&#160;LINE&#95;ARTICLE&#44;<br />
&#160;&#160;&#160;&#160;blp&#95;pri&#160;AS&#160;LINE&#95;UNITPRICE&#44;<br />
&#160;&#160;&#160;&#160;blp&#95;qty&#160;AS&#160;LINE&#95;UNITS&#44;<br />
&#160;&#160;&#160;&#160;blp&#95;pri&#160;&#42;&#160;blp&#95;qty&#160;AS&#160;LINE&#95;TOTALPRICE<br />
FROM<br />
&#160;&#160;&#160;&#160;blh&#95;billheader&#160;LEFT&#160;JOIN&#160;blp&#95;billposits&#160;ON&#160;blh&#95;num&#160;&#61;&#160;blp&#95;num<br />
WHERE<br />
&#160;&#160;&#160;&#160;blh&#95;num&#160;&#61;&#160;4<br />
&#41;&#59;</div>
<p>En la que por tanto filtrábamos los valores para obtener sólo los registros correspondientes a la factura número 4. Bien, vamos a cambiar eso para que ahora nuestro DataTable contenga todos los registros correspondientes a todas las facturas. La vista quedará pues ahora así:</p>
<div class="code">CREATE&#160;VIEW&#160;zbl&#95;bill2print&#160;AS&#160;<br />
&#40;<br />
SELECT<br />
&#160;&#160;&#160;&#160;blh&#95;num&#160;AS&#160;BILL&#95;NUMBER&#44;<br />
&#160;&#160;&#160;&#160;blh&#95;dat&#160;AS&#160;BILL&#95;DATE&#44;<br />
&#160;&#160;&#160;&#160;blh&#95;cus&#160;AS&#160;BILL&#95;CUSTOMER&#44;<br />
&#160;&#160;&#160;&#160;blp&#95;pos&#160;AS&#160;LINE&#95;NUMBER&#44;<br />
&#160;&#160;&#160;&#160;blp&#95;art&#160;AS&#160;LINE&#95;ARTICLE&#44;<br />
&#160;&#160;&#160;&#160;blp&#95;pri&#160;AS&#160;LINE&#95;UNITPRICE&#44;<br />
&#160;&#160;&#160;&#160;blp&#95;qty&#160;AS&#160;LINE&#95;UNITS&#44;<br />
&#160;&#160;&#160;&#160;blp&#95;pri&#160;&#42;&#160;blp&#95;qty&#160;AS&#160;LINE&#95;TOTALPRICE<br />
FROM<br />
&#160;&#160;&#160;&#160;blh&#95;billheader&#160;LEFT&#160;JOIN&#160;blp&#95;billposits&#160;ON&#160;blh&#95;num&#160;&#61;&#160;blp&#95;num<br />
&#41;&#59;</div>
<p>El resto de objetos siguen de momento igual. Esto es, el formulario frmMain y el reporte rptBill. No es preciso volver a generar el archivo XML para los cambios que vamos a hacer.</p>
<div class="subtitle">Paso 2. Añadir parámetro en el informe rptBill.</div>
<p>En el Explorador de campos hacemos click derecho en la opción Campos de parámetro para crear un nuevo parámetro. Lo creamos dándole un nombre (BillNumber) y un tipo de valor (Número) y aceptamos.</p>
<p>Si y sólo si tenemos algún interés en que este parámetro que posteriormente le enviaremos al informe aparezca en algún sitio de este informe, lo añadiremos a su área de impresión. En mi caso y sólo para que todo quede más claro, lo añado tal como se muestra en la imagen siguiente (el parámetro es el campo ?BillNumber):</p>
<p><img class="alignnone size-full wp-image-106" title="blog_031_1" src="http://www.albertmata.net/public/uploads/2008/10/blog_031_1.jpg" alt="" width="372" height="312" /></p>
<p>Pero insisto en que lo importante ha sido crearlo. Arrastrarlo hasta el área de impresión del informe es absolutamente opcional.</p>
<div class="subtitle">Paso 3. Establecer el filtro para el informe.</div>
<p>En este ejemplo partimos de un DataTable con varios registros pertenecientes a distintas facturas y desearemos filtrar el reporte para que nos muestre sólo un determinado número de factura. Para ello tenemos pues que establecer este filtro.</p>
<p>Para ello, hacemos click derecho en cualquier punto del área de impresión del report y seleccionamos la opción Report - Fórmula de selección - Registro. En el editor que nos aparece seleccionamos los campos correspondientes para terminar creando la siguiente fórmula:</p>
<div class="code">&#123;zbl&#95;bill2print&#46;BILL&#95;NUMBER&#125;&#160;&#61;&#160;&#123;&#63;BillNumber&#125;</div>
<p>Guardamos el filtro y cerramos el editor.</p>
<div class="subtitle">Paso 4. Enviar el valor del parámetro desde el formulario.</div>
<p>Ya hemos creado un parámetro en el informe y hemos definido también un filtro basado en ese parámetro. Lo último que nos queda es pues informar el valor que deseamos que coja ese parámetro. En este caso lo haremos enviándoselo desde el formulario a través de una constante, pero como he dicho antes podríamos hacerlo tomando el valor, por ejemplo, de un TextBox o un DataGridView.</p>
<p>Para enviar el valor simplemente debemos añadir esta línea al código del formulario:</p>
<div class="code">RD.SetParameterValue("BillNumber", BILL_NUMBER)</div>
<p>Con lo cual el código íntegro del formulario queda como sigue:</p>
<div class="code">&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#39;&#160;Author&#58;&#160;&#160;&#160;&#160;&#160;&#160;Albert&#160;Mata&#160;&#40;www&#46;albertmata&#46;net&#41;<br />
&#39;&#160;Date&#58;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;20081001<br />
&#39;&#160;Description&#58;&#160;Form&#160;to&#160;show&#160;how&#160;to&#160;create&#160;a&#160;report&#160;using&#160;just&#160;an&#160;XML<br />
&#39;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;file&#44;&#160;and&#160;how&#160;to&#160;send&#160;parameters&#160;to&#160;it&#46;<br />
&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
Imports&#160;CrystalDecisions&#46;CrystalReports&#46;Engine</p>
<p>Public&#160;Class&#160;frmMain</p>
<p>&#160;&#160;&#160;&#160;&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#160;&#160;&#160;&#160;&#39;&#160;Constants&#46;<br />
&#160;&#160;&#160;&#160;&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#160;&#160;&#160;&#160;Const&#160;BILL&#95;NUMBER&#160;As&#160;Integer&#160;&#61;&#160;4</p>
<p>&#160;&#160;&#160;&#160;&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#160;&#160;&#160;&#160;&#39;&#160;Creates&#160;XML&#160;file&#160;&#40;just&#160;once&#41;&#160;and&#160;creates&#160;and&#160;loads&#160;a&#160;report&#46;<br />
&#160;&#160;&#160;&#160;&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#160;&#160;&#160;&#160;Private&#160;Sub&#160;frmMain&#95;Load&#40;ByVal&#160;sender&#160;As&#160;System&#46;Object&#44;&#160;&#95;<br />
&#160;&#160;&#160;&#160;ByVal&#160;e&#160;As&#160;System&#46;EventArgs&#41;&#160;Handles&#160;MyBase&#46;Load<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Creating&#160;XML&#160;file&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Dim&#160;RC&#160;As&#160;New&#160;clsReportCreator&#40;&#34;zbl&#95;bill2print&#34;&#41;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;RC&#46;CreateXMLFile&#40;&#34;C&#58;&#92;&#34;&#41;</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Creating&#160;report&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Dim&#160;RD&#160;As&#160;ReportDocument&#160;&#61;&#160;New&#160;rptBill&#40;&#41;</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Setting&#160;data&#160;source&#160;for&#160;report&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Dim&#160;DT&#160;As&#160;DataTable&#160;&#61;&#160;RC&#46;GetDataTable&#40;&#41;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;RD&#46;SetDataSource&#40;DT&#41;</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Setting&#160;data&#160;source&#160;for&#160;possible&#160;subreports&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;For&#160;Each&#160;SR&#160;As&#160;ReportDocument&#160;In&#160;RD&#46;Subreports<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;If&#160;SR&#46;Database&#46;Tables&#46;Count&#160;&#62;&#160;0&#160;Then<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;SR&#46;SetDataSource&#40;DT&#41;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;End&#160;If<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Next</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Setting&#160;recently&#160;created&#160;report&#160;must&#160;be&#160;shown&#160;in&#160;viewer&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Me&#46;crvBill&#46;ReportSource&#160;&#61;&#160;RD</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Sending&#160;parameter&#160;to&#160;the&#160;report&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;RD&#46;SetParameterValue&#40;&#34;BillNumber&#34;&#44;&#160;BILL&#95;NUMBER&#41;</p>
<p>&#160;&#160;&#160;&#160;End&#160;Sub</p>
<p>End&#160;Class</p></div>
<p>Y esto es todo. A partir de aquí si ejecutamos la aplicación obtendremos el informe correspondiente.</p>
<p>Concretamente tal como está el código obtendremos lo siguiente:</p>
<p><img class="alignnone size-full wp-image-107" title="blog_031_2" src="http://www.albertmata.net/public/uploads/2008/10/blog_031_2.jpg" alt="" width="347" height="214" /></p>
<p>Es decir, la factura número 4 porque hemos establecido el valor de la constante BILL_NUMBER a 4. Si cambiamos ese valor por un 3 y volvemos a ejecutar, obtendremos esto otro:</p>
<p><img class="alignnone size-full wp-image-108" title="blog_031_3" src="http://www.albertmata.net/public/uploads/2008/10/blog_031_3.jpg" alt="" width="343" height="174" /></p>
<p>O sea, la factura número 3.</p>
<p>Vemos además que tanto en una como en la otra aparecen esos 4,00 y 3,00 fruto de que en el paso opcional de añadir el parámetro al área de impresión del informe, yo sí lo hice.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.albertmata.net/2008/10/pasando-parametros-al-informe-en-net-con-crystal-reports/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Jugando con formatos de fechas en MySQL.</title>
		<link>http://www.albertmata.net/2008/09/jugando-con-formatos-de-fechas-en-mysql/#utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=jugando-con-formatos-de-fechas-en-mysql</link>
		<comments>http://www.albertmata.net/2008/09/jugando-con-formatos-de-fechas-en-mysql/#comments</comments>
		<pubDate>Thu, 04 Sep 2008 10:00:40 +0000</pubDate>
		<dc:creator>Albert Mata</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[bases de datos]]></category>
		<category><![CDATA[sintaxis]]></category>
		<category><![CDATA[stored function]]></category>

		<guid isPermaLink="false">http://www.albertmata.net/?p=93</guid>
		<description><![CDATA[Este post es muy simple, pero su contenido me facilita mucho la vida desde que lo programé. Se trata de un par de simples funciones para convertir los dos formatos de fecha que más utilizo en el proyecto que estoy desarrollando. Estos dos formatos son por una parte el habitual DATE de MySQL (YYYY-MM-DD) y [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-full wp-image-88" title="mysql_code" src="http://www.albertmata.net/public/uploads/2008/08/mysql_code.jpg" alt="" width="240" height="118" />Este post es muy simple, pero su contenido me facilita mucho la vida desde que lo programé. Se trata de un par de simples funciones para convertir los dos formatos de fecha que más utilizo en el proyecto que estoy desarrollando. Estos dos formatos son por una parte el habitual <strong>DATE </strong>de <strong>MySQL </strong>(YYYY-MM-DD) y por otra parte un formato texto <strong>VARCHAR(8)</strong> que simplemente elimina los guiones (YYYYMMDD) de la fecha. Lo de utilizar este formato en modo texto viene porque recopilo mucha información de tablas en una base de datos externa en la que las fechas están almacenadas de esta manera.</p>
<p>De paso tiene la ventaja de que es insensible a configuraciones regionales que tienden a cambiar mes y día a la mínima que se les da una oportunidad...</p>
<p>Así pues, para moverme indistintamente con los dos formatos de fecha y no tener que andar preocupándome en cada ocasión si está en uno u otro formato, tengo estas dos minifunciones almacenadas en <strong>MySQL </strong>que me sirven de ayuda.</p>
<p>La primera es para pasar de formato <strong>DATE </strong>a formato <strong>VARCHAR(8)</strong>:</p>
<div class="code">&#35;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#35;&#160;STORED&#160;FUNCTION&#58;&#160;sf&#95;date2strng&#160;<br />
&#35;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#35;&#160;Author&#58;&#160;&#160;&#160;&#160;&#160;&#160;Albert&#160;Mata&#160;&#40;www&#46;albertmata&#46;net&#41;<br />
&#35;&#160;Date&#58;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;20080904<br />
&#35;&#160;Description&#58;&#160;Takes&#160;a&#160;date&#160;in&#160;YYYY&#45;MM&#45;DD&#160;format&#160;and&#160;returns&#160;it&#160;in<br />
&#35;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;YYYYMMDD&#160;format&#46;<br />
&#35;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
DROP&#160;FUNCTION&#160;IF&#160;EXISTS&#160;sf&#95;date2strng&#59;</p>
<p>DELIMITER&#160;&#47;&#47;</p>
<p>CREATE&#160;FUNCTION&#160;sf&#95;date2strng&#40;mydate&#160;DATE&#41;&#160;RETURNS&#160;VARCHAR&#40;8&#41;</p>
<p>BEGIN<br />
&#160;&#160;&#160;&#160;RETURN&#160;CONCAT&#40;MID&#40;mydate&#44;1&#44;4&#41;&#44;MID&#40;mydate&#44;6&#44;2&#41;&#44;MID&#40;mydate&#44;9&#44;2&#41;&#41;&#59;<br />
END<br />
&#47;&#47;</p>
<p>DELIMITER&#160;&#59;</p></div>
<p>Y esta segunda es para pasar de formato <strong>VARCHAR(8)</strong> a formato <strong>DATE</strong>:</p>
<div class="code">&#35;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#35;&#160;STORED&#160;FUNCTION&#58;&#160;sf&#95;strng2date&#160;<br />
&#35;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#35;&#160;Author&#58;&#160;&#160;&#160;&#160;&#160;&#160;Albert&#160;Mata&#160;&#40;www&#46;albertmata&#46;net&#41;<br />
&#35;&#160;Date&#58;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;20080904<br />
&#35;&#160;Description&#58;&#160;Takes&#160;a&#160;date&#160;in&#160;YYYYMMDD&#160;format&#160;and&#160;returns&#160;it&#160;in<br />
&#35;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;YYYY&#45;MM&#45;DD&#160;format&#46;<br />
&#35;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
DROP&#160;FUNCTION&#160;IF&#160;EXISTS&#160;sf&#95;strng2date&#59;</p>
<p>DELIMITER&#160;&#47;&#47;</p>
<p>CREATE&#160;FUNCTION&#160;sf&#95;strng2date&#40;mydate&#160;VARCHAR&#40;8&#41;&#41;&#160;RETURNS&#160;DATE</p>
<p>BEGIN<br />
&#160;&#160;&#160;&#160;RETURN&#160;STR&#95;TO&#95;DATE&#40;mydate&#44;&#39;&#37;Y&#37;c&#37;e&#39;&#41;&#59;<br />
END<br />
&#47;&#47;</p>
<p>DELIMITER&#160;&#59;</p></div>
<p>Para almacenarlas en la base de datos <strong>MySQL </strong>basta con copiar todo este código tal cual en un archivo de texto, añadirle una primera línea...</p>
<div class="code">USE&#160;nameofddbb&#59;</div>
<p>...y guardar el archivo con un nombre corto y en una ruta facilita (esto es opcional, pero para qué complicarse la vida), como por ejemplo <strong>C:\in.txt</strong>. Hecho esto, basta con escribir en un símbolo de sistema de <strong>Windows </strong>(antes de entrar en <strong>MySQL</strong>):</p>
<div class="code">mysql&#160;&#45;u&#160;root&#160;&#45;p&#160;&#60;&#160;C&#58;&#92;in&#46;txt</div>
<p>También podemos hacerlo con un usuario no <strong>root</strong>, pero tiene que tener suficientes permisos para poder crear un procedimiento almacenado en la base de datos concreta que hayamos especificado en esa primera línea del archivo de texto.</p>
<p>Una vez tenemos las funciones almacenadas en <strong>MySQL </strong>comprobamos que funcionan. Primero le introducimos una fecha para que nos la convierta a texto y vemos que funciona sin problemas:</p>
<div class="code">mysql&#62;&#160;SELECT&#160;sf&#95;date2strng&#40;&#39;2008&#45;09&#45;04&#39;&#41;&#59;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;sf&#95;date2strng&#40;&#39;2008&#45;09&#45;04&#39;&#41;&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;20080904&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
1&#160;row&#160;in&#160;set&#160;&#40;0&#46;00&#160;sec&#41;</div>
<p>También podemos introducirle una fecha completa (con hora) y funcionará también bien. Sin embargo nos avisará de que se ha generado un <strong>warning</strong>. Si lo miramos vemos que no es nada grave, simplemente nos informa de que ha desestimado totalmente la hora, lo cual no nos importa.</p>
<div class="code">mysql&#62;&#160;SELECT&#160;sf&#95;date2strng&#40;&#39;2008&#45;09&#45;04&#160;18&#58;23&#58;45&#39;&#41;&#59;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;sf&#95;date2strng&#40;&#39;2008&#45;09&#45;04&#160;18&#58;23&#58;45&#39;&#41;&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;20080904&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
1&#160;row&#160;in&#160;set&#44;&#160;1&#160;warning&#160;&#40;0&#46;00&#160;sec&#41;</p>
<p>mysql&#62;&#160;SHOW&#160;WARNINGS&#59;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;Level&#160;&#124;&#160;Code&#160;&#124;&#160;Message&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;Note&#160;&#160;&#124;&#160;1265&#160;&#124;&#160;Data&#160;truncated&#160;for&#160;column&#160;&#39;mydate&#39;&#160;at&#160;row&#160;1&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
1&#160;row&#160;in&#160;set&#160;&#40;0&#46;00&#160;sec&#41;</p></div>
<p>A continuación probamos la segunda función, introduciéndole un texto que representa una fecha para que nos la convierta a tipo <strong>DATE</strong>:</p>
<div class="code">mysql&#62;&#160;SELECT&#160;sf&#95;strng2date&#40;&#39;20081026&#39;&#41;&#59;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;sf&#95;strng2date&#40;&#39;20081026&#39;&#41;&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;2008&#45;10&#45;26&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
1&#160;row&#160;in&#160;set&#160;&#40;0&#46;00&#160;sec&#41;</div>
<p>A partir de aquí podremos utilizar estas dos funciones en cualquier consulta, vista u otro procedimiento o función almacenada que deseemos.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.albertmata.net/2008/09/jugando-con-formatos-de-fechas-en-mysql/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Instrucciones menos habituales en MySQL (1a parte).</title>
		<link>http://www.albertmata.net/2008/08/instrucciones-menos-habituales-en-mysql-1a-parte/#utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=instrucciones-menos-habituales-en-mysql-1a-parte</link>
		<comments>http://www.albertmata.net/2008/08/instrucciones-menos-habituales-en-mysql-1a-parte/#comments</comments>
		<pubDate>Tue, 26 Aug 2008 14:41:28 +0000</pubDate>
		<dc:creator>Albert Mata</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[bases de datos]]></category>
		<category><![CDATA[sintaxis]]></category>
		<category><![CDATA[stored function]]></category>
		<category><![CDATA[stored procedure]]></category>
		<category><![CDATA[tabla]]></category>
		<category><![CDATA[trigger]]></category>
		<category><![CDATA[view]]></category>
		<category><![CDATA[vista]]></category>

		<guid isPermaLink="false">http://www.albertmata.net/?p=87</guid>
		<description><![CDATA[Utilizando la base de datos MySQL como acostumbro, constantemente estoy lidiando con las sintaxis más habituales para crear y modificar tablas, funciones, vistas y demás. No obstante, hay también por ahí un conjunto de instrucciones que alguna vez he utilizado y que solía tener que googlear porque nunca las recordaba desde la vez anterior. Hasta [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-full wp-image-88" title="mysql_code" src="http://www.albertmata.net/public/uploads/2008/08/mysql_code.jpg" alt="" width="240" height="118" />Utilizando la base de datos <strong>MySQL </strong>como acostumbro, constantemente estoy lidiando con las sintaxis más habituales para crear y modificar tablas, funciones, vistas y demás. No obstante, hay también por ahí un conjunto de instrucciones que alguna vez he utilizado y que solía tener que googlear porque nunca las recordaba desde la vez anterior. Hasta que me decidí a ir anotándolas, por tontas y breves que fueran. Y ahora, ya que estamos, me ha parecido buena idea compartirlas por si a alguien le sirven de algo.</p>
<p><span style="color: #ff6600;"><span style="text-decoration: underline;"><strong>Ver el código que en su día utilizamos para crear una vista.</strong></span></span></p>
<p>Si por ejemplo hacemos un...</p>
<div class="code">
DESCRIBE&#160;tbl&#95;tablenamex&#59;
</div>
<p>...sobre una tabla o una vista, nos devuelve la estructura de esa tabla o vista, con sus campos y tipos de datos y demás información básica. No obstante, en ocasiones con las vistas me interesa ver de una manera rápida con qué sintaxis exacta la creé (de dónde saqué los campos, cómo enlacé las tablas, etc.). Normalmente tengo esa información guardada en archivos de texto, ya que raramente creo una vista directamente en consola, sino que más bien suelo hacerlo a través de archivos planos. No obstante me resulta más rápido verlo directamente en la consola que tener que ir a buscar el archivo. Para ello me valgo de...</p>
<div class="code">
SHOW&#160;CREATE&#160;VIEW&#160;viw&#95;viewnamexx&#59;
</div>
<p>...y obtengo, aunque de un modo no muy agradable de ver, la sintaxis que utilicé para crear la vista en su momento.</p>
<p><span style="color: #ff6600;"><span style="text-decoration: underline;"><strong>Reiniciar el contador autonumérico de una tabla.</strong></span></span></p>
<p>A menudo utilizo campos autonuméricos en mis tablas. Aunque tienen algún inconveniente, si se utilizan únicamente a modo de campo identificador para uso fundamentalmente interno, suelen aportar mayores ventajas que inconvenientes presentan. ¿Pero cómo reiniciamos el contador autonumérico después de haber estado trasteando con la tabla? Muy fácil, en dos pasos. El primero es asegurarnos que la tabla está totalmente vacía de registros. El segundo consiste en aplicar...</p>
<div class="code">
ALTER&#160;TABLE&#160;tbl&#95;tablenamex&#160;AUTO&#95;INCREMENT&#160;&#61;&#160;1&#59;
</div>
<p>...y el contador habrá quedado convenientemente reseteado. Si queremos que se resetee pero que no comience de nuevo por el 1 sino por ejemplo por el 1001, también se lo podemos indicar con esta misma instrucción.</p>
<p><span style="color: #ff6600;"><span style="text-decoration: underline;"><strong>Listar todas las tablas en una base de datos.</strong></span></span></p>
<p>En principio para hacer esto nos podemos valer de un simple...</p>
<div class="code">
SHOW&#160;TABLES&#59;
</div>
<p>...pero esto solo nos listará las tablas sin añadir mayor información, cosa que la mayor parte de las veces nos puede ser más que suficiente. Sin embargo si queremos obtener más información podemos utilizar...</p>
<div class="code">
SELECT&#160;&#42;<br />
FROM&#160;information&#95;schema&#46;tables<br />
WHERE&#160;table&#95;schema&#160;&#61;&#160;&#39;nameofddbb&#39;&#59;
</div>
<p>...y obtendremos no solo el nombre sino también si se trata de una tabla o vista, qué motor utiliza (<strong><a href="http://es.wikipedia.org/wiki/InnoDB" target="_blank">InnoDB</a></strong>, <strong><a href="http://es.wikipedia.org/wiki/MyISAM" target="_blank">MyISAM</a></strong>...), el número de registros, la fecha de creación, aspectos sobre el tamaño, etc.</p>
<p><span style="color: #ff6600;"><span style="text-decoration: underline;"><strong>Listar todos los campos en una tabla.</strong></span></span></p>
<p>Del mismo modo, para los campos podemos hacer como hemos dicho antes un...</p>
<div class="code">
DESCRIBE&#160;tbl&#95;tablenamex&#59;
</div>
<p>...pero si queremos un poco más de información también podemos recurrir a...</p>
<div class="code">
SELECT&#160;&#42;<br />
FROM&#160;information&#95;schema&#46;columns<br />
WHERE&#160;table&#95;name&#160;&#61;&#160;&#39;tbl&#95;tablenamex&#39;&#59;
</div>
<p>...y como ocurría con las tablas obtendremos algo más de información.</p>
<p><span style="color: #ff6600;"><span style="text-decoration: underline;"><strong>Obtener información sobre rutinas.</strong></span></span></p>
<p>Si lo que queremos es obtener información sobre funciones o procedimientos almacenados en una base de datos (incluyendo el código fuente con el que se crearon), podemos utilizar...</p>
<div class="code">
SELECT&#160;&#42;<br />
FROM&#160;information&#95;schema&#46;routines<br />
WHERE&#160;routine&#95;schema&#160;&#61;&#160;&#39;nameofddbb&#39;&#59;
</div>
<p><span style="color: #ff6600;"><span style="text-decoration: underline;"><strong>Obtener información sobre vistas (otro método).</strong></span></span></p>
<p>Si de lo que queremos obtener información más detallada (incluyendo nuevamente el código utilizado en la generación) es una vista, podemos utilizar...</p>
<div class="code">
SELECT&#160;&#42;<br />
FROM&#160;information&#95;schema&#46;views<br />
WHERE&#160;table&#95;schema&#160;&#61;&#160;&#39;nameofddbb&#39;&#59;
</div>
<p><span style="color: #ff6600;"><span style="text-decoration: underline;"><strong>Obtener información sobre triggers (disparadores).</strong></span></span></p>
<p>Y si lo que queremos es obtener información más detallada sobre disparadores o <strong><a href="http://es.wikipedia.org/wiki/Trigger_(base_de_datos)" target="_blank">triggers</a></strong> (también incluyendo el código con el que se han generado), podemos utilizar...</p>
<div class="code">
SELECT&#160;&#42;<br />
FROM&#160;information&#95;schema&#46;triggers<br />
WHERE&#160;trigger&#95;schema&#160;&#61;&#160;&#39;nameofddbb&#39;&#59;
</div>
<p><span style="color: #ff6600;"><span style="text-decoration: underline;"><strong>Copiar una tabla y opcionalmente rellenarla.</strong></span></span></p>
<p>Si deseamos crear una copia de una tabla en la misma o en otra base de datos, podemos utilizar primero esta instrucción para copiar la estructura...</p>
<div class="code">
CREATE&#160;TABLE&#160;tbl&#95;targettabl&#160;LIKE&#160;nameofddbb&#46;tbl&#95;sourcetabl&#59;
</div>
<p>...y nos creará una tabla destino igual que la tabla origen, solo que sin datos dentro. Para copiar a continuación todos los datos nos bastará con...</p>
<div class="code">
INSERT&#160;INTO&#160;tbl&#95;targettabl<br />
SELECT&#160;&#42;&#160;FROM&#160;nameofddbb&#46;tbl&#95;sourcetabl&#59;
</div>
<p>De hecho, en caso de querer copiar tanto estructura como datos, también podríamos haberlo hecho en un solo paso con...</p>
<div class="code">
CREATE&#160;TABLE&#160;tbl&#95;targettabl<br />
SELECT&#160;&#42;&#160;FROM&#160;nameofddbb&#46;tbl&#95;sourcetabl&#59;
</div>
<p>...pero para mí gusto, este método presenta el inconveniente de que si la tabla contiene claves principales no se trasladan a la copia, por lo cual yo prefiero siempre el método en dos pasos.</p>
<p>Y lo de añadir <strong>nameofddbb.</strong> antes del nombre de la tabla está claro que sólo será preciso cuando estemos operando con dos bases de datos distintas (si solo trabajamos con una no es preciso añadirlo).</p>
<p>Esto es todo por ahora. Seguro que me dejo más instrucciones de esas poco frecuentes que a veces necesitamos, así que titulo intencionadamente el post con lo de <strong>1a parte</strong> en previsión de que más adelante pueda haber otras.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.albertmata.net/2008/08/instrucciones-menos-habituales-en-mysql-1a-parte/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Informe en .NET con Crystal Reports y base de datos MySQL.</title>
		<link>http://www.albertmata.net/2008/07/informe-en-net-con-crystal-reports-y-base-de-datos-mysql/#utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=informe-en-net-con-crystal-reports-y-base-de-datos-mysql</link>
		<comments>http://www.albertmata.net/2008/07/informe-en-net-con-crystal-reports-y-base-de-datos-mysql/#comments</comments>
		<pubDate>Thu, 31 Jul 2008 16:14:01 +0000</pubDate>
		<dc:creator>Albert Mata</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Crystal Reports]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[bases de datos]]></category>
		<category><![CDATA[connection string]]></category>
		<category><![CDATA[dataset]]></category>
		<category><![CDATA[datatable]]></category>
		<category><![CDATA[informe]]></category>
		<category><![CDATA[odbc]]></category>
		<category><![CDATA[report]]></category>
		<category><![CDATA[xml]]></category>

		<guid isPermaLink="false">http://www.albertmata.net/?p=70</guid>
		<description><![CDATA[Vaya por delante que el tema de la creación de informes (o reports) siempre ha sido una de las partes de la programación que me ha dado más pereza. Pero está claro que pocas aplicaciones se salvan de requerirlos en mayor o menor grado, y la que actualmente tengo entre manos no es, en absoluto, [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-full wp-image-74" title="xmlreport" src="http://www.albertmata.net/public/uploads/2008/07/xmlreport.jpg" alt="" width="230" height="227" />Vaya por delante que el tema de la creación de informes (o reports) siempre ha sido una de las partes de la programación que me ha dado más pereza. Pero está claro que pocas aplicaciones se salvan de requerirlos en mayor o menor grado, y la que actualmente tengo entre manos no es, en absoluto, una excepción. Así pues, estos últimos días he tenido que preparar un nuevo report y de paso he aprovechado para investigar un poco y descubrir una nueva manera de realizarlos. Paso a explicarme.</p>
<p>Como ya he comentado en ocasiones, mi entorno de desarrollo es VisualBasic.NET y una base de datos MySQL. Y los informes los hago con el propio Crystal Reports que incorpora el VisualStudio.NET. El tema está en que hasta ahora los hacía a través de una conexión ODBC que tenía que instalar en cada máquina apuntando hacia el servidor MySQL, pero este sistema no me gustaba demasiado. Y no me gustaba porque en realidad de bases de datos tengo distintas con distintos nombres pero con las mismas estructuras de tablas y datos parecidos, ya que una es la productiva (la real, la buena) y las otras son para desarrollo, para que los usuarios hagan pruebas sin que afecte a los datos reales, etc. Controlar la cadena de conexión en la aplicación para que ataque a una u otra base de datos no me supone el más mínimo problema, pero los informes cogen sus datos a través de una conexión ODBC concreta y ésta en cada máquina ataca a una única base de datos. Así que no me convence este sistema.</p>
<p>Y ahora he descubierto cómo puede crear informes a través de un DataTable y de una estructura en un archivo XML, sin necesidad de nada más. De hecho en lugar de un DataTable se puede utilizar perfectamente un DataSet y funciona sin ningún tipo de problemas ni apenas modificaciones (dejo en manos del lector probarlo si le interesa). Voy a pasar a explicar mediante un ejemplo y algunas imágenes cómo realizarlo desde cero.</p>
<p>Partiré de dos tables en mi base de datos MySQL en las que guardaré información de facturas. La primera tabla es de cabeceras de esas facturas y tiene estos datos:</p>
<div class="code">&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;blh&#95;num&#160;&#124;&#160;blh&#95;dat&#160;&#160;&#160;&#160;&#124;&#160;blh&#95;cus&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1&#160;&#124;&#160;2008&#45;07&#45;30&#160;&#124;&#160;CERAMICAS&#160;PEPE&#44;&#160;S&#46;A&#46;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;2&#160;&#124;&#160;2008&#45;07&#45;30&#160;&#124;&#160;TALLERES&#160;GOMEZ&#44;&#160;S&#46;L&#46;&#160;&#160;&#160;&#160;&#124;<br />
&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;3&#160;&#124;&#160;2008&#45;07&#45;31&#160;&#124;&#160;DEPORTES&#160;DAMIAN&#44;&#160;S&#46;L&#46;&#160;&#160;&#160;&#124;<br />
&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;4&#160;&#124;&#160;2008&#45;07&#45;31&#160;&#124;&#160;SOFTWARE&#160;ALBERTMATA&#46;NET&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;</div>
<p>La segunda tabla son las posiciones de cada factura y tiene estos otros datos:</p>
<div class="code">&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;blp&#95;num&#160;&#124;&#160;blp&#95;pos&#160;&#124;&#160;blp&#95;art&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;blp&#95;pri&#160;&#124;&#160;blp&#95;qty&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;<br />
&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1&#160;&#124;&#160;RATON&#160;LOGITECH&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;15&#46;95&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1&#160;&#124;<br />
&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;2&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1&#160;&#124;&#160;MONITOR&#160;LG&#160;19&#160;PULGADAS&#160;&#124;&#160;&#160;&#160;210&#46;5&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1&#160;&#124;<br />
&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;3&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1&#160;&#124;&#160;ROUTER&#160;DLINK&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;56&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1&#160;&#124;<br />
&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;4&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1&#160;&#124;&#160;RATON&#160;LOGITECH&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;15&#46;95&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;2&#160;&#124;<br />
&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;4&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;2&#160;&#124;&#160;TECLADO&#160;LOGITECH&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;12&#46;95&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1&#160;&#124;<br />
&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;4&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;3&#160;&#124;&#160;RECEPTOR&#160;GPS&#160;ZAPPA&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;59&#46;95&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1&#160;&#124;<br />
&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;4&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;4&#160;&#124;&#160;PAQUETE&#160;500&#160;FOLIOS&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;3&#46;7&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;4&#160;&#124;<br />
&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#43;</div>
<p>Es algo muy sencillo y poco <a href="http://es.wikipedia.org/wiki/Normalizaci%C3%B3n_de_bases_de_datos" target="_blank">normalizado</a>, pero nos servirá para el ejemplo. Concretamente vamos a crear un informe que será nada más que una impresión de una factura. Como voy a trabajar con un simple DataTable pero mi informe requerirá datos de dos tablas, me crearé primero una <a href="http://dev.mysql.com/doc/refman/5.0/en/views.html" target="_blank">vista</a> en MySQL con la siguiente instrucción:</p>
<div class="code">CREATE&#160;VIEW&#160;zbl&#95;bill2print&#160;AS&#160;<br />
&#40;<br />
SELECT<br />
&#160;&#160;&#160;&#160;blh&#95;num&#160;AS&#160;BILL&#95;NUMBER&#44;<br />
&#160;&#160;&#160;&#160;blh&#95;dat&#160;AS&#160;BILL&#95;DATE&#44;<br />
&#160;&#160;&#160;&#160;blh&#95;cus&#160;AS&#160;BILL&#95;CUSTOMER&#44;<br />
&#160;&#160;&#160;&#160;blp&#95;pos&#160;AS&#160;LINE&#95;NUMBER&#44;<br />
&#160;&#160;&#160;&#160;blp&#95;art&#160;AS&#160;LINE&#95;ARTICLE&#44;<br />
&#160;&#160;&#160;&#160;blp&#95;pri&#160;AS&#160;LINE&#95;UNITPRICE&#44;<br />
&#160;&#160;&#160;&#160;blp&#95;qty&#160;AS&#160;LINE&#95;UNITS&#44;<br />
&#160;&#160;&#160;&#160;blp&#95;pri&#160;&#42;&#160;blp&#95;qty&#160;AS&#160;LINE&#95;TOTALPRICE<br />
FROM<br />
&#160;&#160;&#160;&#160;blh&#95;billheader&#160;LEFT&#160;JOIN&#160;blp&#95;billposits&#160;ON&#160;blh&#95;num&#160;&#61;&#160;blp&#95;num<br />
WHERE<br />
&#160;&#160;&#160;&#160;blh&#95;num&#160;&#61;&#160;4<br />
&#41;&#59;</div>
<p>Así, mi informe a partir de ahora se realizará sobre esta vista zbl_bill2print. Vamos pues a empezar con la parte que incumbe a .NET.</p>
<div class="subtitle">Paso 1. Creación del archivo XML con la estructura de la tabla/vista.</div>
<p>Para todo el ejemplo jugaremos con:</p>
<p>1) un formulario frmMain donde tendremos el objeto visualizador de informes.<br />
2) una clase clsReportCreator que crearemos a continuación.<br />
3) un informe rptBill que representará la factura que queremos imprimir.</p>
<p>Comenzamos pues creando la clase clsReportCreator, que constará de un único atributo (el nombre de la tabla o vista), un método constructor, un método para cargar el DataTable correspondiente y un último método para generar el archivo XML. El código completo de esta clase es el siguiente:</p>
<div class="code">&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#39;&#160;Author&#58;&#160;&#160;&#160;&#160;&#160;&#160;Albert&#160;Mata&#160;&#40;www&#46;albertmata&#46;net&#41;<br />
&#39;&#160;Date&#58;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;20080731<br />
&#39;&#160;Needs&#58;&#160;&#160;&#160;&#160;&#160;&#160;&#160;MySQL&#46;Data&#160;reference&#46;<br />
&#39;&#160;Description&#58;&#160;Class&#160;to&#160;create&#160;a&#160;report&#160;using&#160;just&#160;an&#160;XML&#160;file&#46;&#160;<br />
&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
Imports&#160;MySql&#46;Data&#46;MySqlClient</p>
<p>Public&#160;Class&#160;clsReportCreator</p>
<p>&#160;&#160;&#160;&#160;&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#160;&#160;&#160;&#160;&#39;&#160;Attributes&#46;<br />
&#160;&#160;&#160;&#160;&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#160;&#160;&#160;&#160;Private&#160;TableOrView&#160;As&#160;String</p>
<p>&#160;&#160;&#160;&#160;&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#160;&#160;&#160;&#160;&#39;&#160;Constructor&#160;method&#46;<br />
&#160;&#160;&#160;&#160;&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#160;&#160;&#160;&#160;Public&#160;Sub&#160;New&#40;ByVal&#160;TableOrView&#160;As&#160;String&#41;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Me&#46;TableOrView&#160;&#61;&#160;TableOrView<br />
&#160;&#160;&#160;&#160;End&#160;Sub</p>
<p>&#160;&#160;&#160;&#160;&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#160;&#160;&#160;&#160;&#39;&#160;Returns&#160;DataTable&#160;corresponding&#160;to&#160;TableOrView&#46;<br />
&#160;&#160;&#160;&#160;&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#160;&#160;&#160;&#160;Public&#160;Function&#160;GetDataTable&#40;&#41;&#160;As&#160;DataTable<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Dim&#160;DA&#160;As&#160;MySqlDataAdapter<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Dim&#160;DS&#160;As&#160;New&#160;DataSet<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Dim&#160;DT&#160;As&#160;DataTable<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Dim&#160;ConnectionString&#160;As&#160;String<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Dim&#160;SQL&#160;As&#160;String</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Setting&#160;connection&#160;string&#160;to&#160;connect&#160;to&#160;MySQL&#160;database&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;ConnectionString&#160;&#61;&#160;&#34;Database&#160;&#61;&#160;blog&#59;&#160;&#34;&#160;&#95;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#38;&#160;&#34;Data&#160;Source&#160;&#61;&#160;localhost&#59;&#160;&#34;&#160;&#95;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#38;&#160;&#34;User&#160;ID&#160;&#61;&#160;root&#59;&#160;&#34;&#160;&#95;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#38;&#160;&#34;Password&#160;&#61;&#160;mypassword&#34;</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Setting&#160;SQL&#160;string&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;SQL&#160;&#61;&#160;&#34;SELECT&#160;&#42;&#160;FROM&#160;&#34;&#160;&#38;&#160;Me&#46;TableOrView</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Getting&#160;data&#160;and&#160;filling&#160;DataSet&#160;and&#160;DataTable&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;DA&#160;&#61;&#160;New&#160;MySqlDataAdapter&#40;SQL&#44;&#160;ConnectionString&#41;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;DA&#46;Fill&#40;DS&#44;&#160;Me&#46;TableOrView&#41;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;DT&#160;&#61;&#160;DS&#46;Tables&#40;Me&#46;TableOrView&#41;</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Returning&#160;DataTable&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Return&#160;DT<br />
&#160;&#160;&#160;&#160;End&#160;Function</p>
<p>&#160;&#160;&#160;&#160;&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#160;&#160;&#160;&#160;&#39;&#160;Creates&#160;XML&#160;file&#160;in&#160;desired&#160;path&#46;<br />
&#160;&#160;&#160;&#160;&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#160;&#160;&#160;&#160;Public&#160;Sub&#160;CreateXMLFile&#40;ByVal&#160;FilePath&#160;As&#160;String&#41;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Dim&#160;DT&#160;As&#160;DataTable</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Creating&#160;DataTable&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;DT&#160;&#61;&#160;Me&#46;GetDataTable&#40;&#41;</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Writting&#160;XML&#160;file&#160;in&#160;desired&#160;path&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;DT&#46;WriteXmlSchema&#40;FilePath&#160;&#38;&#160;Me&#46;TableOrView&#160;&#38;&#160;&#34;&#46;xml&#34;&#41;<br />
&#160;&#160;&#160;&#160;End&#160;Sub</p>
<p>End&#160;Class</p></div>
<p>Y creamos también el formulario frmMain cuyo único código por el momento (después cambiará un poco) será el que sigue:</p>
<div class="code">&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#39;&#160;Author&#58;&#160;&#160;&#160;&#160;&#160;&#160;Albert&#160;Mata&#160;&#40;www&#46;albertmata&#46;net&#41;<br />
&#39;&#160;Date&#58;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;20080731<br />
&#39;&#160;Description&#58;&#160;Form&#160;to&#160;show&#160;how&#160;to&#160;create&#160;a&#160;report&#160;using&#160;just&#160;an&#160;XML<br />
&#39;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;file&#46;&#160;<br />
&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
Public&#160;Class&#160;frmMain</p>
<p>&#160;&#160;&#160;&#160;&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#160;&#160;&#160;&#160;&#39;&#160;As&#160;a&#160;first&#160;step&#44;&#160;creates&#160;XML&#160;file&#46;<br />
&#160;&#160;&#160;&#160;&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#160;&#160;&#160;&#160;Private&#160;Sub&#160;frmMain&#95;Load&#40;ByVal&#160;sender&#160;As&#160;System&#46;Object&#44;&#160;&#95;<br />
&#160;&#160;&#160;&#160;ByVal&#160;e&#160;As&#160;System&#46;EventArgs&#41;&#160;Handles&#160;MyBase&#46;Load<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Creating&#160;XML&#160;file&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Dim&#160;RC&#160;As&#160;New&#160;clsReportCreator&#40;&#34;zbl&#95;bill2print&#34;&#41;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;RC&#46;CreateXMLFile&#40;&#34;C&#58;&#92;&#34;&#41;<br />
&#160;&#160;&#160;&#160;End&#160;Sub</p>
<p>End&#160;Class</p></div>
<p>Con esto tenemos una primera aplicación que al ejecutarla nos creará el archivo C:\zbl_bill2print.xml con la estructura de la vista zbl_bill2print. Lo probamos pues y obtenemos un archivo como <a href="http://www.albertmata.net/files/zbl_bill2print.xml" target="_blank">éste</a>.</p>
<div class="subtitle">Paso 2. Creación del informe e inserción del origen de datos.</div>
<p>Añadimos al proyecto un informe al que llamaremos rptBill.rpt y que crearemos seleccionando la alternativa Como informe en blanco y por tanto desestimando plantillas.</p>
<p>A continuación en el menú Explorador de campos seleccionamos la primera opción Campos de base de datos y en su menú contextual hacemos click en la opción Asistente de base de datos.</p>
<p style="text-align: center;"><img class="alignnone size-full wp-image-75" title="blog_020_1" src="http://www.albertmata.net/public/uploads/2008/07/blog_020_1.jpg" alt="" width="224" height="147" /></p>
<p>En el menú que se despliega (Orígenes de datos disponibles) seleccionamos Crear nueva conexión y a continuación la opción ADO.NET.</p>
<p style="text-align: center;"><img class="alignnone size-full wp-image-76" title="blog_020_2" src="http://www.albertmata.net/public/uploads/2008/07/blog_020_2.jpg" alt="" width="232" height="305" /></p>
<p>Con esto se nos abrira un nuevo formulario en el que nos solicitará la Ruta del archivo. Debemos aquí ir a buscar el archivo XML que hemos creado anteriormente (en mi caso el C:\zbl_bill2print.xml) y acto seguido pulsar en Finalizar. Con ello, en el menú anterior (Orígenes de datos disponibles) se nos mostrará ya la opción NewDataSet incluyendo el zbl_bill2print que acabamos de añadir.</p>
<p style="text-align: center;"><img class="alignnone size-full wp-image-77" title="blog_020_3" src="http://www.albertmata.net/public/uploads/2008/07/blog_020_3.jpg" alt="" width="232" height="305" /></p>
<p>Lo marcamos y le damos al botón para trasladarlo al menú de Tablas seleccionadas y pulsamos en Aceptar.</p>
<p style="text-align: center;"><img class="alignnone size-full wp-image-78" title="blog_020_4" src="http://www.albertmata.net/public/uploads/2008/07/blog_020_4.jpg" alt="" width="231" height="305" /></p>
<p>Con esto hemos conseguido que en el menú Explorador de campos nos aparezca ya la estructura de zbl_bill2print con sus campos, tal como se muestra a continuación:</p>
<p style="text-align: center;"><img class="alignnone size-full wp-image-79" title="blog_020_5" src="http://www.albertmata.net/public/uploads/2008/07/blog_020_5.jpg" alt="" width="224" height="311" /></p>
<div class="subtitle">Paso 3. Diseño del informe.</div>
<p>No tiene ningún misterio. Se trata de añadir los campos desde el menú Explorador de campos donde corresponda, insertarle los objetos de texto que nos parezcan adecuados, los totales cuando sea preciso, dar formato a los textos, incorporar imágenes y demás florituras a nuestro antojo...</p>
<p>Yo me inclino por un diseño sobrio como éste:</p>
<p style="text-align: center;"><img class="alignnone size-full wp-image-80" title="blog_020_6" src="http://www.albertmata.net/public/uploads/2008/07/blog_020_6.jpg" alt="" width="399" height="313" /></p>
<div class="subtitle">Paso 4. Últimos pasos para obtener la factura.</div>
<p>Por último vamos ya a crear la factura. Para ello en el formulario frmMain añadiremos un objeto de tipo CrystalReportViewer al que llamaremos por ejemplo crvBill. Y modificamos el código de frmMain para dejarlo como sigue:</p>
<div class="code">&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#39;&#160;Author&#58;&#160;&#160;&#160;&#160;&#160;&#160;Albert&#160;Mata&#160;&#40;www&#46;albertmata&#46;net&#41;<br />
&#39;&#160;Date&#58;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;20080731<br />
&#39;&#160;Description&#58;&#160;Form&#160;to&#160;show&#160;how&#160;to&#160;create&#160;a&#160;report&#160;using&#160;just&#160;an&#160;XML<br />
&#39;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;file&#46;&#160;<br />
&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
Imports&#160;CrystalDecisions&#46;CrystalReports&#46;Engine</p>
<p>Public&#160;Class&#160;frmMain</p>
<p>&#160;&#160;&#160;&#160;&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#160;&#160;&#160;&#160;&#39;&#160;Creates&#160;XML&#160;file&#160;&#40;just&#160;once&#41;&#160;and&#160;creates&#160;and&#160;loads&#160;a&#160;report&#46;<br />
&#160;&#160;&#160;&#160;&#39;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;<br />
&#160;&#160;&#160;&#160;Private&#160;Sub&#160;frmMain&#95;Load&#40;ByVal&#160;sender&#160;As&#160;System&#46;Object&#44;&#160;&#95;<br />
&#160;&#160;&#160;&#160;ByVal&#160;e&#160;As&#160;System&#46;EventArgs&#41;&#160;Handles&#160;MyBase&#46;Load<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Creating&#160;XML&#160;file&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Dim&#160;RC&#160;As&#160;New&#160;clsReportCreator&#40;&#34;zbl&#95;bill2print&#34;&#41;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;RC&#46;CreateXMLFile&#40;&#34;C&#58;&#92;&#34;&#41;</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Creating&#160;report&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Dim&#160;RD&#160;As&#160;ReportDocument&#160;&#61;&#160;New&#160;rptBill&#40;&#41;</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Setting&#160;data&#160;source&#160;for&#160;report&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Dim&#160;DT&#160;As&#160;DataTable&#160;&#61;&#160;RC&#46;GetDataTable&#40;&#41;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;RD&#46;SetDataSource&#40;DT&#41;</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Setting&#160;data&#160;source&#160;for&#160;possible&#160;subreports&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;For&#160;Each&#160;SR&#160;As&#160;ReportDocument&#160;In&#160;RD&#46;Subreports<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;If&#160;SR&#46;Database&#46;Tables&#46;Count&#160;&#62;&#160;0&#160;Then<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;SR&#46;SetDataSource&#40;DT&#41;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;End&#160;If<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Next</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#39;Setting&#160;recently&#160;created&#160;report&#160;must&#160;be&#160;shown&#160;in&#160;viewer&#46;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Me&#46;crvBill&#46;ReportSource&#160;&#61;&#160;RD<br />
&#160;&#160;&#160;&#160;End&#160;Sub</p>
<p>End&#160;Class</p></div>
<p>Nótese que ahora ya he comentado la línea en que creamos el archivo XML, puesto que sólo necesitamos crearlo una única vez para luego poder generar el origen de datos, pero a partir de aquí no necesitaremos andar creándolo cada vez.</p>
<p>En este código lo que estamos haciendo fundamentalmente es crear un objeto del tipo informe que hemos diseñado en el paso 3, obtener un DataTable con los datos que queremos mostrar (en este caso y tal como tenemos definida la vista de MySQL, queremos mostrar la factura número 4), establecer que el origen de datos del informe será este DataTable y finalmente solicitarle al CrystalReportViewer que nos muestre este informe.</p>
<p>Ejecutamos nuevamente la aplicación y obtenemos la factura que queríamos:</p>
<p style="text-align: center;"><img class="alignnone size-full wp-image-81" title="blog_020_7" src="http://www.albertmata.net/public/uploads/2008/07/blog_020_7.jpg" alt="" width="484" height="416" /></p>
<p>Por supuesto en una factura auténtica faltarían datos fiscales, logotipos, impuestos, condiciones de pago y demás, pero lo que aquí pretendía era únicamente mostrar cómo llevar a cabo el informe en sí mismo.</p>
<p>Con esto queda visto cómo simplemente utilizando un archivo XML podemos crear un informe en VisualBasic.NET. Por supuesto habría que mejorar muchas cosas, por ejemplo optimizar cómo se realiza la conexión con la base de datos (particularmente tengo un clase para llevar a cabo esa serie de cuestiones), también evitar poner la condición WHERE directamente en la vista de MySQL y sí por ejemplo cuando recuperamos el DataTable... en fin, unas cuantas cosas. Pero lo que buscaba con este ejemplo era hacer algo muy minimalista para que quedara claro el funcionamiento.</p>
<div class="subtitle">Actualización.</div>
<p> A raíz de uno de los comentarios he añadido una pequeña segunda parte a este post, en la que se explica <a href="http://www.albertmata.net/2008/10/pasando-parametros-al-informe-en-net-con-crystal-reports/" target="_blank">cómo pasar parámetros desde el formulario hasta el informe</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.albertmata.net/2008/07/informe-en-net-con-crystal-reports-y-base-de-datos-mysql/feed/</wfw:commentRss>
		<slash:comments>39</slash:comments>
		</item>
		<item>
		<title>Copias de seguridad en MySQL con mysqldump.</title>
		<link>http://www.albertmata.net/2008/06/copias-de-seguridad-en-mysql-con-mysqldump/#utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=copias-de-seguridad-en-mysql-con-mysqldump</link>
		<comments>http://www.albertmata.net/2008/06/copias-de-seguridad-en-mysql-con-mysqldump/#comments</comments>
		<pubDate>Thu, 05 Jun 2008 18:54:34 +0000</pubDate>
		<dc:creator>Albert Mata</dc:creator>
				<category><![CDATA[Batch]]></category>
		<category><![CDATA[Herramientas]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[bases de datos]]></category>
		<category><![CDATA[copias de seguridad]]></category>
		<category><![CDATA[gnu-gpl]]></category>
		<category><![CDATA[mysqldump]]></category>

		<guid isPermaLink="false">http://www.albertmata.net/?p=30</guid>
		<description><![CDATA[En los pocos días de vida que tiene este blog es posible que haya mencionado ya que en el proyecto en el que estoy trabajando actualmente estamos utilizando una base de datos MySQL. Sí, lo sé, unas cuantas veces llevo ya... pero es que realmente va muy bien, estamos muy contentos con sus prestaciones hasta [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-full wp-image-31" title="mysqldump" src="http://www.albertmata.net/public/uploads/2008/06/mysqldump.jpg" alt="" width="233" height="118" />En los pocos días de vida que tiene este blog es posible que haya mencionado ya que en el proyecto en el que estoy trabajando actualmente estamos utilizando una base de datos <strong>MySQL</strong>. Sí, lo sé, unas cuantas veces llevo ya... pero es que realmente va muy bien, estamos muy contentos con sus prestaciones hasta la fecha. Se está mostrando rápida y muy fiable... y todo ello con una licencia <strong>GPL</strong>, no lo olvidemos.</p>
<p>Bueno, el caso es que como es evidente, cuando trabajamos con cualquier sistema tenemos que tener muy bien previsto un método decente de copias de seguridad. En el caso de <strong>MySQL</strong> tenemos varias alternativas, pero la que a mí más me ha convencido ha sido la herramienta <strong>mysqldump</strong>. Es realmente sencilla de utilizar y tremendamente funcional. Su funcionamiento exacto con las decenas de opciones que admite se puede encontrar en el propio <a href="http://dev.mysql.com/doc/refman/5.0/en/mysqldump.html" target="_blank">manual de referencia de MySQL</a>. No requiere instalación alguna, simple y llanamente que dispongamos del archivo <strong>mysqldump.exe</strong> que conseguiremos sin problemas en la página oficial de <strong>MySQL</strong> y que si hemos instalado el servidor <strong>MySQL</strong> probablemente tendremos ya en nuestro equipo.</p>
<p>La herramienta <strong>mysqldump</strong> nos genera archivos con extensión <strong>.sql</strong> que incluyen -según hayamos configurado- las instrucciones necesarias para restaurar una base de datos entera -o todas las que tengamos en el servidor <strong>MySQL</strong>-, desde su creación hasta la adición de los datos pasando por la creación de las tablas. Realmente completito. Para una restauración sólo habría que hacer algo así en una línea de comandos (<strong>localhost</strong> o servidor según corresponda):</p>
<div class="code">mysql -u root -p -h localhost &lt; C:\archivo_backup.sql</div>
<p>No obstante lo que quiero explicar hoy es cómo he automatizado estas copias de seguridad que hago con <strong>mysqldump</strong> a través de un archivo <strong>batch</strong>. Expongo código y después lo comento.</p>
<div class="code">&#64;echo&#160;off</p>
<p>set&#160;path&#95;mysqldump&#61;&#34;C&#58;&#92;Program&#160;Files&#92;MySQL&#92;MySQL&#160;Server&#160;5&#46;0&#92;bin&#34;<br />
set&#160;path&#95;backups&#61;&#34;&#92;&#92;99&#46;24&#46;13&#46;29&#92;BBDD&#92;Backups&#34;<br />
set&#160;user&#61;root<br />
set&#160;password&#61;mi&#95;password<br />
set&#160;host&#61;99&#46;24&#46;13&#46;26</p>
<p>if&#160;&#37;time&#58;&#126;0&#44;2&#37;&#160;GEQ&#160;10&#160;goto&#160;&#58;DespuesDeLas10</p>
<p>&#58;AntesDeLas10<br />
&#37;path&#95;mysqldump&#37;&#92;mysqldump&#160;&#45;&#45;user&#61;&#37;user&#37;&#160;&#45;&#45;password&#61;&#37;password&#37;&#160;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#45;h&#160;&#37;host&#37;&#160;&#45;&#45;databases&#160;db&#95;offers&#160;&#45;&#45;single&#45;transaction&#160;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#62;&#160;&#37;path&#95;backups&#37;&#92;backup&#95;&#37;date&#58;&#126;6&#44;4&#37;&#37;date&#58;&#126;3&#44;2&#37;&#37;date&#58;&#126;0&#44;2&#37;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#95;0&#37;time&#58;&#126;1&#44;1&#37;&#37;time&#58;&#126;3&#44;2&#37;&#46;sql<br />
goto&#160;&#58;Salir</p>
<p>&#58;DespuesDeLas10<br />
&#37;path&#95;mysqldump&#37;&#92;mysqldump&#160;&#45;&#45;user&#61;&#37;user&#37;&#160;&#45;&#45;password&#61;&#37;password&#37;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#45;h&#160;&#37;host&#37;&#160;&#45;&#45;databases&#160;db&#95;offers&#160;&#45;&#45;single&#45;transaction&#160;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#62;&#160;&#37;path&#95;backups&#37;&#92;backup&#95;&#37;date&#58;&#126;6&#44;4&#37;&#37;date&#58;&#126;3&#44;2&#37;&#37;date&#58;&#126;0&#44;2&#37;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#95;&#37;time&#58;&#126;0&#44;2&#37;&#37;time&#58;&#126;3&#44;2&#37;&#46;sql<br />
&#58;Salir</p></div>
<p>Antes que nada, comentar que las líneas que comienzan por <strong>%path</strong>... aparecen aquí cortadas por temas de espacio (en píxeles, no en bytes <img src='http://www.albertmata.net/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' />  ) en el blog, pero en realidad deben formar una sola línea que termina con <strong>.sql</strong>. Debe haber un espacio entre <strong>%password%</strong> y <strong>-h</strong> y después otro entre <strong>transaction</strong> y <strong>&gt; %path_</strong>, pero en cambio la última linea va sin espacio (<strong>%date:~0,2%_0%time</strong> va todo seguido, ¿ok?).</p>
<p>Paso a explicarlo. Las primeras cinco líneas después del archiconocido <strong>@echo off</strong> son asignaciones de valores a las variables que después utilizaremos. Es la parte de configuración del archivo <strong>batch</strong>.</p>
<p>1) <strong>path_mysqldump</strong> contiene la ruta del directorio donde se encuentra el archivo <strong>mysqldump.exe</strong>.</p>
<p>2) <strong>path_backups</strong> contiene la ruta del directorio donde se almacenará la copia de seguridad, en este ejemplo he puesto una carpeta en un servidor.</p>
<p>3) <strong>user</strong> es el usuario con el que se ejecutará <strong>mysqldump</strong>. Parece una perogrullada, pero hay que tener en cuenta que debe disponer de permisos suficientes, aunque no es necesario que sea el usuario <strong>root</strong> (de hecho mucho mejor si no lo es, ya que así no quedará en un archivo <strong>batch</strong> visualizable el password del usuario <strong>root</strong>).</p>
<p>4) <strong>password</strong> es... sí, eso.</p>
<p>5) <strong>host</strong> es la máquina donde se encuentra el servidor <strong>MySQL</strong> que queremos backupear. Si es nuestro propio ordenador escribiremos <strong>localhost</strong>. A destacar que el servidor <strong>MySQL</strong> debe estar corriendo en el momento de lanzar el <strong>mysqldump</strong>.</p>
<p>Lo que sigue es ya la ejecución. En mi caso las copias de seguridad las quiero en formato <strong>backup_YYYYMMDD_HHMM</strong> con la fecha y la hora de esta manera, ya que así una simple ordenación alfabética de los archivos lleva a cabo también una ordenación por fechas. Para lograr eso hay que jugar con los <strong>date:~6,4</strong> y similares y además hay que programar dos ramas en función de que sean antes o después de las 10 de la mañana, ya que hasta entonces necesito concatenar un <strong>0</strong> y un <strong>time:~1,1</strong> para la hora con dos dígitos y a partir de las 10 me vale con <strong>time:~0,2</strong>. Podemos prescindir de hacer estas dos alternativas si vamos a lanzar siempre el batch a la misma hora y será más tardía que esas 10am de la <em>madrugada</em>. En cualquier caso para discernir entre si seguir un camino u otro utilizamos el...</p>
<div class="code">if %time:~0,2% GEQ 10 goto <img src='http://www.albertmata.net/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> espuesDeLas10</div>
<p>...donde <strong>GEQ</strong> equivale a lo que en lenguaje de programación normal y corriente diríamos <strong>&gt;=</strong>.</p>
<p>Por último comentar que con esto obtenemos un archivo <strong>.bat</strong> que podemos ejecutar manualmente o programar para que se ejecute periódicamente a nuestro antojo. Por ejemplo con una simple tarea programada de <strong>Windows</strong> si no nos queremos complicar demasiado la vida.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.albertmata.net/2008/06/copias-de-seguridad-en-mysql-con-mysqldump/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>
