1.14. Ejemplo práctico: gestión del catálogo de genes humanos
Para demostrar cómo extraer conocimiento útil de una base de datos relacional, os proponemos analizar con MySQL el contenido de un catálogo de genes humanos. Un gen es un fragmento de ADN ubicado en el genoma que contiene la información precisa para sintetizar una molécula de ARN. En los organismos eucariotas, un gen está constituido por una sucesión de fragmentos útiles denominados exones. En una proporción significativa de los genes humanos existen varias combinaciones alternativas de exones, dando lugar a distintas formas alternativas de un mismo gen, denominadas transcritos alternativos. Para codificar la información relativa a la localización de los genes en el genoma es frecuente utilizar ficheros de texto tabulado. Cada línea de estos ficheros contiene los valores de los atributos que caracterizan a un transcrito de un determinado gen. Básicamente, un transcrito de un gen posee una localización concreta, identificada por un cromosoma, una posición inicial/final y una dirección de lectura. Otras características que podemos recuperar sobre un transcrito son su código, el nombre del gen, el número de exones o sus coordenadas exactas.
Ved también
Para revisar los conceptos de genoma, cromosoma, gen y proteína os recomendamos la asignatura Fundamentos de biología molecular.
El navegador genómico de UCSC representa gráficamente los diferentes tipos de anotaciones existentes sobre el genoma humano en forma de cientos de pistas. Para administrar eficientemente este elevado volumen de información, una copia del SGBD MySQL está funcionando de forma transparente a los miles de usuarios que cada día visitan este servidor. De este modo, en el caso de que deseemos reproducir una pista en nuestro ordenador, disponemos en la sección de descargas de un fichero SQL para ser ejecutado con el comando source
y un fichero de texto con el conjunto de datos que deben importarse con la instrucción LOAD DATA
. En este ejercicio vamos a utilizar la anotación de los genes humanos distribuida por el consorcio RefSeq para el genoma humano. Este formato es común a todas las especies suministradas por el navegador.
Ved también
Es posible profundizar sobre el funcionamiento de los navegadores genómicos en la asignatura Genómica computacional.
Vamos a proceder ahora a descargar los dos ficheros asociados a la pista refGene, que contiene el catálogo de genes humanos anotados por el consorcio RefSeq, en su versión hg38.
Para ello, debemos utilizar el comando wget
para transferir ambos ficheros a nuestro terminal.
wget
http://hgdownload.soe.ucsc.edu/goldenPath/hg38/database/refGene.sql
wget
http://hgdownload.soe.ucsc.edu/goldenPath/hg38/database/refGene.txt.gz
Mostramos a continuación el contenido del fichero refGene.sql que realiza la creación de la tabla refGene. Los atributos que consultaremos con mayor frecuencia serán: name (código del transcrito), chrom (cromosoma), strand (hebra), txStart y txEnd (coordenadas de inicio y final), exonCount (número de exones) y name2 (nombre del gen).
Es importante no confundir los campos de name y name2: un gen puede tener varios transcritos, pero un transcrito únicamente pertenece a un gen.
CREATE TABLE 'refGene' ( 'bin' smallint(5) unsigned NOT NULL, 'name' varchar(255) NOT NULL, 'chrom' varchar(255) NOT NULL, 'strand' char(1) NOT NULL, 'txStart' int(10) unsigned NOT NULL, 'txEnd' int(10) unsigned NOT NULL, 'cdsStart' int(10) unsigned NOT NULL, 'cdsEnd' int(10) unsigned NOT NULL, 'exonCount' int(10) unsigned NOT NULL, 'exonStarts' longblod NOT NULL, 'exonEnds' longblod NOT NULL, 'score' int(11) DEFAULT NULL, 'name2' varchar(255) NOT NULL, 'cdsStartStat' enum('none','unk','incmpl','cmpl') NOT NULL, 'cdsEndStat' enum('none','unk','incompl','cmpl') NOT NULL, 'exonFrames' longblod NOT NULL, KEY 'chrom' ('chrom', 'bin'), KEY 'name' ('name'), KEY 'name2' ('name2') ) ENGINE=MyISAM DEFAULT CHARSET=1atin1;
Pasaremos ahora a visualizar con el terminal el segundo fichero refGene.txt. Este archivo contiene los datos del catálogo completo de genes anotados en el genoma humano. Debemos cargar esta información en nuestra base de datos una vez esté creada la tabla refGene. En el contexto de este ejercicio, cada registro contiene información sobre un transcrito de un determinado gen. En el caso de que un gen posea varios transcritos, cada uno se codifica en registros separados (cada uno con su propio código y sus correspondientes coordenadas).
En primer lugar, debemos descomprimir el fichero con el comando gzip.
% gzip -d refGene.txt.gz % head -5 refGene.txt 585 NR_046018 chr1 + 11873 14409 14409 14409 3 11873,12612,13220, 12227,12721,14409, 0 DOX11L1 unk unk -1,-1,-1, 585 NR_024540 chrl - 14361 29370 29370 29370 11 14361,14969,15795,16606,16857,17232,11605, 11914, 18267,24737,29320,14829,15038,15947,16765,17055,17368,17742,18061,18366,24891,29370, 0 WASH7P unk unk -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 932 NR_104645 chrX + 45505387 45523644 45523644 45523644 3 45505387,45510496,45521607, 45505465, 45510595,45523644, 0 LINC01204 unk unk -1,-1,-1, 1078 NR_104148 chr7 + 64666082 6468783O 64687830 64687830 4 64666082,64669036,64679176,64684334, 64666285,64669178,64679336,64687830, O ZNF107 unk unk -1,-1,-1,-1, 103 NR_120408 chrl4 + 31561384 31861223 31861223 31861223 10 31561384,31562067,31565013,31599288, 31673354,31673483,31826628,31846470,31850118,31859117,31561547,31562215,31565048,31599379, 31673394,31673574,31826714,31846591,31850201,3186l223, ONUBPL unk unk -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
Las anotaciones de un genoma suelen actualizarse frecuentemente. Por este motivo, los datos mostrados en este tutorial pueden variar ligeramente con el paso del tiempo.
Una vez dentro del intérprete de MySQL, indicaremos que vamos a trabajar dentro de nuestra base de datos catalogo.
Ejecutaremos, posteriormente, el fichero refGene.sql con el comando source
para crear la tabla refGene.
Para verificar que la instrucción anterior ha funcionado correctamente, podemos ver el listado de atributos de la tabla refGene con el comando DESCRIBE
:
mysql> USE catalogo; Database changed mysql> DESCRIBE refGene; +---------------+-----------------------------------+------+------+---------+-------+ | Field | Type | Null | Key | Default | Extra | +---------------+-----------------------------------+------+------+---------+-------+ | bin | smallint(5) unsigned | NO | | NULL | | | name | varchar(255) | NO | MUL | NULL | | | chrom | varchar(255) | NO | MUL | NULL | | | strand | char(1) | NO | | NULL | | | txStart | int(10) unsigned | NO | | NULL | | | txEnd | int(10) unsigned | NO | | NULL | | | cdsStart | int(10) unsigned | NO | | NULL | | | cdsEnd | int(10) unsigned | NO | | NULL | | | exonCount | int(10) unsigned | NO | | NULL | | | exonStarts | longblog | NO | | NULL | | | exonEnds | longblog | NO | | NULL | | | score | int(11) | YES | | NULL | | | name2 | varchar(255) | NO | MUL | NULL | | | cdsStartStat | emun('none','unk',incmpl','cmpl') | NO | | NULL | | | cdsEndStat | emun('none','unk',incmpl','cmpl') | NO | | NULL | | | exonFrames | longblog | NO | | NULL | | +---------------+-----------------------------------+------+------+---------+-------+ 16 rows in set (0.14 sec)
Vamos a asumir que ambos ficheros (refGene.sql y refGene.txt) están guardados en la misma carpeta de trabajo desde la cual hemos invocado al programa MySQL, anteriormente.
El segundo paso consiste en poblar la tabla con las anotaciones de los genes humanos que hemos descargado dentro del fichero refGene.txt. Usando el comando LOAD DATA podemos volcar todo el contenido en la tabla refGene:
mysql> LOAD DATA LOCAL INFILE 'refGene.txt' INTO TABLE refGene; Query OK, 69853 rows affected (2.54 sec) Records: 69853 Deleted: 0 Skipped: 0 Warnings: 0
Nos encontramos en condiciones de comenzar a interrogar a la base de datos. Recordemos, nuevamente, que cada registro de la tabla refGene alberga la información asociada al transcrito de un gen en particular. Igualmente, es importante tener en cuenta que una elevada fracción de los genes humanos posee dos o más transcritos alternativos. Nuestra misión, a continuación, es mostrar el enorme potencial de las consultas de SQL a la hora de extraer nuevo conocimiento biológico de los datos almacenados en las tablas de nuestra base de datos.
Comenzaremos mostrando los primeros registros de nuestra tabla, incluyendo únicamente varios de sus atributos para favorecer la legibilidad de los valores de los registros por pantalla:
mysql> SELECT name2,name,chrom,strand,txStart,txEnd,exonCount -> FROM refGene ORDER BY name2 LIMIT 10; +----------+--------------+-------+--------+----------+----------+-----------+ | name2 | name1 | chrom | strand | txStart | txEnd | exonCount | +----------+--------------+-------+--------+----------+----------+-----------+ | A1BG | NM_130786 | chr19 | - | 58346805 | 58353499 | 8 | | A1BG-AS1 | NR_015380 | chr19 | + | 58351969 | 5835583 | 4 | | A1CF | NM_01198819 | chr10 | - | 50799408 | 50885675 | 15 | | A1CF | NM_014576 | chr10 | - | 50799408 | 50885675 | 13 | | A1CF | NM_138932 | chr10 | - | 50799408 | 50885675 | 13 | | A1CF | NM_01198820 | chr10 | - | 50799408 | 50885675 | 14 | | A1CF | NM_01198818 | chr10 | - | 50799408 | 50885675 | 14 | | A1CF | NM_138933 | chr10 | - | 50799408 | 50885675 | 13 | | A2M | NM_001347423 | chr12 | - | 9067707 | 9116229 | 37 | | A2M | NM_000014 | chr12 | - | 9067707 | 9116229 | 36 | +----------+--------------+-------+--------+----------+----------+-----------+ 10 rows in set (0.00 sec)
Dado que cada registro contiene la información de un transcrito, el número de transcritos conocidos en el genoma humano coincidirá con el número de registros almacenados en la tabla refGene. Este contaje es sencillo:
mysql> SELECT COUNT(*) FROM refGene; +----------+ | COUNT(*) | +----------+ | 69853 | +----------+ 1 row in set (0.00 sec)
También podemos contar fácilmente el número total de genes codificados en el genoma humano. Si un gen posee varios transcritos alternativos, entonces encontraremos varios registros en nuestro catálogo que poseen un valor distinto del atributo name, pero que comparten el mismo valor para el atributo name2. Por tanto, empleando la cláusula DISTINCT
sobre este último atributo, contaremos una única vez cada gen de nuestra tabla, aunque posea varias formas alternativas:
mysql> SELECT COUNT(DISTINCT name2) FROM refGene; +-----------------------+ | COUNT(DISTINCT name2) | +-----------------------+ | 27656 | +-----------------------+ 1 row in set (0.07 sec)
Si agrupamos los registros de la tabla por el atributo name2, podemos elaborar un inventario del número de transcritos alternativos anotados para cada gen.
mysql> SELECT name2, COUNT(name2) -> FROM refGene GROUP BY name2 LIMIT 10; +----------+--------------+ | name2 | COUNT(name2) | +----------+--------------+ | A1BG | 1 | | A1BG-AS1 | 1 | | A1CF | 6 | | A2M | 4 | | A2M-AS1 | 3 | | A2ML1 | 2 | | A2MP1 | 1 | | A3GALT2 | 1 | | A4GALT | 3 | | A4GNT | 1 | +----------+--------------+ 10 rows in set (0.00 sec)
Podemos obtener resultados interesantes aplicando la cláusula WHERE
sobre los atributos de cada registro. Por ejemplo, imaginemos que deseamos conocer el número de transcritos ubicados en cada hebra de la molécula de ADN:
mysql> SELECT COUNT(*) FROM refGene WHERE strand LIKE '+'; +----------+ | COUNT(*) | +----------+ | 35724 | +----------+ 1 row in set (0.10 sec) mysql> SELECT COUNT(*) FROM refGene WHERE strand LIKE '-'; +----------+ | COUNT(*) | +----------+ | 34129 | +----------+ 1 row in set (0.09 sec)
También podemos contar el número de transcritos localizados en un cromosoma:
mysql> SELECT COUNT(*) FROM refGene WHERE chrom LIKE 'chr21'; +----------+ | COUNT(*) | +----------+ | 961 | +----------+ 1 row in set (0.00 sec)
Nuevamente, jugando con el atributo name2 podemos contar el número de genes codificados en el mismo cromosoma:
mysql> SELECT COUNT(DISTINCT name2) -> FROM refGene WHERE chrom LIKE 'chr21'; +-----------------------+ | COUNT(DISTINCT name2) | +-----------------------+ | 408 | +-----------------------+ 1 row in set (0.01 sec)
O identificar cuáles son los transcritos que poseen un mayor número de exones:
mysql> SELECT name2,name,exonCount -> FROM refGene ORDER BY exonCount DESC LIMIT 10; +-------+--------------+-----------+ | name2 | name | exonCount | +-------+--------------+-----------+ | TTN | NM_001267550 | 363 | | TTN | NM_001256850 | 313 | | TTN | NM_133378 | 312 | | TTN | NM_133437 | 192 | | TTN | NM_133432 | 192 | | TTN | NM_003319 | 191 | | NEB | NM_001271208 | 183 | | NEB | NM_001164507 | 182 | | NEB | NM_001164508 | 182 | | MUC19 | NM_173600 | 174 | +-------+--------------+-----------+ 10 rows in set (0.11 sec)
También podemos seleccionar aquellos transcritos que poseen un único exón:
mysql> SELECT name2,name,exonCount -> FROM refGene WHERE exonCount = 1 -> ORDER BY name2 LIMIT 10; +------------+---------------+-----------+ | name2 | name | exonCount | +------------+---------------+-----------+ | AADACL2-AS1 | NR_110203 | 1 | | ABALON | NR_131907 | 1 | | AEBP16B | NM_080622 | 1 | | ACKR1 | NM_001122951 | 1 | | ACKR4 | NM_178445 | 1 | | ACTBL2 | NM_001017992 | 1 | | ACTG1P20 | NR_033926 | 1 | | ACTG1P4 | NR_024438 | 1 | | ACTL10 | NM_001024675 | 1 | | ACTL7A | NM_006687 | 1 | +------------+---------------+-----------+ 10 rows in set (0.00 sec)
Es posible calcular el número de exones, en promedio, por cada transcrito:
mysql> SELECT AVG(exonCount) FROM refGene; +----------------+ | AVG(exonCount) | +----------------+ | 9.4126 | +----------------+ 1 row in set (0.11 sec)
Y la longitud en promedio de los transcritos de los genes humanos:
mysql> SELECT AVG(txEnd-txStart+1) FROM refGene; +----------------------+ | AVG(txEnd-txStart+1) | +----------------------+ | 56983.2770 | +----------------------+ 1 row in set (0.10 sec)
Finalmente, vamos a integrar en este análisis el genoma de ratón doméstico. Descargamos los ficheros refGene.sql y refGene.txt de esta especie en su versión mm9.
Para evitar sobrescribir las anotaciones humanas, debemos grabar ambos ficheros con un nombre diferente (por ejemplo, refGene_mouse.sql y refGene_mouse.txt). Posteriormente, es necesario editar el contenido del fichero SQL para modificar el nombre de la tabla, por la misma razón.
Tras estas modificaciones, ya estamos en condiciones de lanzar la creación de la nueva tabla con el comando source y su repoblación con los datos relativos al genoma del ratón con el comando LOAD DATA
.
DROP TABLE IF EXISTS 'refGene_mouse'; CREATE TABLE 'refGene_mouse' ( 'bin" smallint(S) unsigned NOT NULL, 'name' varchar(255) NOT NULL, 'chrom' varchar(255) NOT NULL, 'strand' char(l) NOT NULL, ... --------------------------------------- mysql> source 'refGene_mouse.sql'; Query OK, 0 rows affected (O.00 sec) mysql> LOAD DATA LOCAL INFILE 'refGene_mouse.txt' -> INTO TABLE refGene_mouse; Query OK, 34904 rows affected (l.23 sec) Records: 34904 Deleted: O Skipped: O Warnings: 0
Comprobamos que los registros almacenados en la nueva tabla son correctos:
mysql> SELECT name2,name,chrom,strand,txStart,txEnd,exonCount -> FROM refGene_mouse ORDER BY name2 LIMIT 10; +---------------+--------------+-------+--------+-----------+-----------+-----------+ | name2 | name | chrom | strand | txStart | txEnd | exonCount | +---------------+--------------+-------+--------+-----------+-----------+-----------+ | 0610005C13R1k | NR_O38166 | chr7 | - | 52823164 | 52830S46 | 5 | | 0610005C13R1k | NR_038165 | chr7 | - | 52823164 | 52830S46 | 4 | | 0610007P14Rik | NM_021446 | chr12 | - | 87156404 | 87165495 | 5 | | 0610009B22Rik | NM_L025319 | chr11 | - | 51498886 | 51502136 | 2 | | 0610009Ll8Rik | NR_038126 | chr11 | + | 120209991 | 120212504 | 2 | | 0610009O20Rik | NM_024179 | chr18 | + | 38409902 | 38422283 | 13 | | 0610010B08Rik | NM_001177543 | chr2 | - | 175017505 | 175163713 | 6 | | 0610010B08Rik | NM_001177543 | chr2 | - | 174952492 | 175261278 | 6 | | 0610010B08Rik | NM_001177543 | chr2 | + | 175639522 | 175655901 | 5 | | 0610010B08Rik | NM_001177543 | chr2 | + | 175737073 | 175753460 | 5 | +---------------+--------------+-------+--------+-----------+-----------+-----------+ 10 rows in set (0,00 sec)
Ahora, si seleccionamos aquellos registros de las dos tablas que pertenecen al mismo gen en ambas especies, podemos construir un catálogo de genes homólogos.
Podemos llevar a cabo esta asociación porque SQL no distingue entre mayúsculas o minúsculas a la hora de comparar la columna name2.
mysql> SELECT DISTINCT refGene.name2,refGene.chrom,refGene.strand, -> RefGene.txStart,refGene.txEnd,refGene.exonCount, -> refGene_mouse.name2,RefGene_mouse.chrom, -> refGene_mouse.strand,refGene_mouse.txStart, -> refGene_mouse.txEnd,refGene_mouse.exonCount -> FROM refGene JOIN refGene_mouse -> ON refGene.name2 = refGene_mouse.name2 -> ORDER BY refGene.name2 ASC LIMIT 10; +---------+-------+--------+----------+----------+-----------+---------+-------+--------+-----------+-----------+-----------+ | name2 | chrom | strand | txStart | txEnd | exonCount | name2 | chrom | strand | txStart | txEnd | exonCount | +---------+----------------+----------+----------+-----------+---------+-------+--------+-----------+-----------+-----------+ | A1BG | chr19 | - | 58346805 | 58353499 | 8 | A1bg | chr15 | - | 60749143 | 60752825 | 7 | | A1CF | chr10 | - | 50799408 | 50885675 | 13 | A1cf | chr19 | + | 31943250 | 32023896 | 12 | | A1CF | chr10 | - | 50799408 | 50885675 | 14 | A1cf | chr19 | + | 31943250 | 32023896 | 12 | | A1CF | chr10 | - | 50799408 | 50885675 | 15 | A1cf | chr19 | + | 31943250 | 32023896 | 12 | | A2M | chr12 | - | 9067707 | 9116229 | 35 | A2m | chr6 | + | 121586190 | 121629256 | 36 | | A2M | chr12 | - | 9067707 | 9116229 | 36 | A2m | chr6 | + | 121586190 | 121629256 | 36 | | A2M | chr12 | - | 9067707 | 9116229 | 37 | A2m | chr6 | + | 121586190 | 121629256 | 36 | | A3GALT2 | chr1 | - | 33306765 | 33321098 | 5 | A3galt2 | chr4 | + | 128436501 | 128446542 | 5 | | A4GALT | chr22 | - | 42692111 | 42720910 | 3 | A4galt | chr15 | - | 83057151 | 83082161 | 3 | | A4GALT | chr22 | - | 42692111 | 42720910 | 3 | A4galt | chr15 | - | 83057151 | 83082204 | 3 | +---------+-------+--------+----------+----------+-----------+---------+-------+--------+-----------+-----------+-----------+ 10 rows in set (5.14 sec)