Código ejemplo en T-SQL para generar copia de seguridad
Código ejemplo en T-SQL para generar copia de seguridad en una carpeta de todas las bases de datos del servidor actual
DECLARE @name VARCHAR(50) — NOMBRE DE LA BASE DE DATOS
DECLARE @path VARCHAR(256) — RUTA DONDE SE GUARDARN LAS COPIAS DE SEGURIDAD
DECLARE @fileName VARCHAR(256) — NOMBRE DEL ARCHIVO BACKUP
DECLARE @fileDate VARCHAR(20) — UTILIZADO PARA EL NOMBRE DEL ARCHIVO
— RUTA DODNE SE GUARDAN LOS .BAK
SET @path = ‘C:\Backup\‘
SELECT @fileDate = CONVERT(VARCHAR(20),GETDATE(),112)
— CREACION DEL CURSOR CON LOS NOMBRE DE LAS BASES DE DATOS
DECLARE db_cursor CURSOR FOR
SELECT name
FROM master.dbo.sysdatabases
WHERE name NOT IN (‘master’,’model’,’msdb’,’tempdb’)
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @name
WHILE @@FETCH_STATUS = 0
BEGIN
SET @fileName = @path + @name + ‘_’ + @fileDate + ‘.BAK’
— CREACION DE LA COPIA DE SEGURIDAD
BACKUP DATABASE @name TO DISK = @fileName
FETCH NEXT FROM db_cursor INTO @name
END
CLOSE db_cursor
DEALLOCATE db_cursor
Equivalencia de datos de SQL Server y .NET
La siguiente tabla muestra los tipos de datos de Microsoft SQL Server, sus equivalentes en el Common Language Runtime (CLR) de SQL Server en el espacio de nombres System.Data.SqlTypes, y sus equivalentes en el CLR nativo de Microsoft. NET Framework.
SQL Server data type | Type (in System.Data.SqlTypes or Microsoft.SqlServer.Types) |
CLR data type (.NET Framework) |
bigint | SqlInt64 | Int64, Nullable<Int64> |
binary | SqlBytes, SqlBinary | Byte[] |
bit | SqlBoolean | Boolean, Nullable<Boolean> |
char | None | None |
cursor | None | None |
date | SqlDateTime | DateTime, Nullable<DateTime> |
datetime | SqlDateTime | DateTime, Nullable<DateTime> |
datetime2 | None | DateTime, Nullable<DateTime> |
DATETIMEOFFSET | None | DateTimeOffset, Nullable<DateTimeOffset> |
decimal | SqlDecimal | Decimal, Nullable<Decimal> |
float | SqlDouble | Double, Nullable<Double> |
geography | SqlGeography | None |
geometry | SqlGeometry | None |
hierarchyid | SqlHierarchyId | None |
image | None | None |
int | SqlInt32 | Int32, Nullable<Int32> |
money | SqlMoney | Decimal, Nullable<Decimal> |
nchar | SqlChars, SqlString | String, Char[] |
ntext | None | None |
numeric | SqlDecimal | Decimal, Nullable<Decimal> |
nvarchar | SqlChars, SqlString | String, Char[] |
nvarchar(1), nchar(1) | SqlChars, SqlString | Char, String, Char[], Nullable<char> |
real | SqlSingle | Single, Nullable<Single> |
rowversion | None | Byte[] |
smallint | SqlInt16 | Int16, Nullable<Int16> |
smallmoney | SqlMoney | Decimal, Nullable<Decimal> |
sql_variant | None | Object |
table | None | None |
text | None | None |
time | None | TimeSpan, Nullable<TimeSpan> |
timestamp | None | None |
tinyint | SqlByte | Byte, Nullable<Byte> |
uniqueidentifier | SqlGuid | Guid, Nullable<Guid> |
User-defined type(UDT) | None | The same class that is bound to the user-defined type in the same assembly or a dependent assembly. |
varbinary | SqlBytes, SqlBinary | Byte[] |
varbinary(1), binary(1) | SqlBytes, SqlBinary | byte, Byte[], Nullable<byte> |
varchar | None | None |
xml | SqlXml | None |
Google Maps desde VFP
Con Visual FoxPro podemos hacer muchas cosas entre ellas es incorporar un control Explorador Web en un formulario y utilizar código HTML y JavaScript.
Veremos un ejemplo de como incorporar dinámicamente código HTML y JavaScript, que nos permita navegar por Google Maps y poder desplazarnos virtualmente a diversos lugares del mundo.
Creamos un formulario y en INIT copiados el siguiente código
CREATE CURSOR PosGoogleMaps (Descri C(60), Lat N(12,6), Lon N(12,6), Zoom I(4))
INSERT INTO PosGoogleMaps VALUES («Donde vivo actualmente – Santiago de compostela», 42.87532724503904, -8.550581932067871, 17)
INSERT INTO PosGoogleMaps VALUES («Estadio de Matute», -12.068363200515948, -77.02249646186828, 17)
INSERT INTO PosGoogleMaps VALUES («El mejor lugar del mundo – Jauja Perú», -11.775123309556793, -75.49994051456451, 17)
INSERT INTO PosGoogleMaps VALUES («Colegio San José de Jauja», -11.78266440268941, -75.49357295036316, 17)
Thisform.cmbPosGoogleMaps.RowSourceType= 6
Thisform.cmbPosGoogleMaps.Style = 2
Thisform.cmbPosGoogleMaps.RowSource = ‘PosGoogleMaps.Descri’
Thisform.cmbPosGoogleMaps.ListIndex = 1
Adjuntamos 3 objetos a este formulario
1.- Un ComboBox — Name : cmbPosGoogleMaps
2.- Un Commandbutton — Name : cmdPosGoogleMaps
3.- Un Microsoft Web Browser — Name : oInternetExplorer
Copiamos el siguiente código en evento click del commandbutton
TEXT TO lcHtml NOSHOW TEXTMERGE
<html> <head>
<meta http-equiv=»content-type» content=»text/html; charset=utf-8″/>
<title>Google Maps</title>
<script src=»http://maps.google.com/maps?file=api&v=2&key=123» type=»text/javascript»></script>
<script type=»text/javascript»>
//<![CDATA[
function load()
{ if (GBrowserIsCompatible())
{ var map = new GMap2(document.getElementById(«map»),G_SATELLITE_MAP);
map.addControl(new GLargeMapControl());
map.addControl(new GMapTypeControl());
map.addControl(new GOverviewMapControl());
map.setCenter(new GLatLng(<<ALLTRIM(STR(PosGoogleMaps.Lat,12,6))>>,
<<ALLTRIM(STR(PosGoogleMaps.Lon,12,6))>>),<<TRANSFORM(17)>>);
map.setMapType(G_HYBRID_MAP);
} }
//]]> </script> </head>
<body scroll=»no» bgcolor=»#CCCCCC» topmargin=»0″ leftmargin=»0″
onload=»load()» onunload=»GUnload()»>
<div id=»map» style=»width:678px;height:416px»></div>
</body> </html>
ENDTEXT
STRTOFILE(lcHtml,»c:\MiHtml.htm»)
Thisform.oInternetExplorer.Navigate2(FULLPATH(«c:\MiHtml.htm»))
Como visualizar un documento PDF desde VFP
Visualizar documentos pdf con el objeto InternetExplorer desde VFP
PUBLIC oInternetExplorer
m.cArchivo = ‘c:\CI0403324335.pdf’
IF FILE(m.cArchivo) THEN
oInternetExplorer = Createobject(«InternetExplorer.Application»)
oInternetExplorer.Visible = .T.
oInternetExplorer.Navigate2(m.cArchivo)
oInternetExplorer.FullScreen = .T.
temp = INKEY(3)
ObjTexto = ‘Cargando…..’
DO WHILE oInternetExplorer.Busy
WAIT WINDOW ObjTexto TIME(0.1)
ENDDO
ELSE
MESSAGEBOX(‘Archivo no existe …’,0+16,’Error’)
ENDIF
Existe el objeto llamado Microsoft Web Browser el cual puede ser insertado en un formulario como cualquier otro objeto de VFP y desde ahí visualizar los pdf sin necesidad de abrirlos fuera de VFP.
Errores mas frecuentes en VFP
Listado de errores mas frecuentes en VFP
API Code | VFP Code | Visual FoxPro Mensajes de Error |
3 | (none) | Free handle is not found. |
4 | (none) | Use of invalid handle. |
5 | (none) | Use of unallocated handle. |
6 | (none) | Use of transgressed handle. |
7 | (none) | Transgressed node found during compaction. |
8 | (none) | Foreign node found during compaction. |
9 | (none) | Incorrect handle found during compaction. |
10 | (none) | Area size exceeded during compaction. |
11 | (none) | Area cannot contain handle. |
12 | (none) | Operating system memory error. |
13 | (none) | This Beta version has expired. |
14 | (none) | Mismatched pushjmp/popjmp call. |
Estos errores se procesa con normalidad: | ||
120 | 1 | File does not exist. |
173 | 1 | File » does not exist. |
132 | 3 | File is in use. |
135 | 4 | End of file encountered. |
109 | 5 | Record is out of range. |
100 | 6 | Too many files open. |
121 | 7 | File already exists. |
302 | 9 | Data type mismatch. |
Las transacciones y el almacenamiento en búfer VFP
En VFP, para el tiempo que transcurre entre BEGIN y END TRANSACTION la cabecera de la tabla está bloqueado, lo que significa que nadie más puede insertar.
Este es un gran problema de escalabilidad, ya que se tiende a aumentar geométricamente con el número de usuarios concurrentes
Como ejemplo de lo anterior, se debería trabajar de esta manera :
– El usuario introduce datos en el formulario
– Usuario presiona el botón Guardar
– BEGIN TRANSACTION
– Basado en los datos introducidos por el usuario, el sistema de procesos de cambios en varias tablas
– Realizar TABLEUPDATE () s
– Si cualquier TABLEUPDATE () falla, ROLLBACK
– Si todos los TABLEUPDATE () s con éxito, END TRANSACTION
He aquí un ejemplo del uso de las transacciones en las tablas con Buffer
BEGIN TRANSACTION
lActualizo = TABLEUPDATE(.T.,.T.,’Tabla1′) .AND. ;
TABLEUPDATE(.T.,.T.,’Tabla2′)
IF lActualizo THEN
MESSAGEBOX(‘Transacción realizada.’, 0)
END TRANSACTION
ELSE
ROLLBACK
MESSAGEBOX( ‘Uno o más de las tablas no fueron actualizadas. Cancelación de la transacción.’, 0)
TABLEREVERT(.T.,’Tabla1′)
TABLEREVERT(.T.,’Tabla2′)
ENDIF
Recursividad en Mysql – ERROR 1456 (HY000): límite recursivo 0 (según lo establecido por la variable max_sp_recursion_depth)
La primera vez que utilizo la recursividad, no entendía en absoluto lo que está pasando. La mayoría de los compiladores e intérpretes no lo soportan y la gente suele buscar soluciones no recursivas.
Implícitamente, MySQL no permite llamadas recursivas de los procedimientos. Pero esto no es un problema. Es fácil cambiar el max_sp_recursion_depth variable del sistema:
SET @@max_sp_recursion_depth = 254 ;
Un ejemplo de un procedimiento almacenado recursivo.
CREATE DEFINER=`root`@`%` PROCEDURE `spAnulasRegistroDocumentos`(cEstado CHAR(1),nId_Usuario INT,
cMotivo Varchar(100),nId_RegDocumento INT)
BEGIN
DECLARE nId_RegDocumentoCur INT ;
DECLARE l_last_row INT DEFAULT 0 ;
DECLARE nTotal INT DEFAULT 0;
DECLARE cHijos CURSOR FOR SELECT Id_RegDocumento FROM RegistroDocumentos WHERE Id_RegDocumentoRaiz = nId_RegDocumento ;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET l_last_row=1 ;
/* Habilitando para que pueda ejecutar funciones recursivas */
SET @@max_sp_recursion_depth = 254 ;
UPDATE RegistroDocumentos SET Estado = cEstado, Id_UsuarioAnula = nId_Usuario, MotivoAnula = cMotivo, FechaHoraAnula = NOW() WHERE Id_RegDocumento = nId_RegDocumento ;
UPDATE RegistroDocumentos SET Estado = cEstado, Id_UsuarioAnula = nId_Usuario, MotivoAnula = cMotivo, FechaHoraAnula = NOW() WHERE Id_RegDocumentoRaiz = nId_RegDocumento ;
/* Abrimos el cursor para empezar a recorrerlo */
OPEN cHijos;
c1_loop: LOOP
/* Cada registro se le otorga a la variable nId_RegDocumentoCur */
FETCH cHijos INTO nId_RegDocumentoCur;
IF (l_last_row=1) THEN
LEAVE c1_loop;
END IF ;
/* Lógica propia de este procedure */
SELECT COUNT(Id_RegDocumentoRaiz) INTO nTotal FROM RegistroDocumentos WHERE Id_RegDocumentoRaiz = nId_RegDocumento ;
IF nTotal > 0 THEN
CALL spAnulasRegistroDocumentos(cEstado,nId_Usuario,cMotivo,nId_RegDocumentoCur) ;
END IF ;
END LOOP c1_loop;
/* cerramos el cursor */
CLOSE cHijos;
END
Claves foráneas en MySQL
MySQL permite trabajar con distintos tipos de motores de almacenamiento (MyIsam, Memory/HEAP, BDB, InnoDB, etc). Para poder trabajar con las claves foráneas las tablas deben tener asignado el motor InnoDB.
Se debe cumplir ciertas condiciones para poder crear un enlace de este tipo entre distintas tablas:
Las tablas que se enlazan deben tener el mismo motor (InnoDB).
Los campos que se enlazan deben ser del mismo tipo de dato y tamaño.
Los nombres de las claves foráneas deben ser únicos en la base de datos
En la tabla que hace referencia, debe haber un índice donde las columnas de clave extranjera estén listadas en primer lugar, en el mismo orden.
En la siguiente instrucción SQL se modifica la tabla (TBEjemplo11) para añadirle una clave foránea al campo (CampoTBEjemplo11) indicándole a que tabla y campo hace referencia.
ALTER TABLE TBEjemplo11
ADD CONSTRAINT NombreClaveForanea
FOREIGN KEY (CampoTBEjemplo11)
REFERENCES TablaQueReferencia (CampoQueReferencia)
ON DELETE NO ACTION
ON UPDATE NO ACTION ;
Eliminar una clave foranea
ALTER TABLE TBEjemplo11 DROP FOREIGN KEY NombreClaveForanea;
Tipos de tablas en MySQL
- ISAM.- es el formato de almacenaje mas antiguo, y posiblemente pronto desaparecerá. Presentaba limitaciones (los ficheros no eran transportables entre máquinas con distinta arquitectura, no podía manejar ficheros de tablas superiores a 4 gigas). Si aun tienes tablas tipo ISAM, cambialas a MYISAM.
- MYISAM.- es el tipo de tabla por defecto en MySQL desde la versión 3.23. Optimizada para sistemas operativos de 64 bits, permite ficheros de mayor tamaño que ISAM. Además los datos se almacenan en un formato independiente, con lo que se pueden copiar tablas de una máquina a otra de distinta plataforma. Posibilidad de indexar campos BLOB y TEXT
- HEAP.- Crea tablas en memoria. Son temporales y desaparecen cuando el servidor se cierra; a diferencia de una tabla TEMPORARY, que solo puede ser accedida por el usuario que la crea, una tabla HEAP puede ser utilizada por diversos usuarios.
- BDB.- Base de datos Berkeley. TST. Solo en MySQL MAX
- INNODB.- TST, ACID, con posibilidad de commit, rollback, recuperación de errores y bloqueo a nivel de fila.
- MERGE mas que un tipo de tabla es la posibilidad de dividir tablas MYISAM de gran tamaño (solo útil si son verdaderamente de GRAN tamaño) y hacer consultas sobre todas ellas con mayor rapidez. Las tablas deben ser myisam e idénticas en su estructura.
MySQL nos permite variar el tipo de tabla después de que esta fue creada.
TST se refiere a ‘Transactions safe tables’, o tablas para transacciones seguras. A este tipo pertenecen DBD y INNODB.
Las tablas tipo TST son menos rápidas y ocupan mas memoria, pero a cambio ofrecen mayor seguridad frente a fallos durante la consulta.
Las tablas TST están disponibles desde la versión 4.0 de MySQL
Las tablas TST permiten ir introduciendo consultas y finalizar con un COMMIT (que las ejecuta) o ROLLBACK (que ignora los cambios)
En bases de datos se denomina ACID a un conjunto de características necesarias para que una serie de instrucciones puedan ser consideradas como una transacción. Así pues, si un sistema de gestión de bases de datos es ACID compliant quiere decir que el mismo cuenta con las funcionalidades necesarias para que sus transacciones tengan las características ACID.
En concreto ACID es un acrónimo de Atomicity, Consistency, Isolation and Durability: Atomicidad, Consistencia, Aislamiento y Durabilidad en español.
Tipos de datos en Mysql
Para el diseño de nuestras tablas tenemos que especificar el tipo de datos y tamaño que podrá almacenar cada campo.
Una correcta elección debe procurar que la tabla no se quede corta en su capacidad, que destine un tamaño apropiado a la longitud de los datos, y la máxima velocidad de ejecución Básicamente mysql admite dos tipos de datos: números y cadenas de carácteres. Junto a estos dos grandes grupos, se admiten otros tipos de datos especiales: formatos de fecha, etc.
Datos numéricos
En este tipo de campos solo pueden almacenarse números, positivos o negativos, enteros o decimales, en notación hexadecimal, científica o decimal.
Los tipos numéricos tipo integer admiten los atributos SIGNED y UNSIGNED indicando en el primer caso que pueden tener valor negativo, y solo positivo en el segundo.
Los tipos numéricos pueden además usar el atributo ZEROFILL en cuyo caso los números se completaran hasta la máxima anchura disponible con ceros (column num INT(6) zerofill => valor 55 se almacenará como 000055)
BIT o BOOL, para un número entero que puede ser 0 ó 1
TINYINT es un número entero con rango de valores válidos desde -128 a 127. Si se configura como unsigned (sin signo), el rango de valores es de 0 a 255
SMALLINT, para números enteros, con rango desde -32768 a 32767. Si se configura como unsigned, 0 a 65535.
MEDIUMINT para números enteros; el rango de valores va desde -8.388608 a 8388607. Si se configura como unsigned, 0 a 16777215
INT para almacenar números enteros, en un rango de -2147463846 a 2147483647. Si configuramos este dato como unsigned, el rango es 0 a 4294967295
BIGINT número entero con rango de valores desde -9223372036854775808 a 9223372036854775807. Unsigned, desde 0 a 18446744073709551615.
FLOAT (m,d) representa números decimales. Podemos especificar cuantos dígitos (m) pueden utilizarse (término también conocido como ancho de pantalla), y cuantos en la parte decimal (d). Mysql redondeará el decimal para ajustarse a la capacidad.
DOUBLE Número de coma flotante de precisión doble. Es un tipo de datos igual al anterior cuya única diferencia es el rango numérico que abarca
DECIMAL almacena los números como cadenas.
Caracteres o cadenas
CHAR Este tipo se utiliza para almacenar cadenas de longitud fija. Su longitud abarca desde 1 a 255 caracteres.
VARCHAR Al igual que el anterior se utiliza para almacenar cadenas, en el mismo rango de 1-255 caracteres, pero en este caso, de longitud variable. Un campo CHAR ocupará siempre el máximo de longitud que le hallamos asignado, aunque el tamaño del dato sea menor (añadiendo espacios adicionales que sean precisos). Mientras que VARCHAR solo almacena la longitud del dato, permitiendo que el tamaño de la base de datos sea menor. Eso si, el acceso a los datos CHAR es mas rápido que VARCHAR.
No pueden alternarse columnas CHAR y VARCHAR en la misma tabla. Mysql cambiará las columnas CHAR a VARCHAR. También cambia automaticamente a CHAR si usamos VARCHAR con valor de 4 o menos.
TINYTEXT, TINYBLOB para un máximo de 255 caracteres. La diferencia entre la familia de datatypes text y blob es que la primera es para cadenas de texto plano (sin formato) y case-insensitive (sin distinguir mayúsculas o minúsculas) mientras que blob se usa para objetos binarios: cualquier tipo de datos o información, desde un archivo de texto con todo su formato (se diferencia en esto de el tipo Text) hasta imágenes, archivos de sonido o video
TEXT y BLOB se usa para cadenas con un rango de (255 a 65535) caracteres. La diferencia entre ambos es que TEXT permite comparar dentro de su contenido sin distinguir mayúsculas y minúsculas, y BLOB si distingue.
MEDIUMTEXT, MEDIUMBLOB textos de hasta 16777215 caracteres.
LONGTEXT, LONGBLOB, hasta máximo de 4.294.967.295 caracteres
Diferencia de almacenamiento entre los tipos Char y VarChar
Otros tipos de dato
DATE para almacenar fechas. El formato por defecto es YYYY MM DD desde 0000 00 00 a 9999 12 31.
DATETIME Combinación de fecha y hora. El rango de valores va desde el 1 de enero del 1001 a las 0 horas, 0 minutos y 0 segundos al 31 de diciembre del 9999 a las 23 horas, 59 minutos y 59 segundos. El formato de almacenamiento es de año-mes-dia horas:minutos:segundos
TIMESTAMP Combinación de fecha y hora. El rango va desde el 1 de enero de 1970 al año 2037. El formato de almacenamiento depende del tamaño del campo
TIME almacena una hora. El rango de horas va desde -838 horas, 59 minutos y 59 segundos a 838, 59 minutos y 59 segundos. El formato de almacenamiento es de ‘HH:MM:SS’
YEAR almacena un año. El rango de valores permitidos va desde el año 1901 al año 2155. El campo puede tener tamaño dos o tamaño 4 dependiendo de si queremos almacenar el año con dos o cuatro dígitos.
SET un campo que puede contener ninguno, uno ó varios valores de una lista. La lista puede tener un máximo de 64 valores.
ENUM es igual que SET, pero solo se puede almacenar uno de los valores de la lista