Mostrando las entradas con la etiqueta Base de datos. Mostrar todas las entradas
Mostrando las entradas con la etiqueta Base de datos. Mostrar todas las entradas

viernes, 14 de octubre de 2011

Comparar Bases de datos con Visual Studio

Hace algún tiempo hice un post sobre comparar Esquemas de bases de datos, aquí
http://www.neuronasoft.net/2010/08/comparar-bases-de-datos.html
y bueno, casi inmediatamente después leyendo un post en algún lugar descubrí que también Visual Studio tenía una potente herramienta para comparar esquemas de bases de datos. Peor eso no es todo, además nos permite comparar data entre dos bases de datos. Así que es impresionante y ya no necesito la herramienta anterior.
He usado esta herramienta extensivamente y tengo que decirles que es muy buena. Yo uso Visual Studio Ultimate 2010 y les explicaré cómo usar esta herramienta.
Abran el Visual Studio y vayan al menú Data > Schema Compare > New Schema Comparison
Se mostrará una ventana en donde deben ingresar la base de datos origen y la de destino, luego presionen el botón Ok para que se inicie el proceso.
Se mostrará un resumen con las diferencias detectadas entre ambas bases de datos… verá que hay una columna llamada Update Action, en la cual dirá Skip si no encontró diferencias en dicho objeto y dirá Update si es que detectó diferencias.
Entonces, antes de presionar el botón Write Updates, Ud puede cambiar el estado Update a Skip, osea… si no quieres que algún cambio se aplique.
Finalmente, cuando ya revisaste que todo esté ok… puedes presionar el botón Write Updates para que empiece el proceso de actualización de esquema entre bases de datos.
compare_database
Para el proceso de comparar datos entre dos bases de datos, haremos lo siguiente:
Vayan al menú Data >  Data Compare > New Data Comparison…
Se mostrará una ventana que te solicitará los datos de las dos bases de datos a comparar su data. Finalmente, presionas el botón Finish  para que inicie la comparación.
Como resultado obtendrás un resumen muy intuitivo en el que claramente podrás detectar las diferencias de datos entre ambas bases de datos.
data_compare
Eso es todo.
Espero que les sea de utilidad Guiño

viernes, 9 de setiembre de 2011

Generar registros para hacer pruebas en tu base de datos

cross_join Muchas veces necesitamos generar miles o millones de registros para hacer pruebas desde nuestra aplicación.
Una forma simple y rápida de generrar datos que a menudo utilizo es como a continuación explico:
1.- Elijo una tabla existente (cualquier tabla)
2.- Inserto la data de esa columna en la tabla que quiero generar registros, pero el truco es multiplicar miles de veces esa data.
Y cómo genero miles de veces esas filas?
Fácil, hago un CROS JOIN de la misma tabla, así:
(para este ejemplo estoy usando la data de la tabla del sistema sys.objects)
CREATE TABLE #Dummy_Table(
columnINT INT, 
columnDATETIME DATETIME,
columnVARCHAR VARCHAR(100), 
columnBIT BIT)

INSERT INTO #Dummy_Table
SELECT a.object_id, 
a.modify_date, 
b.name, 
c.is_published
FROM       sys.objects a 
CROSS JOIN sys.objects b 
CROSS JOIN sys.objects c 

SELECT * FROM #Dummy_Table

DROP TABLE #Dummy_Table
Explicaré en qué consiste el T-SQL:
1.- Creo una tabla temporal para guardar los registros que generaremos.
2.- Inserto en la tabla temporal la data de algunas columnas de la tabla sys.objects…
al mismo tiempo, por cada CROSS JOIN que hago, la cantidad de filas se multiplicará por si misma… lo cual genera miles o millones (depende de cuantos CROSS JOIN hagas) de registros generados al vuelo al instante.
Espero que les sea de utilidad ;)

jueves, 30 de junio de 2011

SQL SERVER - Excluyendo columnas del GROUP BY

distinct_sql Bueno, el título es medio confuso… pero la idea es intentar recuperar de una tabla de la bd, un conjunto de filas distintas, y que además en su contenido incluyan una fila que no ha sido evaluada en el DISTINCT.
En otras palabras:
algunas veces no queremos que se evalúen todas las columnas… por ejemplo una columna fecha… dado que siempre va a ser distinta, pues la fecha incluye minutos, segundos , milisegundos, etc y entonces siempre cada fila será distinta… por lo que lo más sabio es excluir la fecha de la evaluación del DISTINCT (en tu caso puede ser otro campo, no necesariamente la fecha).
Recordatorio:
Como sabemos el DISTINCT se aplica  a toda la fila… y no a sólo algunas columnas, osea, esto no funciona:
SELECT DISTINCT(columna1), columna2, columna3
Si funcionara sería maravilloso.
Y entonces Uds me preguntan:
Y cómo logramos excluir algunas columnas del DISTINCT?
Ajá, para ello hacemos un truco sencillo:
1.- A la columna que no queremos evaluar la ponemos como argumento de una función SQL, por ejemplo MAX(columna1) o MIN(Columna2)
2.- Dado que estamos usando funciones de agrupamiento, tenemos que usar entonces también la cláusula GROUP BY… y como dice la teoría, en el GROUP BY van las columnas que no han sido incluídas en alguna función de agrupamiento. Ejm:
SELECT userid, documentid, MAX(RegisteredDate)
FROM Table_Document
--Opcional: WHERE userid = @userid
GROUP BY userid, documentid

--Opcional: ORDER BY MAX(RegisteredDate)
Los puntos claves aquí son la función de agrupamiento, lo cual me permite evadir la columna RegisteredDate, y el GROUP BY, el cual es necesario al usar funciones de agrupamiento.
Se habrán dado cuenta que no uso el elemento DISTINCT ... para esta solución (paradójicamente) no la necesito.
Ahora hay otro tema que hay que considerar aquí: cómo hago si las columnas que quiero incluir en mi consulta, pero al mismo tiempo quiero excluir del GROUP BY son de tipo texto? (varchar, nvarchar,,,etc)
Interesante pregunta no?
Suponiendo que tengo una columna de tipo varchar, lo que tendría que hacer es envolver la columna de esta manera: 
MAX(Cast(column2 as varchar(max))) AS Column2
Y con eso se soluciona el asunto.
Espero que les sea de utilidad ;)

lunes, 13 de junio de 2011

SQL SERVER - Ordenar datos de una columna, poniendo NULL al final

Digamos que se da el caso que tenemos una lista de tareas por realizar, algunas de las cuales no tienen fecha definida de culminación, por lo tanto se han guardado en la base de datos con fecha NULL.
Luego, imaginemos que tenemos que mostrar estas tareas en una grilla… si nosotros hacemos una consulta para obtener todas las tareas, y las ordenamos por fecha de culminación… veremos desagradablemente que las tareas con fecha NULL se mostrarán primero que las demás… lo cual nos hace recordar que un NULL siempre es menor que un dato no NULL… ejemplo:
SELECT [taskid],[userid],[title],[progress],[duedate]

FROM [dbo].[tm_task]

ORDER BY [duedate] ASC
sort_order_null_end 
Y lógicamente no es lo que quisieramos obtener como resultado:

si hay tareas sin fecha definida, estas deberían ir al último (puede ser que tú pienses lo contrario, pero no discutamos).

Entonces, para lograr que las tareas con fecha NULL vayan al final, hacemos uso de COALESCE, elcual nos permite utilizar otro valor si es que el dato es NULL, algo así:

SELECT [taskid],[userid],[title],[progress]
COALESCE([duedate], aqui_pones_una_fecha_con_un_valor_alto) AS [duedate]

FROM [dbo].[tm_task]

ORDER BY [duedate] ASC

Simple no es cierto?

Obviamente no sólo funciona para fechas, también lo puedes usar para números, cadenas, etc.

Espero que les sea de utilidad ;)

viernes, 13 de agosto de 2010

Comparar bases de datos

database_compare Desde hace varios años uso este producto y quiero compartirlo con todos uds (muchos ya lo conocerán), dado que es muy útil… y sobre todo gratuito. Obviamente hay otros más sofisticados, pero éste es gratuito).
Lo que hace este producto es comparar la estructura de dos bases de datos, las cuales pueden estar en diferentes servidores o en local…
luego de ello arroja un reporte muy simple y comprensible en el que muestra todos los objetos de la base de datos (tablas, procedimientos almacenados, funciones, ..etc) e indica si son iguales o diferentes… además también detecta qué objetos faltan en comparación al otro servidor.
Ojo, compara estructuras ah? no compara datos.
Funciona para SQL SERVER, MYSQL y ACCESS.
Este es el enlace: http://www.starinix.com/sqlcompare02.htm

Actualización: Luego escribí otro post acerca del mismo tema, por favor léanlo desde aquí
http://www.neuronasoft.net/2011/10/comparar-bases-de-datos-con-visual.html

Espero que les sea de utilidad ;)

lunes, 12 de julio de 2010

Caso de Modelado de datos

modelado_de_datos Vamos a presentar un caso muy sencillo de modelamiento de datos, el cual tenemos que resolver...

el caso es el siguiente:

Tenemos USUARIOS responsables de PROYECTOS, siempre habrá un solo responsable por proyecto… luego de eso se crea el EQUIPO DE PROYECTO ( 1 ó varios usuarios ), luego a los miembros de cada equipo se les asignan TAREAS ( 0, 1 ó varias ), inclusive el responsable del proyecto puede realizar tareas.

Les propongo algo, presenten su solución en una imagen... súbanlo a flicker, picassa u otro sitio web que nos permita visualizarlo libremente… y compartan el enlace a través de un comentario.

No es necesario que usen un software especial, inclusive pueden usar paint.

Lo importante aquí es ver las tablas que crean y las relaciones que se establecen entre ellas.

Luego de eso vamos a comparar las soluciones propuestas, para finalmente definir cuál es la mejor solución.

Saludos ;)

sábado, 6 de marzo de 2010

Listado de paises script SQL SERVER

Les dejo el script con el listado de todos los países en español.
Dado que un blog también es un repositorio de información: a mí también me conviene publicarlo para tenerlo siempre a la mano.
/*==================================*/
/* Table: FPG_PAIS                                     */
/*=================================*/

create table FPG_PAIS (
   PAISID              int                  identity,
   ISOnum               smallint             null,
   ISO2                 char(2)              null,
   ISO3                 char(3)              null,
   TITULO               varchar(150)         not null,
   constraint PK_FPG_PAIS primary key (PAISID)
)
go

SET IDENTITY_INSERT fpg_pais ON 
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (1, 4, 'AF', 'AFG', 'Afganistán');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (2, 248, 'AX', 'ALA', 'Islas Gland');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (3, 8, 'AL', 'ALB', 'Albania');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (4, 276, 'DE', 'DEU', 'Alemania');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (5, 20, 'AD', 'AND', 'Andorra');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (6, 24, 'AO', 'AGO', 'Angola');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (7, 660, 'AI', 'AIA', 'Anguilla');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (8, 10, 'AQ', 'ATA', 'Antártida');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (9, 28, 'AG', 'ATG', 'Antigua y Barbuda');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (10, 530, 'AN', 'ANT', 'Antillas Holandesas');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (11, 682, 'SA', 'SAU', 'Arabia Saudí');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (12, 12, 'DZ', 'DZA', 'Argelia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (13, 32, 'AR', 'ARG', 'Argentina');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (14, 51, 'AM', 'ARM', 'Armenia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (15, 533, 'AW', 'ABW', 'Aruba');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (16, 36, 'AU', 'AUS', 'Australia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (17, 40, 'AT', 'AUT', 'Austria');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (18, 31, 'AZ', 'AZE', 'Azerbaiyán');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (19, 44, 'BS', 'BHS', 'Bahamas');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (20, 48, 'BH', 'BHR', 'Bahréin');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (21, 50, 'BD', 'BGD', 'Bangladesh');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (22, 52, 'BB', 'BRB', 'Barbados');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (23, 112, 'BY', 'BLR', 'Bielorrusia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (24, 56, 'BE', 'BEL', 'Bélgica');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (25, 84, 'BZ', 'BLZ', 'Belice');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (26, 204, 'BJ', 'BEN', 'Benin');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (27, 60, 'BM', 'BMU', 'Bermudas');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (28, 64, 'BT', 'BTN', 'Bhután');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (29, 68, 'BO', 'BOL', 'Bolivia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (30, 70, 'BA', 'BIH', 'Bosnia y Herzegovina');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (31, 72, 'BW', 'BWA', 'Botsuana');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (32, 74, 'BV', 'BVT', 'Isla Bouvet');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (33, 76, 'BR', 'BRA', 'Brasil');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (34, 96, 'BN', 'BRN', 'Brunéi');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (35, 100, 'BG', 'BGR', 'Bulgaria');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (36, 854, 'BF', 'BFA', 'Burkina Faso');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (37, 108, 'BI', 'BDI', 'Burundi');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (38, 132, 'CV', 'CPV', 'Cabo Verde');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (39, 136, 'KY', 'CYM', 'Islas Caimán');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (40, 116, 'KH', 'KHM', 'Camboya');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (41, 120, 'CM', 'CMR', 'Camerún');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (42, 124, 'CA', 'CAN', 'Canadá');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (43, 140, 'CF', 'CAF', 'República Centroafricana');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (44, 148, 'TD', 'TCD', 'Chad');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (45, 203, 'CZ', 'CZE', 'República Checa');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (46, 152, 'CL', 'CHL', 'Chile');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (47, 156, 'CN', 'CHN', 'China');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (48, 196, 'CY', 'CYP', 'Chipre');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (49, 162, 'CX', 'CXR', 'Isla de Navidad');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (50, 336, 'VA', 'VAT', 'Ciudad del Vaticano');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (51, 166, 'CC', 'CCK', 'Islas Cocos');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (52, 170, 'CO', 'COL', 'Colombia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (53, 174, 'KM', 'COM', 'Comoras');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (54, 180, 'CD', 'COD', 'República Democrática del Congo');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (55, 178, 'CG', 'COG', 'Congo');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (56, 184, 'CK', 'COK', 'Islas Cook');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (57, 408, 'KP', 'PRK', 'Corea del Norte');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (58, 410, 'KR', 'KOR', 'Corea del Sur');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (59, 384, 'CI', 'CIV', 'Costa de Marfil');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (60, 188, 'CR', 'CRI', 'Costa Rica');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (61, 191, 'HR', 'HRV', 'Croacia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (62, 192, 'CU', 'CUB', 'Cuba');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (63, 208, 'DK', 'DNK', 'Dinamarca');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (64, 212, 'DM', 'DMA', 'Dominica');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (65, 214, 'DO', 'DOM', 'República Dominicana');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (66, 218, 'EC', 'ECU', 'Ecuador');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (67, 818, 'EG', 'EGY', 'Egipto');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (68, 222, 'SV', 'SLV', 'El Salvador');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (69, 784, 'AE', 'ARE', 'Emiratos Árabes Unidos');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (70, 232, 'ER', 'ERI', 'Eritrea');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (71, 703, 'SK', 'SVK', 'Eslovaquia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (72, 705, 'SI', 'SVN', 'Eslovenia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (73, 724, 'ES', 'ESP', 'España');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (74, 581, 'UM', 'UMI', 'Islas ultramarinas de Estados Unidos');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (75, 840, 'US', 'USA', 'Estados Unidos');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (76, 233, 'EE', 'EST', 'Estonia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (77, 231, 'ET', 'ETH', 'Etiopía');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (78, 234, 'FO', 'FRO', 'Islas Feroe');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (79, 608, 'PH', 'PHL', 'Filipinas');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (80, 246, 'FI', 'FIN', 'Finlandia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (81, 242, 'FJ', 'FJI', 'Fiyi');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (82, 250, 'FR', 'FRA', 'Francia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (83, 266, 'GA', 'GAB', 'Gabón');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (84, 270, 'GM', 'GMB', 'Gambia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (85, 268, 'GE', 'GEO', 'Georgia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (86, 239, 'GS', 'SGS', 'Islas Georgias del Sur y Sandwich del Sur');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (87, 288, 'GH', 'GHA', 'Ghana');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (88, 292, 'GI', 'GIB', 'Gibraltar');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (89, 308, 'GD', 'GRD', 'Granada');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (90, 300, 'GR', 'GRC', 'Grecia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (91, 304, 'GL', 'GRL', 'Groenlandia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (92, 312, 'GP', 'GLP', 'Guadalupe');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (93, 316, 'GU', 'GUM', 'Guam');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (94, 320, 'GT', 'GTM', 'Guatemala');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (95, 254, 'GF', 'GUF', 'Guayana Francesa');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (96, 324, 'GN', 'GIN', 'Guinea');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (97, 226, 'GQ', 'GNQ', 'Guinea Ecuatorial');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (98, 624, 'GW', 'GNB', 'Guinea-Bissau');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (99, 328, 'GY', 'GUY', 'Guyana');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (100, 332, 'HT', 'HTI', 'Haití');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (101, 334, 'HM', 'HMD', 'Islas Heard y McDonald');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (102, 340, 'HN', 'HND', 'Honduras');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (103, 344, 'HK', 'HKG', 'Hong Kong');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (104, 348, 'HU', 'HUN', 'Hungría');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (105, 356, 'IN', 'IND', 'India');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (106, 360, 'ID', 'IDN', 'Indonesia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (107, 364, 'IR', 'IRN', 'Irán');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (108, 368, 'IQ', 'IRQ', 'Iraq');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (109, 372, 'IE', 'IRL', 'Irlanda');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (110, 352, 'IS', 'ISL', 'Islandia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (111, 376, 'IL', 'ISR', 'Israel');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (112, 380, 'IT', 'ITA', 'Italia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (113, 388, 'JM', 'JAM', 'Jamaica');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (114, 392, 'JP', 'JPN', 'Japón');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (115, 400, 'JO', 'JOR', 'Jordania');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (116, 398, 'KZ', 'KAZ', 'Kazajstán');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (117, 404, 'KE', 'KEN', 'Kenia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (118, 417, 'KG', 'KGZ', 'Kirguistán');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (119, 296, 'KI', 'KIR', 'Kiribati');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (120, 414, 'KW', 'KWT', 'Kuwait');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (121, 418, 'LA', 'LAO', 'Laos');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (122, 426, 'LS', 'LSO', 'Lesotho');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (123, 428, 'LV', 'LVA', 'Letonia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (124, 422, 'LB', 'LBN', 'Líbano');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (125, 430, 'LR', 'LBR', 'Liberia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (126, 434, 'LY', 'LBY', 'Libia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (127, 438, 'LI', 'LIE', 'Liechtenstein');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (128, 440, 'LT', 'LTU', 'Lituania');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (129, 442, 'LU', 'LUX', 'Luxemburgo');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (130, 446, 'MO', 'MAC', 'Macao');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (131, 807, 'MK', 'MKD', 'ARY Macedonia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (132, 450, 'MG', 'MDG', 'Madagascar');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (133, 458, 'MY', 'MYS', 'Malasia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (134, 454, 'MW', 'MWI', 'Malawi');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (135, 462, 'MV', 'MDV', 'Maldivas');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (136, 466, 'ML', 'MLI', 'Malí');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (137, 470, 'MT', 'MLT', 'Malta');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (138, 238, 'FK', 'FLK', 'Islas Malvinas');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (139, 580, 'MP', 'MNP', 'Islas Marianas del Norte');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (140, 504, 'MA', 'MAR', 'Marruecos');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (141, 584, 'MH', 'MHL', 'Islas Marshall');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (142, 474, 'MQ', 'MTQ', 'Martinica');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (143, 480, 'MU', 'MUS', 'Mauricio');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (144, 478, 'MR', 'MRT', 'Mauritania');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (145, 175, 'YT', 'MYT', 'Mayotte');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (146, 484, 'MX', 'MEX', 'México');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (147, 583, 'FM', 'FSM', 'Micronesia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (148, 498, 'MD', 'MDA', 'Moldavia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (149, 492, 'MC', 'MCO', 'Mónaco');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (150, 496, 'MN', 'MNG', 'Mongolia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (151, 500, 'MS', 'MSR', 'Montserrat');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (152, 508, 'MZ', 'MOZ', 'Mozambique');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (153, 104, 'MM', 'MMR', 'Myanmar');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (154, 516, 'NA', 'NAM', 'Namibia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (155, 520, 'NR', 'NRU', 'Nauru');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (156, 524, 'NP', 'NPL', 'Nepal');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (157, 558, 'NI', 'NIC', 'Nicaragua');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (158, 562, 'NE', 'NER', 'Níger');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (159, 566, 'NG', 'NGA', 'Nigeria');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (160, 570, 'NU', 'NIU', 'Niue');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (161, 574, 'NF', 'NFK', 'Isla Norfolk');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (162, 578, 'NO', 'NOR', 'Noruega');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (163, 540, 'NC', 'NCL', 'Nueva Caledonia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (164, 554, 'NZ', 'NZL', 'Nueva Zelanda');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (165, 512, 'OM', 'OMN', 'Omán');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (166, 528, 'NL', 'NLD', 'Países Bajos');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (167, 586, 'PK', 'PAK', 'Pakistán');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (168, 585, 'PW', 'PLW', 'Palau');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (169, 275, 'PS', 'PSE', 'Palestina');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (170, 591, 'PA', 'PAN', 'Panamá');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (171, 598, 'PG', 'PNG', 'Papúa Nueva Guinea');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (172, 600, 'PY', 'PRY', 'Paraguay');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (173, 604, 'PE', 'PER', 'Perú');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (174, 612, 'PN', 'PCN', 'Islas Pitcairn');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (175, 258, 'PF', 'PYF', 'Polinesia Francesa');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (176, 616, 'PL', 'POL', 'Polonia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (177, 620, 'PT', 'PRT', 'Portugal');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (178, 630, 'PR', 'PRI', 'Puerto Rico');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (179, 634, 'QA', 'QAT', 'Qatar');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (180, 826, 'GB', 'GBR', 'Reino Unido');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (181, 638, 'RE', 'REU', 'Reunión');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (182, 646, 'RW', 'RWA', 'Ruanda');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (183, 642, 'RO', 'ROU', 'Rumania');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (184, 643, 'RU', 'RUS', 'Rusia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (185, 732, 'EH', 'ESH', 'Sahara Occidental');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (186, 90, 'SB', 'SLB', 'Islas Salomón');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (187, 882, 'WS', 'WSM', 'Samoa');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (188, 16, 'AS', 'ASM', 'Samoa Americana');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (189, 659, 'KN', 'KNA', 'San Cristóbal y Nevis');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (190, 674, 'SM', 'SMR', 'San Marino');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (191, 666, 'PM', 'SPM', 'San Pedro y Miquelón');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (192, 670, 'VC', 'VCT', 'San Vicente y las Granadinas');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (193, 654, 'SH', 'SHN', 'Santa Helena');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (194, 662, 'LC', 'LCA', 'Santa Lucía');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (195, 678, 'ST', 'STP', 'Santo Tomé y Príncipe');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (196, 686, 'SN', 'SEN', 'Senegal');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (197, 891, 'CS', 'SCG', 'Serbia y Montenegro');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (198, 690, 'SC', 'SYC', 'Seychelles');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (199, 694, 'SL', 'SLE', 'Sierra Leona');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (200, 702, 'SG', 'SGP', 'Singapur');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (201, 760, 'SY', 'SYR', 'Siria');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (202, 706, 'SO', 'SOM', 'Somalia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (203, 144, 'LK', 'LKA', 'Sri Lanka');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (204, 748, 'SZ', 'SWZ', 'Suazilandia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (205, 710, 'ZA', 'ZAF', 'Sudáfrica');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (206, 736, 'SD', 'SDN', 'Sudán');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (207, 752, 'SE', 'SWE', 'Suecia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (208, 756, 'CH', 'CHE', 'Suiza');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (209, 740, 'SR', 'SUR', 'Surinam');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (210, 744, 'SJ', 'SJM', 'Svalbard y Jan Mayen');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (211, 764, 'TH', 'THA', 'Tailandia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (212, 158, 'TW', 'TWN', 'Taiwán');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (213, 834, 'TZ', 'TZA', 'Tanzania');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (214, 762, 'TJ', 'TJK', 'Tayikistán');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (215, 86, 'IO', 'IOT', 'Territorio Británico del Océano Índico');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (216, 260, 'TF', 'ATF', 'Territorios Australes Franceses');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (217, 626, 'TL', 'TLS', 'Timor Oriental');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (218, 768, 'TG', 'TGO', 'Togo');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (219, 772, 'TK', 'TKL', 'Tokelau');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (220, 776, 'TO', 'TON', 'Tonga');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (221, 780, 'TT', 'TTO', 'Trinidad y Tobago');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (222, 788, 'TN', 'TUN', 'Túnez');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (223, 796, 'TC', 'TCA', 'Islas Turcas y Caicos');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (224, 795, 'TM', 'TKM', 'Turkmenistán');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (225, 792, 'TR', 'TUR', 'Turquía');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (226, 798, 'TV', 'TUV', 'Tuvalu');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (227, 804, 'UA', 'UKR', 'Ucrania');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (228, 800, 'UG', 'UGA', 'Uganda');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (229, 858, 'UY', 'URY', 'Uruguay');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (230, 860, 'UZ', 'UZB', 'Uzbekistán');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (231, 548, 'VU', 'VUT', 'Vanuatu');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (232, 862, 'VE', 'VEN', 'Venezuela');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (233, 704, 'VN', 'VNM', 'Vietnam');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (234, 92, 'VG', 'VGB', 'Islas Vírgenes Británicas');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (235, 850, 'VI', 'VIR', 'Islas Vírgenes de los Estados Unidos');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (236, 876, 'WF', 'WLF', 'Wallis y Futuna');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (237, 887, 'YE', 'YEM', 'Yemen');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (238, 262, 'DJ', 'DJI', 'Yibuti');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (239, 894, 'ZM', 'ZMB', 'Zambia');
INSERT INTO fpg_pais(paisid, ISOnum, ISO2, ISO3, titulo) VALUES (240, 716, 'ZW', 'ZWE', 'Zimbabue');

SET IDENTITY_INSERT fpg_pais OFF

Sé que nos será de utilidad ;)

sábado, 27 de febrero de 2010

SQL SERVER – Llamar Funciones de la base de datos directamente

udfs Hasta que me lo preguntaron, me dijeron: Yo sé que las funciones definidas por el usuario (en adelante UDF) han sido creadas para encapsular funcionalidades y para que al ser llamadas desde un procedimiento almacenado (en adelante SP), simplifiquen el armado y entendimiento de las sentencias t-sql que finalmente terminan siendo los SP.
Pero, pero, pero (continuaban…):Se puede llamar una UDF directamente? osea, sin necesidad de usarla desde un SP?
La razón que argumentaban era que querían testear las funciones y se veían en la engorrosa necesidad de meterla en un SP cada vez que querían testear la función.
Mi respuesta fue: hmmm… de poder se puede, y sería así:
1.- Creen una UDF, digamos algo como esto
CREATE FUNCTION [dbo].[risk_user_GetDescription]
(@userid int)
RETURNS varchar(150)

AS
BEGIN
    RETURN
    (
    SELECT [FirstName] + ' ' + [LastName])

    FROM [dbo].[risk_user]
    WHERE [userid] = @userid
    )
END

Esta UDF es muy senclla: simplemente devuelve el nombre de un usuario, recibiendo como parámetro el ID de usuario.
2.- Ahora, cómo lo llamo directamente?
Si están en el SQL SERVER Management Studio, simplemente presionen el botón Nueva consulta y tipeen
SELECT [dbo].[risk_user_GetDescription](1)
Luego presionen F5 para que se ejecute la consulta. Verán que se originan resultados.
Si se dan cuenta, es muy simple: sólo añadí un SELECT antes del nombre de la UDF y al final simplemente le pasé el parámetro que requiere la función.
Si quisieras hacer lo mismo ( llamar una UDF directamente ) desde el Visual Studio, también se puede. Simplemente harías esto:
Dim connection As New SqlConnection("server=.\SQLEXPRESS;database=midatabase;uid=sa;pwd=")

Dim command As New SqlCommand("SELECT [dbo].[risk_user_GetDescription](1)", connection)
command.CommandType = CommandType.Text

connection.Open()
Dim NombreDeUsuario As String = DirectCast(command.ExecuteScalar(), String)
connection.Close()

Lo que hace este código es llamar a la UDF directamente, y la variable NombreDeUsuario es la que recibe el resultado.
Yo he hecho el ejemplo con una función que devuelve un string, les dejo como tarea a Uds el que traten con funciones que devuelven otros tipos de datos.
;)

viernes, 12 de febrero de 2010

SQL SERVER – Generar script INSERT con los datos de las tablas SQL

select-insert A veces queremos exportar los datos de algunas tablas hacia archivos planos… y no siempre tenemos a la mano alguna herramienta para realizar esta tarea.
Y desde el SQL Management Studio no tenemos la opción (al menos no la he visto en SQL SERVER 2005) de exportar los datos como un script. Me refiero a hacerlo de manera simple.
Si haces click derecho sobre una de tus tablas verás que hay distintas opciones para generar scripts para lo que quieras, menos lo que realmente queremos: exportar los datos como un script.
Pero eso no debería ser problema para nosotros, vamos a ver cómo lo podemos hacer…
1.- Estando en el Management Studio y dentro de una base de datos, hacemos click en New Query (Nueva consulta) y suponiendo que tenemos una tabla que se llama emotiaudio_distrito
la cual tiene tres campos llamados distritoid, title y costoreparto…  de tipos int, varchar y decimal respectivamente… tipeamos lo sgte:
PRINT 'SET IDENTITY_INSERT emotiaudio_distrito ON'  --Use esta línea sólo si la tabla incluye una columna identity
SET NOCOUNT ON
SELECT     'INSERT INTO emotiaudio_distrito(distritoid,
                                title, costoreparto)

           VALUES(' +
            cast(distritoid as varchar) + ',''' +
            title + ''',' +
            cast(costoreparto as varchar) +
           ') '
FROM         emotiaudio_distrito
SET NOCOUNT OFF
PRINT 'SET IDENTITY_INSERT emotiaudio_distrito OFF'  --Use esta línea sólo si la tabla incluye una columna identity

Puede darse el caso en que uno de los datos devuelva NULL, en ese caso el resultado de toda esa fila será simplemente NULL… porque:
NULL + no null = NULL… lo cual no queremos. Por ejemplo, cuando una tabla incluye una columna parentID, es posible que no todos tengan parentID … no es cierto? por eso es mejor agregarle una pequeña modificación:
PRINT 'SET IDENTITY_INSERT fpg_ubigeo ON'  --Use esta línea sólo si la tabla incluye una columna identity
SET NOCOUNT ON
SELECT     'INSERT INTO fpg_ubigeo(ubigeoid, parentid, ubigeotypeid, titulo)
           VALUES('
+
            cast(locationid as varchar) + ',' +
            CASE WHEN cast(ISNULL(parentid, 0) as varchar) = '0' THEN 'NULL' ELSE cast(parentid as varchar) END  + ',' +
            cast(locationtypeid as varchar) + ',''' +
            title +
           ''') '
FROM         risk_location
SET NOCOUNT OFF
PRINT 'SET IDENTITY_INSERT fpg_ubigeo OFF'  --Use esta línea sólo si la tabla incluye una columna identity
Y luego presionamos F5 para que se ejecute la consulta… eeeeeeespera, debiste antes de presionar F5 ir al menú Consultas… > Resultados a… > Resultados a Texto… de esa manera los datos se muestran en un formato plano, para poder ser copiados y guardarlos en un block de notas.
result
Pero… y qué estoy haciendo? simplemente estoy armando un string de los datos… osea, concateno “INSERT INTO TU_TABLA…” con los datos.
Recuerda que si incluyes campo de tipo integer o decimal debes castearlos a varchar y también nota que no lo concateno con tres comillas simples como lo hago cuando es un string, sólo uso una comilla simple.
Para terminar, diré que este artificio nos sirve hasta SQL SERVER 2005, porque ya el SQL SERVER 2008 brinda la opción de generar el script INSERT de los datos.
;)

martes, 26 de enero de 2010

SQL SERVER - Obtener texto de procedimientos almacenados recientemente modificados

sqlquery Este post es la continuación de este otro: Obtener fecha de modificacion de procedimientos almacenados, …
Como les decía en el post anterior, la idea finalmente es recuperar el texto o código de los objetos recientemente modificados… si se fijan en el código que a continuación pego, estoy haciendo la consulta a partir de una fecha dada… en mi caso, desde el 21/enero/2010:
YEAR(modify_date)=2010 AND month(modify_date)=1 AND DAY(modify_date)>20
Vean el código T-SQL:
set nocount on
declare @ProcName nvarchar(100)
declare @ProcSortOrder int
declare @CursorProcList CURSOR

declare @StoredProcs TABLE
(
SortOrder int,
ProcedureName varchar(100),
ProcedureCode varchar(7500)
)

Insert Into @StoredProcs
SELECT 0 AS SortOrder, name, SC.Text
FROM sys.objects SO INNER JOIN SysComments SC
ON SO.OBJECT_ID = SC.ID
WHERE type = 'P'
AND YEAR(modify_date)=2010 AND month(modify_date)=1 AND DAY(modify_date)>20
ORDER BY modify_date DESC
set nocount off

SET @CursorProcList = CURSOR FAST_FORWARD
FOR
select ProcedureName,
SortOrder = (select count(*)
from @StoredProcs B
WHERE (A.ProcedureName <> B.ProcedureName)
and (REPLACE(UPPER(B.ProcedureCode),B.ProcedureName,'')
LIKE '%' + upper(A.ProcedureName) + '%')
)
from @StoredProcs A
order by SortOrder Desc
OPEN @CursorProcList
FETCH NEXT FROM @CursorProcList
INTO @ProcName,@ProcSortOrder

WHILE @@FETCH_STATUS = 0
BEGIN

PRINT 'if exists (select * from dbo.sysobjects '
PRINT ' where id = object_id(N' + char(39) + '[dbo].[' + @ProcName + ']' + char(39) + ')'
PRINT ' and OBJECTPROPERTY(id, N' + char(39) + 'IsProcedure' + char(39) + ') = 1) '
PRINT ' drop procedure ' + @ProcName
PRINT ' GO '
PRINT ' SET QUOTED_IDENTIFIER OFF '
PRINT ' GO '
PRINT ' SET ANSI_NULLS OFF '
PRINT ' GO'
exec sp_helptext @ProcName
PRINT ' GO '
PRINT ' SET QUOTED_IDENTIFIER OFF '
PRINT ' GO '
PRINT ' SET ANSI_NULLS ON '
PRINT ' GO '

FETCH NEXT FROM @CursorProcList
INTO @ProcName,@ProcSortOrder
END

CLOSE @CursorProcList
DEALLOCATE @CursorProcList

Antes de ejecutar este código, debes ir al Menú Query (en español supongo que será Consultas) y seleccionar Resultados a… > Resultados a Texto… como la imagen que muestro al inicio de este post.
Nota: No me voy a dar todo el crédito por este código, en realidad es un código cogido del maestro Robbe D. Morris, el cual me permitía recuperar todos los procedimientos almacenados de una base de datos… pero no listaba ordenados por fecha de modificación, porque consultaba de otras tablas del sistema… el valor agregado que le di es cambiar las tablas de consulta que hacia, para que me liste ordenados por fecha de modificación y además me permita recuperar desde una fecha determinada.
;)

martes, 12 de enero de 2010

SQL SERVER – Obtener fecha de modificacion de procedimientos almacenados, funciones y tablas

sqltables Tengo un retazo de código que uso desde hace algún tiempo y quiero compartirlo.
Lo que permite hacer es listar los objetos de la base de datos, pueden ser procedimientos almacenados, funciones definidas por el usuario, tablas de usuario, etc.
Alguien preguntará:
Para qué es útil ese trozo de código?
Bueno pues, en el desarrollo de software, nuevas versiones, etc… se van modificando también los objetos de la base de datos, primero en el servidor de pruebas, y luego hay que actualizar la base de datos en el servidor de producción… y cuando la base de datos tiene muchos objetos… resulta molesto y se pierde mucho tiempo reemplazando todo de nuevo… entonces, esta solución permite listar los objetos de la base de datos ordenados por fecha de modificación.
Vean el T-SQL:
--stored procedures
SELECT name, modify_date FROM sys.objects
WHERE type = 'P' AND name NOT LIKE 'sp_%'
ORDER BY modify_date DESC


--tables
SELECT name, modify_date FROM sys.objects
WHERE type = 'U'
ORDER BY modify_date DESC


--Functions
SELECT name, modify_date FROM sys.objects
WHERE type = 'FN'
ORDER BY modify_date DESC

En realidad pueden consultar por cualquier tipo de objeto, basta que quiten o cambien el WHERE, ejemplo:
SELECT name, modify_date FROM sys.objects
WHERE type = 'U'
ORDER BY modify_date DESC

y pongan el tipo que necesitan. Más información en MSDN: sys.objects (Transact-SQL).

A partir de SQL 2008 este T-SQL ya no es necesario, porque el listado de procedimientos y tablas ya incluyen una columna llamada ÚLTIMA FECHA DE EDICIÓN.

Pero alguien se preguntará: Y para qué quiero la lista de objetos modificados si no obtengo automáticamente el código de esos objetos?
Porque la idea es finalmente obtener el código de los objetos de la base de datos modificados recientemente… Y eso lo veremos en el post que he titulado Obtener texto de procedimientos almacenados recientemente modificados.
;)

jueves, 31 de enero de 2008

Ponerle alias al servidor SQL SERVER - II

Ahora, vamos a crear el alias de servidor ... pero en SQL Server 2000.
1.-Vamos a Inicio > Programas > Microsoft SQL Server > Herramienta de red de cliente,
Aparecerá una caja de diálogo con varias pestañas, de las cuales elegimos la que dice Alias.
2.-Luego de eso, presionamos el botón añadir... lo cual nos mostrará otra caja de diálogo:
Del lado izquierdo de esa caja de diálogo, seleccionamos la opción que dice TCP/IP y después le ingresamos los demás valores necesarios y... listo!!!

ya tenemos nuestro alias de servidor en SQL Server 2000.

viernes, 28 de diciembre de 2007

Ponerle alias al servidor SQL SERVER - I


Voy a poner un caso:
Digamos que tenemos varias aplicaciones que recuperan data de algún servidor SQL SERVER remoto.
Por lo tanto, en nuestras aplicaciones deberíamos tener cadenas de conexión a la base de datos de ese servidor remoto... cierto?
Ahora digamos que la cadena de conexión fuera algo así:
server=111.333.444.555;database=MyDatabase;uid=MyUser;pwd=MyPassword;
Qué pasaría si nos cambiamos de servidor de base de datos? osea, contratamos a otro proveedor?
Pasaría que tendríamos que modificar la cadena de conexión en todas las aplicaciones que usaban ese servidor... cierto?
No sé qué piensen uds, pero a mi no me agrada la idea de estar haciendo eso.
Hay una salida? sí: ponerle un alias a esa instancia de servidor.
Pero, qué es un alias de servidor SQL SERVER y cómo se hace?
Un alias de servidor es un mecanismo que consiste en ponerle otro nombre o alias o apodo o nombre más amigable(como uds lo entiendan mejor) a una instancia de SQL SERVER.
Pasemos de una vez a la acción.
En el próximo post crearé un alias de servidor para SQL SERVER 2000, ahora les diré cómo se crea un alias de servidor SQL SERVER 2005.
En la máquina donde están corriendo las aplicaciones:
Vamos a Inicio > Programas > Microsoft SQL SERVER 2005 > Herramientas de configuración > Administrador de configuración de SQL Server.
Se mostrará la caja de diálogo siguiente:
Hacemos click derecho sobre la opción que dice Alias y del menú desplegable elegimos Nuevo alias...Se mostrará una nueva caja de diálogo, e ingresamos los datos pertinentes según nuestro caso. Pueden notar que también está la opción para añadir el número de puerto, si es tu caso, entonces ponle también el número de puerto.
Es todo, recontra simple cierto?
Ahora veamos cómo se usaría desde nuestras aplicaciones.
Recuerden que al empezar este post creamos una cadena de conexión.
En esa cadena de conexión, la instancia de SQL SERVER es 111.333.444.555, entonces... al ponerle el alias que acabamos de crear, quedaría así...
server=NUEVO_ALIAS;database=MyDatabase;uid=MyUser;pwd=MyPassword;
Qué hice? casi nada: simplemente reemplacé la IP por el alias.
Es todo lo que habría que hacer.
En realidad, un alias de servidor brinda muchos más beneficios, pero mi enfoque ha sido desde la perspectiva de un desarrollador de aplicaciones, y cómo podría ayudar en su trabajo.

miércoles, 5 de diciembre de 2007

Indices SQL SERVER - II

Este post es la continuación del previo post con el mismo título, jeje.
Recordemos:
Para qué sirven los índices?
Para mejorar la performance de una consulta.
Cómo es que un índice puede mejorar la performance de una consulta?
Fácil, los índices ordenan los registros de una tabla, esta ordenación finalmente permite acceder a los registros de manera más rápida, pues se llega más rápido al lugar donde se encuentra la información requerida, ya que estos índices funcionan de similar manera a los índices de un libro (lo he dicho 20 veces en el post anterior).
La recomendación es usar índices sobre las columnas que participan en la cláusula WHERE de una consulta.
Una tabla puede tener un índice clusterado y 249 índices no clusterados. Osea, en total 250 índices.
Recuerda que un índice puede estar conformado por varias columnas.
Hay dos tipos de índices:
Clusterados.- Ordenan físicamente las filas de una tabla.
Por lo tanto sólo puede haber un índice clusterado por tabla.
Normalmente, el índice clusterado termina siendo la columna con la clave primaria, pues por defecto la columna con clave primaria crea un índice clusterado sobre sí, determinando de esta manera el ordenamiento de dicha tabla (si es que no se ha declarado previamente otra columna con índice clusterado ... claro).
Si Ud. desea crear una tabla cuya clave principal no tenga el índice clusterado, debe añadirle el comando NONCLUSTERED.
De igual manera debe especificar cuál será la columna CLUSTERED... vea:
CREATE TABLE Employee
(
EmployeeID INT PRIMARY KEY NONCLUSTERED,
FirstName VARCHAR(100),
LastName VARCHAR(100),
SSN VARCHAR(8) UNIQUE CLUSTERED
)

Como observa: la columna EmployeeID tiene un índice no clusterado y, la columna SSN ha sido designada como índice clusterado.
Para confirmar, ejecutamos:
SP_HELPINDEX Employee
Pero, qué gano si a la clave primaria le pongo NONCLUSTERED?
Para que entiendas el beneficio de un índice NONCLUSTERED, revisa este concepto:
No Clusterados.- Funcionan similar a los índices clusterados, mejoran la performance de las consultas ya que buscan los registros siguiendo un orden en las filas.
La diferencia es que estos índices no clusterados no determinan el orden físico de las filas en una tabla.
Mas bien, lo que hacen es crear una pila de información lejos de la tabla, donde la información se organiza en base a punteros hacia los identificadores de cada fila... llamados RID (Row Id).
Y cuando se hace una consulta a dicha tabla, se accede a esta pila de información para obtener las filas necesarias.
Entenderás ahora por qué las búsquedas en base a índices clusterados es más rápida:
Porque se busca directamente en la tabla.Pero bueno, no todo es color de rosa, algo malo deben tener estos índices cierto?
Tienes razón. Hablemos de ello.
Los índices son excelentes cuando se trata de consultar datos... osea en operaciones con el comando SELECT.
Lo triste viene con las operaciones de INSERT o UPDATE de una fila... las filas buscarán reordenarse... pues la fila insertada/editada querrá ocupar su nuevo lugar... y las demás filas deberán cederle un lugar... esto provocará que toda la tabla se re-ordene y por consecuencia, genere un retraso en la culminación de la consulta.
Esta pérdida de performance nos conlleva a analizar muy bien cuáles son los índices realmente necesarios que necesita la tabla, ya que a mayor cantidad de índices: mayor retraso en la finalización de la consulta.
Díganme que no es cierto.

martes, 20 de noviembre de 2007

STATISTICS SQL SERVER - II

En el post anterior acerca de STATISTICS también, les decía que me faltó hablar del comando CREATE STATISTICS, y quedó pendiente verdad? pues empecemos el rollo.
Cuando creamos un índice (INDEX) sobre una o varias columnas, lo hacemos porque sabemos que esa(s) columna(s) serán usadas en la cláusula WHERE de una consulta... cierto? sino no tiene caso el índice.
Hasta aquí estamos de acuerdo? Entonces sigamos.
Ahora, cuando en el WHERE de una consulta se incluyen varias columnas, y bajo estas columnas no se ha creado un índice que los haya agrupado... pues la consulta no va a ser resuelta con la mejor performance.
Es en estos casos cuando es el momento adecuado de usar el comando CREATE STATISTICS:
Osea, debemos usar el comando CREATE STATISTICS cuando surge la necesidad de agrupar varias columnas, de modo que las estadísticas generadas (en base a esas columnas) permitirán llevar a buen puerto la consulta ejecutada, porque las estadísticas crean un histograma con los grupos de densidad asociados (colecciones) sobre la columna o conjunto de columnas especificados (revisen el post anterior).
Vamos con un ejemplo:
Digamos que necesito filtrar los registros de una tabla, así:
USE Northwind
GO
SELECT * FROM Employees
WHERE LastName LIKE 'A%' AND FirstName LIKE 'B%' AND Title LIKE 'C%'
Para que mi consulta sea optimizada, sería bueno que hubiese un INDEX(LastName,FirstName, Title), cierto? claro.
Pero la tabla Employees no tiene ese índice, chequeen:
EXEC sp_helpindex employees
Entonces nosotros aplicamos:
CREATE STATISTICS Name_statistics
ON Employees (LastName, FirstName, Title)
Y fuahhhhh!!!!, las estadísticas se crean.
Ahora bien, la ejecución de la consulta sobre la tabla Employees ya debería ser mucho más rápida, pues eso es posible gracias a los histogramas e información sobre la distribución generados de los datos.
Ahora, te estarás preguntando:
Por qué diablos simplemente no hice un CREATE INDEX sobre esas columnas?
La respuesta es: hazlo si quieres.
Debido a la respuesta que te di, entonces tu avispado cerebro se estará preguntando:
hay alguna diferencia entre CREATE STATISTICS o CREATE INDEX?
No pes, son cosas distintas.
Te explico:
Las estadísticas son usadas para determinar qué índices se deben usar cuando se procese una consulta. Son complementarios, no rivales.
Tan simple como eso. Mira que después de dos post de full palabreo, termino diciéndote cómo funcionan las STATISTICS, jeje.

domingo, 18 de noviembre de 2007

STATISTICS SQL SERVER - I

Hay algo en SQL SERVER que se llama STATISTICS (estadísticas) y que nos permite ganar performance a la hora de hacer consultas.
Me explico:
En SQL SERVER tenemos lo que se llama "plan de ejecución", que dicho de manera no técnica sería el camino que el SQL SERVER supone más óptimo para abordar una determinada consulta hacia una o varias tabla(s) dada(s) de la base de datos.
Osea, la probable mejor forma de recuperar datos de la base de datos.
Seguro me preguntarás:

y en qué se basan esos planes de ejecución? Pues en las estadísticas (que desde este momento llamaremos STATISTICS).
Y en qué se basan las STATISTICS? pues las STATISTICS son la metadata de las columnas con índices de las tablas.
Es decir, son las respuestas a:
cuántas filas y páginas tiene una tabla, cómo es la distribución de la data, información sobre las columnas claves, histograma del crecimiento de los datos, etc.
Pero no todo es color de rosa:
así como los datos están constantemente siendo modificados, borrados, insertados, también las STATISTICS necesitan estar actualizadas.
Eso significa que las STATISTICS se desactualizan? exacto.
Sin embargo, se supone que las STATISTICS se actualizan automáticamente, y esto es cierto, pero no siempre...

entonces, cuáles son los disparadores para que esta actualización ocurra??
La actualización de STATISTICS se da cuando la tabla crece o decrece + - en un 10% de su total de registros. Osea, si tu tabla tiene 100 registros y te vuelas 10 o más, la actualización de STATISTICS ocurre.Y si tu tabla tiene 100 registros y añades 10 o más, la actualización de STATISTICS ocurre.
Si tu tabla tiene 100 registros y te vuelas 1, LA ACTUALIZACIÓN DE STATISTICS NO OCURRE!! ajá, he ahí el problema!!

Cómo lo solucionamos??
Es aquí cuando tenemos que hacer la actualización manual de las STATISTICS, veamos cómo se hace eso.
Se puede hacer de dos formas:
1.- Usando el procedimiento almacenado sp_updatestats
Este procedimiento almacenado actualiza las tablas de usuario y también las tablas del sistema de toda una base de datos.
Ejemplo:
use Northwind
go
exec sp_updatestats
go
2.- A través del comando UPDATE STATISTICS.

Esta es la manera más flexible.
Permite combinar una serie de opciones adicionales, como:
FULLSCAN, realiza un escaneo completo del índice o columna en observación
WITH SAMPLE (PERCENT, ROWS), permite ingresar el porcentaje o número de filas que deseamos que se use como muestra
RESAMPLE, permitirá incluir a los nuevos registros en la muestra para hacer las STATISTICS
ALL / COLUMNS / INDEX, especifica qué STATISTICS actualizar
NORECOMPUTE, indicará que las filas que son añadidas después de esta actualización, no sean incluidas en las siguientes actualizaciones de STATISTICS.
use Northwind

go
UPDATE STATISTICS Employees WITH SAMPLE 35 PERCENT, ALL
go
También podemos saber si un índice ha sido actualizado (y cuándo... claro está) usando el comando DBCC SHOW_STATISTICS:

DBCC SHOW_STATISTICS ( MyTableName, MyIndexName )
Y qué sabes del comando CREATE STATISTICS?

Jeje... tienes razón, no he dicho nada al respecto.
En el próximo post hablaremos de ello.

sábado, 10 de noviembre de 2007

Indices en SQL SERVER - I

Analizemos una situación:
Digamos que tengo una tabla llamada Empleados en donde se guarda la información de 2'000,000 de empleados.
Si yo quisiera recuperar los registros de aquellos empleados cuyo nombre sea Pepe...
estarán de acuerdo conmigo en que para hacer esto necesito necesito ir de fila en fila y verificar si el campo nombre es igual a Pepe. Osea,
SELECT * FROM Empleados WHERE Nombre = 'Pepe'
simple no?
claro, pero cuánto te demoras.
Otro ejemplo (este es el típico ejemplo y que termina convenciéndote):
Si tengo un libro y quiero buscar un tema específico, digamos LA BATALLA DE LAS TERMÓPILAS, cómo hago?

voy de hoja en hoja y busco un título que coincida? no seas malo... nunca acabaría, mas bien vamos derechito al índice buscamos ahí ese título, luego que lo encontramos nos fijamos en qué página dice que se encuentra y fuah!! en un dos por tres llegamos a la página especificada. Perfecto no?
Y, eso se puede hacer en SQL SERVER? exaaaaaaaaaaaaacto, captaste la idea!! yuuuuuuuuju!!
Sí, sí se puede hacer en SQL SERVER.
Y eso mejora la performance de la consulta? pos pa' que te digo que no si sí.

En el ejemplo del libro que te comentaba, se llegaba más rápido al tema buscado gracias a que se contaba con un índice.
En SQL SERVER también hay índices... y te recomiendo muy seriamente que lo tomes en cuenta a la hora de trabajar con tablas que contengan bastantes registros.

Ahora, te explicaré cómo funcionan los índices en SQL SERVER.
Si tenemos una tabla con 10 empleados: pepe, juan, juana, camilo, pedro, pepe, jesus, charles, juan y diana.
Digamos también que los ingresaste en ese orden: primero a pepe, luego a juan, luego a juana y asi sucesivamente.
Si tuvieras que hacer una consulta que busque a todos los empleados que se llamen pepe, harías esto:
SELECT * FROM Empleados WHERE Nombre = 'Pepe'
y el SQL lo primero que haría es preguntar: esa tabla tiene índice? si la respuesta es NO, entonces el SQL diría "pucha, osea que tengo que buscar fila por fila!"... efectivamente, eso tendría que hacer... preguntaría: te llamas pepe? si es así te acumula, si no pasa al siguiente registro, y así... pero si son 2 millones de filas?... imagínate cuánto demora esta consulta.
Ahora, te explicaré por qué mejora la performance de la consulta si le pones índices a la tabla.
Al crearle un índice a una tabla, tú debes especificar a cuál(es) columnas le deseas poner índice, ponerle índice significa darles un orden ascendente o descendente, en función de los caracteres que forman ese campo (en nuestro caso nos referimos al campo Nombre).
Observen el gráfico

En realidad hay dos tipos de índices:
Clusterados, reordenan la tabla de manera física, osea cambian el orden de los registros.
No clusterados, no reordenan los registros de manera física, pero si almacenan una especie de secuencia en otro lugar, de manera que cuando hay una consulta, chequeamos ese índice e igual, accedemos más rápido a los registos que buscamos.

Pero por esta vez no profundicemos más en el tema, mi idea era hablarles sobre los índices SQL SERVER a manera de cuento para que quede más o menos claro y ya desde el próximo post nos ponemos más técnicos en el tema jeje.

viernes, 2 de noviembre de 2007

Insertar varias filas a la vez en SQL SERVER - II

Insertar elementos y atributos
Me pregunté si alguien se preguntaría el ¿cómo insertar elementos y atributos de un documento XML a la vez?, osea ambos...
Por si las dudas, aquí va un ejemplo de cómo se debería proceder.
Para ello necesitamos el documento XML que contenga elementos y atributos







Como pueden observar, he indicado cuál es un atributo y cuál es un elemento.
Profesor, profesor, al construir mi documento XML...cómo hago para determinar cuál es indicado a ser atributo y cuál debería ser el elemento?
Muy buena tu pregunta, y aunque no hay una respuesta única, esto se ve con más claridad con la experiencia, ...pero puedo decirte que particularmente lo declaro como atributo cuando la información es complementaria y lo marco como elemento cuando la información es parte fundamental del nodo, osea su razón de ser.
Algunos más radicales dicen que es elemento cuando lo puede entender una persona y es atributo cuando la información va a ser procesada y entendida por la máquina.
En todo caso, si quieres profundizar en el tema, para eso está internet jeje.

Sigamos con lo nuestro.
Éste sería el store procedure que haga el trabajo sucio:



















Y nuevamente, no hay mucho que explicar aquí, en realidad lo único que tenemos que hacer para obtener el elemento, es poner un punto, vean la imagen.














Imagínense, todo un post para decirles que pongan un punto jaja.
Si este post no es muy claro, les sugiero que chequeen el post previo a éste, 

http://www.neuronasoft.net/2007/10/insertar-varias-filas-la-vez-sql-server.html
pues éste es sólo un complemento del anterior.

lunes, 29 de octubre de 2007

Insertar varias filas a la vez en SQL SERVER - I

Cuántas veces nos hemos encontrado en la situación de tener que insertar varias filas en la base de datos?
Muchas veces seguro.
Y cómo lo has solucionado?
No me vayas a decir que hiciste un bucle del 1 al 1000 en tu aplicación para que se comunique con la base de datos tantas veces como filas tenías ah?
For i = 1 to inCantFilas
InsertRow("Dato1","Dato2","Dato3",....,"DatoN")
Next i
Eso no se hace!!

Bueno, si hiciste eso... no lo vuelvas a hacer... nadie se enteró de ello, pero si aún puedes, corrígelo.
Por qué? 3 grandes motivos:
1.- Performance de tu aplicación.
2.- Reducción en el tráfico de red.
3.- Nos hace sentir mejor el hacer las cosas bien.
Así es, insertar varias filas en una base de datos se puede hacer de un sólo viaje.
SQL SERVER usa lo siguiente para ello:
sp_xml_preparedocument
OPENXML
sp_xml_removedocument
Y así, conviertes la operación en un juego de niños.


Empecemos con el juego:
Para este ejemplo vamos a suponer que tienes una tabla llamada NewTable con tres campos(CustomerID, Contactname, OrderDate) en la base de datos... y por qué vamos a suponer eso?? porque se supone que quieres insertar varios registros en una tabla que ya existe!! y si no la tienes: créala!!
Digamos que tienes un datagrid con varias filas (podrían ser 1000 filas) y, digamos que quieres insertar toda esas filas de un pepo en la base de datos.










Lo único que tenemos que hacer es darle la forma de un documento XML





El cual se lo pasamos a este procedimiento











Y, en el servidor necesitaremos un procedimiento almacenado que reciba esa info.


















En realidad, es en el contenido del procedimiento almacenado en lo que debemos concentrarnos... que en realidad es muy simple, explicaré en qué consiste:
La variable @MyXML es la que recibirá el XML desde la aplicación ok?
Antes de poder usar la variable @MyXML, necesitamos preparar el documento XML, lo cual lo hacemos con el procedimiento almacenado sp_xml_preparedocument.
Luego, creamos una tabla temporal (#Temporal), donde previamente guardaremos los datos del XML, esto lo hacemos con la función OPENXML.
Luego de guardar la data en la tabla #Temporal, removemos las referencias al XML de memoria usando sp_xml_removedocument.
Finalmente, insertamos en nuestra tabla NewTable, los datos que previamente guardamos en la tabla #Temporal,usando:
INSERT INTO NewTable
SELECT * FROM #Temporal
Está casi todo explicado verdad?
Me olvidaba de la parte que dice '/Customers/Customer' ... es simplemente la ruta del XML desde donde extraeremos los registros.
Como han visto, insertar varias filas a la vez en una tabla es una tarea sencilla.