Skip to content

Instantly share code, notes, and snippets.

@isra00
Last active April 5, 2016 13:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save isra00/4526066 to your computer and use it in GitHub Desktop.
Save isra00/4526066 to your computer and use it in GitHub Desktop.
Material de estudio para la certificación MySQL Developer

1 Client/Server

  • Las opciones para el comando mysql pueden ser especificadas en el grupo [mysql] de /etc/my.cnf, y sobreescritas en ~/.my.cnf, y también sobreescritas en el fichero que se especifique en la opción --defaults-extra-file
  • mysql -h funciona solo en Windows, y trata de conectarse al servidor local con shared memory o named pipeline.
  • Especificando -h 127.0.0.1, la conexión se hace a través de TCP/IP.

SQL Modes:

  • ANSI QUOTES: dobles comillas en lugar de una.
  • IGNORE_SPACE: permite espacio entre el nombre de una función y los paréntesis.
  • ERROR_FOR_DIVISION_BY_ZERO: lanza warning cuando al dividir por cero, o error si está en strict mode.
  • STRICT_TRANS_TABLES, STRICT_ALL_TABLES: modo estricto (tipos) en los INSERTs (transaccionales o todas).
  • TRADITIONAL: activa strict mode y algunas restricciones más en los INSERTs.
  • ANSI: ANSI_QUOTES + operador || como concatenación (en vez de OR), otros.

Respuestas del test:

  1. false ✓
  2. false ✓
  3. true ✗
  4. false ✓
  5. socket, tcp/ip ✓
  6. host ✗ --user (-u) and --password (-p)
  7. local, tcp/ip, no ✗ socket on Unix, tcp/ip on Win
  8. local, tcp/ip, no ✗ shared memory or named pipe, so it works only on Win
  9. local, tcp/ip, no ✓
  10. remote, tcp/ip, no ✗ remote or local if ip is 192.168.10.1
  11. depends on defaults, depends on defaults, no ✗ local, socket on Unix, shared memory/named pipe on Win
  12. false, false, true, true, false ✓

Total: 6/12

10 SQL expressions

  • 30 decimales

  • Las operaciones con números se realizan con precisión de 64b

  • Aproximados (notación científica). Mantisa de 53b

  • Las cadenas que contienen números son convertidas automáticamente en números

  • Ojo con las comparaciones de valores float!

  • Variables character_set_connection y collation_connection se aplican por defecto a comparaciones de cadenas

  • LENGTH() mide bytes y CHAR_LENGTH() caracteres

  • UPPER() y LOWER() son inocuas en cadenas binarias

  • CONVERT([BINARY] cadena USING charset)

  • [NOT] LIKE 'patron' ESCAPE caracter_de_escape

  • LIKE trata las cadenas como no binarias por defecto

  • (INTERVAL cantidad UNIT) donde UNIT es SECOND, MINUTE, HOUR, DAY, MONTH O YEAR

  • Cualquier operación con NULL da NULL, excepto valor <=> NULL.

  • Modo IGNORE_SPACE permite espacios entre el nombre de una función y los paréntesis de invocación

  • Funciones de comparación: LEAST(valores), GREATEST(valores), INTERVAL(a, b, c, d...) (devuelve los valores <= a), IN, BETWEEN

  • Funciones de control de flujo: IF(condicion, valor_true, valor_false) (como operador ternario)

    CASE [expresion] WHEN expr o valor THEN valor ELSE valor END

  • Funciones de agregación: SUM(), AVG(), MAX(), MIN(), COUNT()

  • Funciones matemáticas: ROUND(), FLOOR(), CEILING(), ABS(), SIGN(), SIN(), COS(), TAN(), PI(), DEGREES(), RADIANS(), RAND()

  • Funciones de cadenas: LENGTH(), CHAR_LENGTH(), CONVERT(cadena USING charset), STRCMP(a, b) (devuelve -1, 1 o 0 si a es mayor, menor o igual, según el cotejamiento), CONCAT(a, b), CONCAT_WS(separador, cadenas), ENCODE(), DECODE(), DES_ENCRYP(), DES_DECRYPT(), AES_ENCRYPT(), AES_DECRYPT()

  • Funciones temporales: YEAR(), MONTH(), DAYOFMONTH(), DAYOFYEAR(), HOUR(), MINUTE(), SECOND(), MAKEDATE(año, dia_del_año), MAKETIME(hora, minuto, segundo), CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, NOW()

  • Funciones de NULL: ISNULL(), IFNULL(valor, devuelto)

  • Comentarios: # para una línea, -- para una línea (espacio obligatorio), /* / para multilínea, /! QUERY / para lanzar la query, /!version QUERY */ para lanzar la query si la versión es >= version

Respuestas del test:

  1. Any type defined as NOT NULL ✗ Table columns (Name, IndepYear), literal values and function (CONCAT, IF)

  2. Float values are not exact. The CPU manages the representation of the values, and the accuracy cannot be guaranteed, so the result of the sum cannot be safely determined as exact. ✓

  3. ✗ sql_mode was set to ANSI_QUOTES before the second statement

  4. When executing the first statement, the session_collation specifies a collation that does not match as equals the strings in the variables (for example, any binary collation). In the second, the session_collation specifies a collation that does. ✗ default collation was latin1_swedish_ci, and latin1_german2_ci was set after

  5. true, since the bytes that represents both strings are equal. ✓

  6. SELECT UPPER(CONVERT(@var USING latin1); ✓

  7. The second one is executed with the IGNORE_SPACES mode enabled, whereas in the second it's disabled. ✓ IGNORE_SPACE

  8. ✗ Constants can be literal numbers, strings or temporal values. A SQL expression can be constant, NULL, references to table columns or functions.

  9. SELECT 9 = 9; ✓

  10. SELECT 'Hello world' IS NOT NULL; ✓

  11. SELECT '2013-01-01' + INTERVAL 2 DAYS; ✓

  12. ✗ SELECT '21:39:00';

  13. SELECT Name FROM world.Country; ✓

  14. SELECT NOW(); ✓

  15. SELECT NOW() = '2013-02-12'; ✓

  16. SELECT pid, salary AS GrossSalary, salary*0.4 AS Deduction, GrossSalary-Deduction AS NetSalary FROM personnel; ✓

  17. SELECT unit, SUM(salary) AS GrossSalary, GrossSalary*0.4 AS Deduction, GrossSalary-Deduction AS NetSalary FROM personnel GROUP BY unit; ✓

  18. SELECT pid, salary AS GrossSalary, salary*IF(GrossSalary >= 2000, 0.4, 0.3) AS Deduction, GrossSalary-Deduction AS NetSalary FROM personnel; ✓

  19. SELECT pid, salary AS GrossSalary, salary*1.1 AS 'Cost Rise' FROM personnel; ✗ salary * .1 AS 'Cost Rise'

  20. SELECT pid, salary AS GrossSalary, salary*IF(unit = 23, 1.1, 1.05) AS 'Cost Rise' FROM personnel; ✗ SUM(salary) * IF(unit = 23, .1, .05) AS 'cost rise'

  21. a) +---------+ | name | +---------+ | Lennart | +---------+ ✓

    b) 1 ✗ 4 c) 4 ✗ error porque no hay sentencia GROUP BY, obligatoria cuando hay COUNT() y otras columnas NO agregadas

  22. a) 4, b) 4, c) 4 ✗ c) error

  23. LENGTH() returns the length in bytes, CHAR_LENGTH() in characters (different in multi-byte charsets). ✓

  24. false ✓

  25. a) 'FALSE', b) 'FALSE', c) 'FALSE' ✗ a) TRUE, because default collation is case-insensitive

  26. 1 ✓

  27. 0 ✓

  28. 1 ✓

  29. 0 ✓

  30. 1 ✗ 0

  31. 1 ✓

  32. 1 ✓

  33. 1 ✓

  34. NULL ✓

  35. NULL ✓

  36. 1 ✓

  37. 0 ✓

  38. 1 ✓

  39. 0 ✗ 1

  40. 0 ✓

  41. SELECT City, Country, Population FROM CityList WHERE Country IN ('DNK', 'DEU', 'USA') AND Population BETWEEN 400000 AND 500000 ORDER BY Population DESC; ✓ Name as City

  42. Error. == is not a valid SQL operator ✓

  43. Error. = is not a ternary operator. ✗ NULL since there is at least one NULL expression

  44. Error. = is not a ternary operator. ✗ NULL since there is at least one NULL expression

  45. Error. "IS NOT NULL" is the right form. ✓

  46. 1 ✓

  47. 1 ✗ 0

  48. yes ✓

  49. no ✗ yes, it's valid

  50. yes ✓ but it's not a version-specific comment

  51. no ✓

  52. no, -- requires a space after ✓

  53. AES_ENCRYPT(), AES_DECRYPT(), DES_ENCRYPT(), DES_DECRYPT(). DES_* needs SSL ½ + ENCODE(), DECODE(), PASSWORD()

  54. 2 and -1 ✗ 2, -2

Total: 37.5/54

11 Updating data

  • INSERT: sintaxis de SET y VALUES
  • INSERT: Si no se especifica una columna, se tomará el default (del campo o del tipo) o error si modo estricto
  • INSERT: se puede poner lista de columnas vacía, en cuyo caso se rellenarán todos los campos con default
  • INSERT múltiples están limitados por max_allowed_packet (transferencia), default 1MB
  • INSERT múltiples: devuelve información Records, Duplicates y Warnings.
  • INSERT múltiples: si INSERT IGNORE, si no da error al haber duplicados en UNIQUEs. En MyISAM inserción parcial, en InnoDB no se inserta nada si falla algo. ON DUPLICATE KEY col1=value1, [col2=value2, ...] actualiza la fila duplicada y devuelve OK, 2 rows affected
  • REPLACE INTO tabla SET/VALUES: elimina el duplicado e inserta la nueva. Solo funciona con claves únicas que no admitan NULL
  • UPDATE no produce efectos si los nuevos valores son idénticos a los antiguos
  • UPDATE devuelve el número de filas afectadas
  • UPDATE ... SET ... ORDER BY ... LIMIT limite (ojo, LIMIT no admite offset, solo nº máximo de filas afectadas)
  • mysql --safe-updates prohibe UPDATEs sin WHERE o LIMIT o que afecten a más de 1000 filas
  • DELETE devuelve el nº de filas borradas, TRUNCATE no
  • TRUNCATE reinicia el auto_increment, y DELETE también solo si no tiene WHERE
  • DELETE ... ORDER BY ... LIMIT limite (igual que UPDATE)
  • Privilegios: REPLACE necesita los permisos INSERT y DELETE; TRUNCATE necesita el permiso DELETE.

Respuestas del test:

  1. (1, '', '', '', '0') <- 1 because AUTO_INCREMENT ✓

  2. It will fail, because with strict_mode you cannot enter NULL values in NOT NULL columns ✓

  3. a) INSERT INTO twounique VALUES (1, 1) ✓ b) INSERT IGNORE INTO twounique VALUES (1, 1), (2, 3) ✗ use REPLACE instead c) REPLACE INTO twounique VALUES (1, 1) ✓ d) INSERT INTO twounique VALUES (1, 2) ON DUPLICATE KEY UPDATE id1=2, id2=3 ✓

  4. a) (2, 2), (3, 4), (5, 6) b) (3, 4), (2, 6) ✓

  5. INSERT INTO table (rows) VALUES (values), (values), (more values), ... ✓

  6. Because REPLACE deletes the duplicates ✓

  7. INSERT INTO access_log SET PIN = whatever, entries = 1 ON DUPLICATE KEY UPDATE entries = entries + 1 ✓

  8. TRUNCATE TABLE table; DELETE FROM table ✓

  9. DELETE FROM table WHERE conditions ✓

  10. The WHERE conditions didn't match any row, or the new values are the same than the old ones ½ and also if the table is empty

  11. Because WHERE condition doesn't match NULL rows, and all the rows matched have the same value (1) for the grade column ✓

  12. true ✓

  13. false ✓

  14. false, only mysql ✓

  15. UPDATE personnel SET grade = 3 WHERE grade IS NULL ✓

  16. REPLACE INTO personnel SET grade = 4, unit = 45 WHERE pid = 10; ✓

  17. +------------+ | name | +------------+ | Lucy | | Macie | | Myra | | Cheep_!!! | | Lucy | | Myra | | Cheep | | Macie | | Pablo | | Stefan | +------------+ ✓

  18. yes ✓

  19. yes ✓

  20. UPDATE personnel SET unit = IF(unit=42, 23, 42) ✓

Total: 21/23

✗ ✓

12 JOINs

INNER JOINs

Obtiene filas que coinciden entre dos tablas. Dos formas equivalentes:

  1. ... FROM t1, t2 WHERE ... si no se especifica WHERE, producto cartesiano. Se puede prohibir con --safe-updates
  2. INNER JOIN

LEFT JOIN

  • Produce un resultado por cada fila de la tabla de la izquierda. Si no coincide con la tabla de la derecha aparece NULL..

Respuestas del test:

  1. Inner join ✗ any join can do it
  2. LEFT JOIN with a WHERE field IS NULL condition ✗ Outer JOINs = RIGHT and LEFT joins
  3. SELECT Country.Name, Language FROM Country, CountryLanguage WHERE Country.Code = CountryLanguage.CountryCode AND IsOfficial = 'T' ORDER BY Country.Code; ✓
  4. USING Is not possible bc the matching field does not have the same name in both tables. SQL: SELECT Country.Name, Language FROM Country INNER JOIN CountryLanguage ON Country.Code = CountryLanguage.CountryCode AND IsOfficial = 'T' ORDER BY Country.Code; ✓
  5. SELECT Country.Name, City.Name, City.Population FROM City INNER JOIN Country ON City.CountryCode = Country.Code AND Country.IndepYear IS NULL; ✓
  6. SELECT Country.Name, SUM(City.Population) FROM Country JOIN City ON City.CountryCode = Country.Code WHERE Country.IndepYear IS NULL GROUP BY Country.Code; ✓
  7. SELECT ... FROM City RIGHT JOIN Country. It returns a lot of results, does a full scan and takes much resources. Also, it is rarely useful. We specify some condition in the JOIN to reduce the results fetched by the SELECT. ✗ You can get a cartesian product with a FROM with comma operator and no WHERE statements. You can avoid them with --safe-updates
  8. ✗ It's always possible if there are only 2 tables
  9. When fields with the same name are in two or more JOINed tables. It's also useful for the SQL readibility. ✓
  10. When you are JOINing two tables with the same name in different databases. ✓
  11. ✗ With self-joins.
  12. 3, 4, 5 ✗ JOINs work for INSERT, UPDATE and DELETE. It IS possible to change data in more than 1 table when joining tables in UPDATE or DELETE
  13. SELECT cp.Name 'Country', Country.Name 'Other countries', Country.Continent, Country.SurfaceArea FROM Country JOIN Country cp ON Country.SurfaceArea > cp.SurfaceArea AND cp.Name = 'Paraguay' AND Country.Continent = cp.Continent; ✓
  14. SELECT cp.Name 'Country', Country.Name 'Other countries', Country.Population FROM Country JOIN Country cp ON Country.Population >= cp.Population AND cp.Name = 'Germany' ORDER BY Country.Population DESC;✓
  15. SELECT cp.Name 'Country', Country.Name 'Other countries', SUBSTRING(Country.Region, 1, 10) Region, Country.Population, Country.SurfaceArea FROM Country JOIN Country cp ON Country.Population >= cp.Population AND Country.SurfaceArea >= cp.SurfaceArea AND cp.Name = 'Nepal' ORDER BY Country.Population DESC; ✗ WHERE Country.region = cp.region
  16. 5*8 = 40, 8 ✓
  17. 6, 4 ✓
  18. SELECT client.name CLIENT, '' PROJECT, '' START, '' END FROM client LEFT JOIN project USING (cid) WHERE pid IS NULL; ✗ col vacías => NULL
  19. SELECT client.name CLIENT, project.name PROJECT, project.start START, project.end END FROM client JOIN project ON client.cid = project.cid AND YEAR(start) = 2003 ORDER BY start ✓
  20. SELECT client.name CLIENT, project.name PROJECT, project.start START, project.end END FROM client LEFT JOIN project ON client.cid = project.cid WHERE project.name = 'Intranet' ✓
  21. SELECT client.name CLIENT, project.name PROJECT, project.start START, project.end END FROM client INNER JOIN project ON client.cid = project.cid AND project.name = 'Intranet' ✓
  22. SELECT client.name CLIENT, project.name PROJECT, project.start START, project.end END FROM client INNER JOIN project USING (cid) WHERE project.name = 'Intranet' ✓
  23. SELECT client.name CLIENT, project.name PROJECT, project.start START, project.end END FROM client JOIN project USING (cid) ORDER BY client.name, project.start ✗ LEFT JOIN

Total: 14/23

13 Subqueries

Operadores de subquery:

    • ALL, ANY, SOME
  • IN
  • EXISTS
  • (campo1, campo2) = (subquery con 2 campos)

Se pueden usar subqueries en INSERT, UPDATE, DELETE, CREATE TABLE...SELECT, etc pero NO se puede hacer subquery sobre la tabla que está siendo modificada.

Respuestas del test:

  1. In any place where a scalar is expected: SELECT here FROM here WHERE here, UPDATE ... SET field = here... NOT in LIMIT statements ✓
  2. It's not, because the subquery can be performed independently from the outer. ✓
  3. SELECT * FROM Country c WHERE Continent = 'South America' AND Population = (SELECT MIN(Population) FROM Country WHERE Continent = c.Continent); ✓
  4. The Continent and Name of the country with the greatest population of each continent ✓
  5. The Continent and Name of the countries whose SurfaceArea is greater than the average surface area of their countries.✗ of any country
  6. SELECT * FROM Country WHERE SurfaceArea > ALL (SELECT SurfaceArea FROM Country GROUP BY Continent)
  7. SELECT DISTINCT Language FROM CountryLanguage WHERE CountryCode IN (SELECT Code FROM Country WHERE GovernmentForm LIKE 'Monarchy%') ORDER BY Language; ✓
  8. SELECT Name FROM Country c WHERE EXISTS (SELECT CountryCode FROM CountryLanguage WHERE Language = 'German' AND CountryCode = c.Code) ✓
  9. SELECT Population FROM City WHERE (Name, District, CountryCode) = ('Houston', 'Texas', 'USA'); ✓
  10. SELECT SUM(cl.Percentage * Population * .01) FROM (SELECT CountryCode, Percentage FROM CountryLanguage WHERE Language = 'German') cl, Country WHERE Country.Code = cl.CountryCode AND Country.Region = 'Western Europe'; ✓
  11. Because it uses a field FROM a table of the outer query. ✓
  12. ? raro raro raro lo que está pasando con MySQL.
  13. SELECT pid Project ID, project.name Project Name, id Client No, client.name Client Name FROM client LEFT JOIN project USING (id) ✗ project LEFT JOIN client WHERE client.name IS NOT NULL
  14. SELECT pid Project ID, project.name Project Name, id Client No, client.name Client Name FROM client RIGHT JOIN project USING (id) ✗ ...WHERE client.name IS NOT NULL
  15. SELECT pid Project ID, project.name Project Name, id Client No, client.name Client Name FROM client INNER JOIN project USING (id) ✗ project INNER JOIN client
  16. SELECT pid Project ID, project.name Project Name, id Client No, client.name Client Name FROM project LEFT JOIN client USING (id) WHERE client.id IS NULL ✓
  17. SELECT pid Project ID, project.name Project Name, id Client No, client.name Client Name FROM client LEFT JOIN project USING (id) WHERE client.id IS NULL ✗ RIGHT

Total: 10/18

14 Views

CREATE [OR REPLACE] [ALGORITHM = algorithm_type] VIEW view_name [(column_list)] AS select_statement [WITH [CASCADED | LOCAL] CHECK OPTION];

En vez de CREATE [OR REPLACE] se puede usar ALTER TABLE

  • Especificar explícitamente las columnas es útil para cuando hay nombres repetidos en el select_statement o este contiene funciones.

Algoritmos

  • MERGED: cuando se hace un SELECT sobre la view, MySQL mezclará las cláusulas del SELECT con las cláusulas del SELECT que define la view, y ejecutará la query sobre la tabla base.
  • TEMPTABLE: cuando se hace un SELECT sobre la view, MySQL guardará el resultado de la view en una tabla temporal, y posteriormente, ejecutará el SELECT sobre esta tabla temporal. Puede ser interesante usar TEMPTABLE para minimizar el bloqueo de tablas, ya que cuando se lanza un SELECT, la tabla base solo estará bloqueada hasta que haya sido volcada a la tabla temporal, mientras que con MERGED estará bloqueada hasta que toda la query haya sido procesada.
  • UNDEFINED: selección automática. Intentará elegir MERGED primero ya que es más eficiente.

UPDATEABILIDAD de las tablas

  • Cada fila de la vista debe corresponder a una fila de la tabla (por tanto, no agregación)
  • Las columnas deben ser definidas como referencias, no pudiendo contener ningún cálculo ni función
  • Para INSERTs, además, las columnas que no estén en la vista deben tener un valor DEFAULT

WITH CHECK OPTION

  • Los datos introducidos en INSERTs y UPDATEs deben cumplir las condiciones del select_statement, es decir, deben estar dentro de la vista

Si la vista está definida en base a otra(s) vista(s)...

  • WITH CASCADED CHECK OPTION (=WITH CHECK OPTION): hace esta comprobación en todas las vistas
  • WITH LOCAL OPTION: hace esta comprobación solo con las condiciones de la vista de primer nivel.

OTRAS COSAS

  • ALTER TABLE new_definition
  • DROP VIEW [IF EXISTS] vista [,vista2, ...]
  • SHOW CREATE TABLE, SHOW TABLE STATUS, SHOW FULL TABLES, SHOW COLUMNS y DESCRIBE funcionan con vistas, así como SHOW CREATE VIEW
  • Permisos: CREATE VIEW, DROP, SHOW VIEW si no se tiene permisos de SELECT sobre la tabla base

Respuestas del test:

  1. It can fullfill all the requirements of the updatable views but if the base table does not have a default value for all the fields that are not in the view definition, it can't be insertable ✗ if it has columns as expressions, it can also be updatable but not insertable
  2. updatable and insertable ✓ but UPDATEs and INSERTs can only affect to one table
  3. CREATE VIEW continents AS SELECT Continent, SUM(SurfaceArea), AVG(SurfaceArea) FROM Country GROUP BY Continent. It's not updatable because it contains aggregate data. ✓
  4. ✗ Summary tables has the advantage of performance, because it stores the table results when created (views have to query it each time), but data became obsolete (since data is not updated from base table automatically), where views always get latest data from table.
  5. MySQL raises a warning and the UNDEFINED algorithm is chosen instead of it. ✓
  6. a) view, b) table ✗ only view
  7. a) Include a column list, b) Provide column aliases in the view SELECT statement ✓
  8. a) ALGORITHM=TEMPTABLE, c) Use of aggregate functions, d) Use of GROUP BY or HAVING clauses in the view definition, e) Use of expressions like col = col + 1 in the view definition ✗ e) It depends on columns being updated
  9. Only for updatable views ✓
  10. Because TEMPTABLE creates non updatable views, and WITH CHECK OPTION is for updatable views only ✓

Total: 6/10

15 Importing and exporting data

LOAD DATA INFILE

LOAD DATA [LOCAL] INFILE ‘file_name’ [IGNORE | REPLACE] INTO TABLE table_name [format_specifiers] [IGNORE n LINES] [(column_list)] [SET (assignment_list)]

Inserta registros en la tabla indicada a partir de un fichero TSV.

  • LOAD DATA INFILE: fichero en servidor. La ruta del fichero se calcula a partir del directorio de la BD activa.
  • LOAD DATA LOCAL INFILE: fichero en cliente. La ruta del fichero se calcula a partir del directorio en que fue lanzado el cliente mysql.
  • IGNORE n LINES ignora las n primeras filas del TSV
  • Si el TSV tiene más columnas que la tabla, se omiten. Si tiene menos, se inserta el DEFAULT.
  • Se pueden especificar las columnas en las que se insertarán los datos del TSV en column_list
  • Duplicados: por defecto (inserta las filas correctamente hasta que se produce el duplicado), IGNORE (inserta todas las filas que no produzcan duplicado) y REPLACE (inserta todas las filas, reemplazando las que producen duplicado). En ficheros locales, IGNORE es el modo por defecto.

Para ficheros en servidor es necesario el permiso FILE

SELECT INTO OUTFILE

SELECT * INTO OUTFILE ‘file’ [format_specifiers] FROM mi_tabla ...;

  • Escribe fichero TSV en servidor, con propietario mysql y permisos de lectura para todos
  • El fichero no puede existir previamente

format_specifiers

FIELDS TERMINATED BY 'char' [OPTIONALLY] ENCLOSED BY 'char' ESCAPED BY 'char' LINES TERMINATED BY 'string'

  • Con OPTIONALLY solo se envuelven las cadenas
  • Valores null se exportan como "\N"

mysqlimport

mysqlimport options db_name input_file_a [input_file_b...]

Options son las mismas opciones de format_specifiers más LOCAL e IGNORE: --fields-terminated-by, --fields-escaped-by, --fields-enclosed-by, --lines-terminated-by, --local, --ignore

mysqldump

  • Con --tab=dir se guarda un TSV en dir con los contenidos de la tabla, y un SQL con el DDL, pero ¡OJO! el TSV se guarda en el servidor y el SQL en el cliente.
  • Con --no-create-info se omite el fichero
  • La cuenta debe tener permiso FILE para escribir ficheros en servidor
  • --databases y --all-databases no puede ser usado con --tab ya que solo se puede guardar 1 BD en TSV
  • Se pueden usar los mismos format_specifiers que mysqlimport

Respuestas del test:

  1. 0, N, NULL; \N \N \N ½ 0, N, 0000-00-00
  2. 'C:\Dokumente und Einstellungen\All Users\data for t.txt' ✓
  3. a) LOAD DATA INFILE 'more_contries.dat' INTO TABLE Country (Code, Name); b) Yes, because all the fields have a DEFAULT value. ✓
  4. FILE, SELECT, INSERT and UPDATE/REPLACE if REPLACE mode is selected ✗ FILE and access permissions to the file in the server
  5. mysqlimport ✓
  6. Tabs and \n ✓
  7. When file is in server, default is stop and raise an error when a duplicated is found. When file is in client, IGNORE is the default behavior. ✓
  8. ? ✗ there were 9 records in the file, and the 9 produced a duplicated resolved with REPLACE, and so there are 18 affected. Also, there were 2 problems importing the file.
  9. ? ✗ 9 lines in the file, and 9 caused a duplicated resolved by skipping them => 0 affected. Also, there were 2 problems.
  10. mysqlimport and mysql ½ mysql with LOAD DATA INFILE
  11. For multiple databases, tab format can't be used. We can use --databases or --all-databases option to export them in SQL format. ✓
  12. mysqldump --databases=a,b,c tbl1 tbl2 ✓
  13. LOAD DATA INFILE 'even_more_countries.dat' (Code, Name, @PopCity, @PopRural) INTO TABLE Country IGNORE 1 LINES (@skip, Code, Name, @PopCity + @PopRural) ✗ LOAD DATA INFILE 'even_more_countries.dat' INTO TABLE Country IGNORE 1 LINES (@unused, Code, Name, @PopCity, @PopRural) SET Population = @PopCity + @PopRural
  14. The directory of the active database ✓
  15. Every column ✓
  16. 0 ✓
  17. SELECT pid, unit INTO OUTFILE 'filename' FIELDS ENCLOSED BY '"' TERMINATED BY ';' LINES TERMINATED BY '\r\n' FROM personnel ORDER BY grade LIMIT 5

Total: 10/17

16 User variables

SET @a = 1; SET @a := 1; SELECT @a := 1;

Respuestas del test:

  1. 1st, 2nd and 5th ✓
  2. '@a is NULL' ✓
  3. 1, 1; 2, 2 ✓
  4. Storing them as server or user variables: SET USER @a = 1; SET SERVER @a = 1; ✗ NOT POSSIBLE

Total: 3/4

17 Prepared Statements

PREPARE nombre_del_stmt FROM 'SELECT ... WHERE a = ?';

SET @a = 1;

EXECUTE nombre_del_stmt USING @a;

DEALLOCATE PREPARE nombre_del_stmt; = DROP PREPARE nombre_del_stmt;

  • Al declararlo, se sobreescribe si ya existe
  • Sentencias preparables: SELECT, INSERT, UPDATE, REPLACE, DELETE, CREATE TABLE, CREATE VIEW, SET, DO, CALL, SHOW

Respuestas del test:

  1. Because if you need to execute a statement a number of times just changing paremeters, with prepared you save to parse, compile and process the parts of the statement that don't depend on parameters. ✓
  2. 2 ✗ 1
  3. Nothing. Prepared statements are per-session. ✓
  4. PREPARE s1 FROM 'SELECT Name FROM Country WHERE Continent = ? AND Population > ?'; SET @continent = 'Asia'; SET @pop = 100000000; EXECUTE s1 USING @continent, @pop; ✓
  5. Error. Prepared statement does not exist. ✓
  6. DEALLOCATE PREPARE stmt; DROP PREPARE stmt; No, it's removed when session is disconnected. ✓
  7. b, c, d, e, f ✓
  8. Nope ✓

Total: 7/8

18 Stored procedures

  • Incompatibles con replicación

  • Al contrario que funciones, no hay valor retornado y se pueden usar parámetros de salida, además de entrada

     delimiter //
    
     CREATE PROCEDURE my_procedure (parameters)
     [characteristics]
     BEGIN
       SELECT ...;
     END
     //
     
     
     CREATE FUNCTION my_func (parameters)
     RETURNS data_type
     [characteristics]
     BEGIN
       ...
       RETURN ...
     END
     //
    

El delimiter puede ser cualquiera distinto al delimiter por defecto (;)

characteristics := SQL SECURITY {DEFINER|INVOKER} Indica si la rutina se ejecutará con los permisos del usuario que la definió o los del que la invocó {DETERMINISTIC|NO DETERMINISTIC} Indica si es determinística o no LANGUAGE SQL Indica que la rutina está escrita en SQL. Impresionante. COMMENT 'comentario'

Tras la ejecución de una rutina, el sql mode es el que había cuando la rutina fue definida. De regalo.

BLOQUES

Los scopes se heredan en bloques anidados.

    ...
        bloque: BEGIN
          ...                
          LEAVE inner_block;    # Sale del bloque indicado
        END inner_block;
    ...

Declaración de parámetros

[IN|OUT|INOUT] nombre1 tipo1, [IN|OUT|INOUT] nombre1 tipo1, ...

La clásula [IN|OUT|INOUT] solo se aplica a procedures. Un parámetro de salida es aquel que puede ser accedido por el invocador. Si es OUT, inicialmente valdrá NULL y no se tendrá en cuenta en la invocación de la rutina.

DECLARE

Variables
    DECLARE var1, var2, ... DATATYPE [DEFAULT value]
  • Declara variables y condiciones, cursors y handlers, en ese orden
  • Los nombres son únicos por tipo
  • NO se usa el prefijo @ en las variables
Handlers
    DECLARE [CONTINUE|EXIT|UNDO] HANDLER FOR condition_type [, condition_type2] stmt;

La condition_type puede ser declarada previamente con:

    DECLARE condition_name CONDITION FOR condition_type

...donde condition_type := SQLSTATE 'num' | otra condition | SQLWARNING | NOT FOUND | SQLEXCEPTION

Por ejemplo,

    DECLARE null_no_permitido CONDITION FOR SQLSTATE '23000';
    DECLARE CONTINUE HANDLER FOR null_no_permitido SET salir = 1;
Cursores
    DECLARE nombre CURSOR FOR SELECT ...;

Los cursores operan sobre la query declarada, para lo cual primero se abre con OPEN y luego se accede a sus filas con FETCH

    OPEN nombre
    BEGIN
      DECLARE EXIT HANDLER FOR SQLSTATE '02000' BEGIN END
      LOOP
        FETCH nombre INTO variable1, variable2
        ...
      END LOOP
    END

Condicionales

    IF expr
    THEN
      [ELSE IF expr THEN ...]
      [ELSE ...]
    END IF;

    CASE expr
      WHEN val THEN ...
      WHEN val THEN ...
      [ELSE ...]
    END CASE;

    CASE
      WHEN expr THEN ...
      WHEN expr THEN ...
      [ELSE ...]
    END CASE;

Iteradores

Bucle infinito (necesita instrucción explícita de salida):

    [label:] LOOP
      ...
      LEAVE label;
    END LOOP [label];

Bucle con condición al final:

    [label:] REPEAT
      ...
    UNTIL expr
    END REPEAT [label];

Bucle con condición al principio:

    [label:] WHILE expr DO
      ...
    END WHILE [label:];

ITERATE label transfiere el control solo en iteradores

ALTER y DROP

Solo se pueden modificar las characteristics de un procedimiento o función:

    ALTER PROCEDURE procedimiento [characteristics];
    ALTER FUNCTION funcion [characteristics];

Para modificar otros aspectos (parámetros, cuerpo...) hay que eliminar y crear de nuevo la rutina.

    DROP PROCEDURE [IF EXISTS] nombre;
    DROP FUNCTION [IF EXISTS] nombre;

INVOCACIONES

  • Procedimiento: nunca desde una expresión. Siempre con CALL nombre();
  • Función: siempre desde una expresión: SELECT function();

Info y permisos

  • INFORMATION_SCHEMA.ROUTINES
  • SHOW PROCEDURE STATUS, SHOW FUNCTION STATUS
  • SHOW CREATE PROCEDURE, SHOW CREATE FUNCTION

Permisos:

  • CREATE ROUTINE
  • EXECUTE
  • ALTER ROUTINE
  • La cláusula ON puede ser usada sobre rutinas

Respuestas del test:

  1. Reuse code, traffic savings, more security, cleaner calls ½ more flexible syntax than "regular" SQL; exception handling
  2. Stored procedure ✓
  3. CREATE PROCEDURE world.world_before_count(); ✓
  4. Specifying the characteristic SQL SECURITY INVOKER ✓
  5. 1 true, 2 true, 3 only if SQL SECURITY DEFINER characteristic is declared ✓
  6. 2 and 3 ✗ only 2
  7. Nope, they cause a duplicate ✓
  8. Yes, since they are different type of DECLAREs ✓
  9. No, read only ✓
  10. DECLARE IGNORE name HANDLER FOR exception_type ...; ✗ CONTINUE with an empty block (BEGIN END)
  11. LOOP, REPEAT, WHILE ✓
  12. REPEAT ✓
  13. WHILE ✓
  14. The inner block ✗ the outer one, because it's the block in which the handler was defined
  15. SHOW CREATE PROCEDURE world.world_record_count ½ also in INFORMATION_SCHEMA.ROUTINES
  16. SQL SECURITY and COMMENT ✓
  17. d) Infinite loop, because is NULL, and NULL + 1 = NULL => it never reaches the exit condition ✓

Total: 12/17

19 Triggers

    CREATE TRIGGER nombre
    {BEFORE|AFTER}
    {INSERT|UPDATE|DELETE}
    ON tabla
    FOR EACH ROW
    sentencia

La sentencia puede contener bloque BEGIN-END

Restricciones:

  • No puede usarse CALL en triggers
  • No puede empezar/terminar transacciones
  • No se pueden crear triggers sobre TEMPORARY TABLEs o vistas
  • Ojo con la replicación! Igual que con rutinas

OLD.columna, NEW.columna

  • DROP TRIGGER
  • Un trigger es eliminado automáticamente cuando se borra la tabla a la que afecta

Permisos: SUPER (5.0), CREATE TRIGGER (5.1), UPDATE (para cambiar valores de las columnas)

Respuestas del test:

  1. No limit ✗ 6: before|after insert|update|delete (2*3)
  2. 10 times, one for each new row inserted ✓
  3. Wrapping all the operations in a BEGIN-END block ✓
  4. No. Namespace is db ✓
  5. OLD are read-only and can be used in UPDATE and DELETE. NEW are read-write, and can be used in INSERT and UPDATE triggers ✓

Total: 4/5

2 The mysql client program

  • mysql -e "comando SQL"
  • ; y \g son equivalentes.
  • \G es un terminador pero también hace que los resultados se muestren horizontalmente.
  • El prompt estándar es mysql>. -> espera la siguiente línea de la sentencia, y '>, "> ``>y/*>` esperan cierres de los símbolos correspondientes.
  • Cargar un batch: SOURCE fichero (sin comillas) o desde la shell, mysql < fichero.
  • Cuando se carga un batch, un error detendrá el procesamiento. Para seguir a pesar de errores, mysql -f.
  • Los batches pueden contener sentencias SOURCE, pero cuidado con las referencias circulares.
  • Los batches imprimen la salida en tablas separadas por tabuladores, no como en el modo interactivo.
  • -B fuerza salida con tabuladores, -t en forma de tabla (como en el modo interactivo), -H en HTML y -X en XML
  • Comandos propios del mysql interactivo: CLEAR, EXIT, SOURCE, STATUS, HELP. No se pueden usar en sentencias de varias líneas a no ser que se invoque mysql --named-commands.
  • --i-am-a-dummy es sinónimo de --safe-updates, el cual evita SELECTs de más de 1000 filas y de más de 1M de filas examinadas en los SELECT de múltiples tablas, así como UPDATEs o DELETEs en los que no se identifique los registros a alterar, o no incluyan LIMIT.

Respuestas del test:

  1. mysql -h db.myexample.com -u juan -p -D world < /tmp/queries.sql ✓
  2. \G
  3. ');, \c'\c hay que cerrar las comillas simples
  4. USE test; SOURCE /tmp/tbl_import.sql;, mysql -D test < /tmp/tbl_import.sql, USE test; SOURCE /tmp/tbl_import.sql; ✗ el último es mysql --force test < /tmp/tbl_import.sql
  5. \c [+ ENTER key] ✓
  6. 1, 2 ✓

Total: 4/6

20 Metadata

Tablas en INFORMATION_SCHEMA
  • CHARACTER_SETS
  • COPLLATIONS
  • COLLATION_CHARACTER_SET_APPLICABILITY
  • COLUMNS
  • COLUMN_PRIVILEGES
  • KEY_COLUMN_USAGE
  • ROUTINES
  • SCHEMATA
  • SCHEMA_PRIVILEGES
  • STATISTICS
  • TABLES
  • TABLE_CONSTRAINTS
  • TABLE_PRIVILEGES
  • TRIGGERS
  • USER_PRIVILEGES
  • VIEWS

Todas son read-only

SHOW y DESCRIBE
  • SHOW DATABASES
  • SHOW TABLES [FROM database]
  • SHOW [FULL] COLUMNS FROM tabla
  • SHOW KEYS (índices)
  • SHOW CHARACTER SET
  • SHOW COLLATION
  • DESCRIBE

En todos se puede usar WHERE

En DATABASES, TABLES y COLUMNS puede usarse LIKE 'patron'

mysqlshow

CLI para SHOW

mysqlshow [options] [database] [tabla] [columna]

  • Si no se especifica un objeto, se describirá el de nivel superior.
  • Especificando una tabla y la opción --keys, se muestran los índices de la tabla
  • Si el nombre de la BD, tabla o columna es un patrón entrecomillado, se interpretará como LIKE

Respuestas del test:

  1. mysqlshow test 'my%' ✓
  2. mysqlshow --keys test mytable. No. ✓
  3. mysqlshow --keys buildings, mysql -c "DESC buildings" ✓
  4. mysqlshow 'w%'; SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME LIKE 'w%'; ✓
  5. mysqlshow world; SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLE WHERE TABLE_NAME; ✗ WHERE TABLE_SCHEMA = 'world'
  6. mysqlshow world 'C%'; SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'world' AND TABLE_NAME LIKE 'C%'; ✓
  7. mysqlshow world City; SELECT COLUMN_NAME FROM COLUMNS WHERE TABLE_NAME = 'City' AND TABLE_SCHEMA = 'world'; ✓
  8. mysqlshow --keys world City; SELECT KEY_NAME FROM KEYS WHERE TABLE_NAME = 'City' AND SCHEMA_NAME = 'world'; ✗ FROM KEY_COLUMN_USAGE WEHERE TABLE_SCHEMA = 'world' AND TABLE_NAME = 'City'
  9. SHOW CHARACTER SET ✗ SELECT * FROM INFORMATION_SCHEMA.CHARACTER_SETS
  10. SELECT * FROM INFORMATION_SCHEMA.CHARACTER_SET_COLLATION_APPLICABILITY; ✓
  11. SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'INFORMATION_SCHEMA'; ✓

Total: 8/11

21 Debugging

Respuestas del test:

  1. With perror. 13 is permission denied. ✓
  2. WARNING, ERROR, NOTE. SHOW WARNINGS ✓
  3. a) false, b) false, c) false, d) false, e) true ✓
  4. a) false, b) true, c) false, d) false, e) true ✓
  5. Because SHOW ERRORS shows only errors, no warnings ✓

Total: 5/5

3 MySQL Query Browser

Respuestas del test:

  1. None ✗ both can create databases and tables
  2. Issue a query and then click on create view ✗ Enter a CREATE VIEW statement and click Execute is another valid method
  3. Writing the query in the query window or dragging and dropping tables into the query window ✗ dbl click on a table works as well
  4. Foreign key declarations ✓
  5. mysql ✗ it is the database against which all the queries will be done by default
  6. Ctrl-E, click "run" or selecting a running option ✓
  7. UPDATE privileges for the connected user ✗ the resultset must be from a single table and have a PK
  8. ✗ add a new tab, split horizontally or split vertaically
  9. ✗ you can click on "compare" to compare two resultsets
  10. Ctrl-F ✗ click on Search
  11. You can do it with MySQL Query Browser ✗ you can do it with both
  12. true, false, true, true ✗ false, false, false, true
  13. ✗ false, true, true

Total: 2/13

4 MySQL connectors

Respuestas del test:

  1. a ✓
  2. true, false, false, true, false ✗ false, falase, false, true, false
  3. false. It works under Mono on Linux and Mac too ✓
  4. false. Java and .NET connectors are implemented in Java and .NET, respectively ✓
  5. false. Only the libmysqlclient is written and C. Java and .NET connectors are implemented in Java and .NET, respectively ✓

Total: 4/5

5 Data Types

  • b'01010101' para valores binarios (cualquier type)
  • 3 tipos de data types: numéricos, cadenas y temporales
  • BLOB are treated as strings

Numeric types

  • TINYINT (1)

  • SMALLINT (2)

  • MEDIUMINT (3)

  • INT (4)

  • BIGINT (8)

  • FLOAT (4) single-precision (precision, decimal digits) (default by hardware)

  • DOUBLE (8) double-precision (idem)

  • DECIMAL (precision, decimal digits). Fixed point, no rounding errors.

  • BIT (l+7/8), por ejemplo, un BIT(9) ocupa 2 bytes

Strings

  • CHAR (max 255), fixed length, trailing spaces ignored

  • VARCHAR (max 65535)

  • TINYTEXT (255) / TEXT (65535) / MEDIUMTEXT (16M) / LONGTEXT (4G)

  • BINARY (max 255), fixed length, trailing spaces ignored

  • VARBINARY (max 65535)

  • TINYBLOB (255)/ BLOB (65535) / MEDIUMBLOB (16M) / LONGBLOB (4G)

  • ENUM (65535 members) - it's possible to use internal values WHERE enum_field = 1 (first member)

  • SET (64 members) length depending on # of members

  • Collations can be accent-in/sensitive and case-in/sensitive. Binary collations are both accent-sensitive and case-sensitive.

  • Binary collations differ from binary string because binary string comparisons are always made per-byte, and collations per-character (mb).

  • En campos mb de longitud fija, la longitud es la máxima posible (por ejemplo, 3bytes para utf8).

  • Si se intenta introducir un valor no válido en un ENUM, se guardará internamente 0, representado por '' (cadena vacía).

  • Si se intenta introducir un valor no válido en un SET, simplemente se omitirá.

Temporal

  • DATE (3, 1000-01-01 - 9999-12-13) format: ISO 8601, but you can omit leading zeros, use / as separator and enter Year with 2 digits.
  • TIME (3, -838:59:59 - 838:59:59) format: ISO, but you can omit leading zeros
  • DATETIME (8 1000-01-01 00:00:00 - 9999-12-31 23:59:59)
  • YEAR (1) you can specify display length (2 or 4).
  • TIMESTAMP (4) 1-1-1970 0:0:0 - 2037, DEFAULT CURRENT_TIMESTAMP, ON UPDATE CURRENT_TIMESTAMP, por defecto ambos atributos están activos en el primer campo TIMESTAMP de la tabla. ¡Ojo! No puede haber más de un campo con CURRENT_TIMESTAMP. Si un campo TIMESTAMP tiene DEFAULT 0, al hacer un INSERT con NULL, en vez de NULL se insertará al fecha/hora actual, así que es una forma de saltarse la restricción de 1 solo campo con CURRENT_TIMESTAMP por tabla. Si un campo TIMESTAMP permite NULL, su default pasará a ser NULL en lugar del CURRENT_TIMESTAMP.

Timezones

  • Nomenclaturas
  • Signed offset: +/-hh:mm, por ejemplo, +01:00 para Madrid
  • Named timezone: por ejemplo, US/Western. Necesita las tablas de timezones en la BD mysql.
  • SYSTEM: tomar el huso horario del sistema operativo. Es el huso por defecto.
  • Variable time_zone (global/session).
  • Función CONVERT_TZ()

Atributos

  • Si se introduce un valor negativo en un campo UNSIGNED, se guardará 0.
  • Los campos ZEROFILL se hacen automáticamente UNSIGNED.
  • AUTO_INCREMENT solo se puede aplicar a enteros NOT NULL que sean PK o UNIQUE. Si se inserta un valor concreto en un campo AUTO_INCREMENT, el contador se situará en ese valor + 1
  • Si se inserta 0 en un campo AUTO_INCREMENT, se guardará el auto-incremental que corresponda, a no ser que el modo NO_AUTO_VALUE_ON_ZERO esté activado.
  • MyISAM permite una PK combinada con un campo AUTO_INCREMENT, en cuyo caso se crearán tantas secuencias como valores distintos haya del campo no-autoincremental.
  • CHARACTER SET = CHARSET
  • COLLATE (collation)
  • BINARY es un atributo que especifica collation binario.
  • DEFAULT no se puede aplicar a TEXT, BLOB ni campos AUTO_INCREMENT.
  • Si no se especifica en DEFAULT, el valor por defecto es 0 para números, '' para cadenas, el primer miembro para ENUMs y 0000-00-00 00:00:00 para fechas (excepto TIMESTAMP, solo si son DEFAULT 0).
  • PRIMARY KEY y UNIQUE crean sendas claves. Prohibido para cammpos TEXT y BLOB.

Valores inválidos y por defecto

  • En campos sin DEFAULT, si el strict mode no está activado, se aplicará el valor por defecto para el tipo de campo. Por ejemplo, 0 en INTs. Si el strict mode está activado, lanzará error. En tablas transaccionales se hará rollback, y en no transaccionales se insertarán los valores anteriores al causante del error.
  • En ENUM, si el valor no está definido, se insertará ''.
  • En SET, si un valor no está definido, pero otros sí, se descartará el no definido y se insertarán los válidos.
  • Al transformar un campo SET en ENUM, no se mantienen los miembros. Al transformar ENUM en SET, .
  • Al transformar un campo NULL en NOT NULL, los valores NULL se convertirán en el valor por defecto para el data type.
  • Al insertar NULL en campos NOT NULL, si la inserción es simple, da error. Si es múltiple, asignará el valor por defecto para el data type. Esto es así en cualquier circunstancia de valor inválido para evitar actualizaciones parciales en tablas no transaccionales, a no ser que se active el modo sql STRICT_ALL_TABLES, que lanzará error cuando haya un valor inválido siempre.
  • La conversión automática de cadena a fecha solo funcionará si se respeta el formato YYYY-MM-DD
  • Una fecha no válida, por ejemplo, 2009-02-31, se transforma en 0000-00-00 en modo no estricto, y lanza un error en modo estricto.
  • El modo sql NO_ZERO_DATE lanza error al recibir un valor temporal 0000-00-00
  • El modo sql NO_ZERO_IN_DATE lanza error al recibir un valor temporal con ceros en algún componente de la fecha. Con el modo sql ALLOW_INVALID_UPDATES se desactiva esta comprobación.
  • ERROR_FOR_DIVISION_BY_ZERO, NO_ZERO_DATE y NO_ZERO_IN_DATE solo funcionan en modo estricto.
  • TRADITIONAL es el modo sql más restrictivo, y es una combinación de NO_ZERO_DATE, NO_ZERO_IN_DATE y ERROR_FOR_DIVISION_BY_ZERO.
  • Con INSERT IGNORE y UPDATE IGNORE se eliminan silencian los errores de validación para una sola sentencia.

Respuestas del test:

  1. DECIMAL ✓
  2. VARCHAR(100) ½ in the special case where all the values are 100 chars long, CHAR will be more efficient
  3. Using a case-sensitive collation, e.g. utf8_spanish_cs ✓
  4. In a multi-byte character set, one character might allocate more than 1 byte. ½ binary strings have no charset nor collation.
  5. MEDIUMINT UNSIGNED, whose maximum value is ~16M. It requires 3 bytes. ✓
  6. VARCHAR(2000). It requires 302 bytes, because values longer than 256B take 2B for field length. ½ TEXT is valid as well
  7. 1001-01-01 ✗ 1000-01-01
  8. 10-02-2008, WARNING or ERROR if STRICT_MODE is applicable ✗ 2010-02-08, 2069-12-31, 1970-01-01
  9. NULL, since it's not a valid date. ✗ ERROR in NO_ZERO_DATE mode, 2012-00-00 if NO_ZERO_DATE is not enabled because "12" is understood
  10. a, b, d ✗ DOUBLE takes 8 bytes, whereas DECIMAL just 4
  11. b, c ✓
  12. 10 bytes if a single-byte character set is chosen or the widest character of the charset if a multi-byte one in chosen. ✓
  13. No, MySQL will allocate 3 bytes per char, allowing any utf8 value to be stored, and keeping the field fixed-length. ✓
  14. No, it's not true. By default, charset and collations are taken from the table, but it can be declared for each field independently. ✓
  15. No, it doesn't. ✓
  16. No, it's not true, because binary strings store bytes, and non-binary strings store characters, which makes a difference on mb charsets. ✓
  17. d ✓
  18. a, b, c, d ✗ c is false. Timestamps are stored in UTC.
  19. Yes, it has the default behavior, which is DEFAULT CURRENT_TIMESTAMP, ON UPDATE CURRENT_TIMESTAMP. To override it, declare the field with DEFAULT NULL or another DEFAULT value. ✗ Pregunta mal entendida: se trata de declarar ESE comportamiento explícitamente
  20. It will store current timestamp in a) and c), and 1970-01-01 00:00:00 in b) ✗ b) and c) will throw error
  21. 12 ✓
  22. 2^8 = 255 if it's UNSIGNED. If not, 127 ✗ 127, because not UNSIGNED clause was specified
  23. MEDIUMBLOB, VARCHAR(250) ✓
  24. 2000+2 ✓
  25. SELECT @@global.time_zone, SELECT @@session.time_zone, SET time_zone='+01:00', SELECT @@session.time_zone ½ SET SESSION time_zone
  26. c ✗ d) because changing the server's timezone doesn't affect the stored values, which are always stored in UTC.
  27. SELECT LAST_INSERT_ID(), the same value because LAST_INSERT_ID() only affects to those rows entered by the current user. ✓
  28. The second row will have the values (0, '') because they are the intrinsic default values for those data types. ✗ (0,0)
  29. yes ✓
  30. TIMESTAMP NULL DEFAULT NULL ½ TIMESTAMP NULL
  31. When not specified, it stores the current time and date by default. ✓
  32. When the row is updated and a value for the TIMESTAMP field is not specified, the current timestamp is stored. ✓
  33. updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, created TIMESTAMP DEFAULT CURRENT_TIMESTAMP ✗ created TIMESTAMP DEFAULT 0, updated TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
  34. SET time_zone='-05:00'; ✓
  35. a ✓
  36. STRICT_ALL_TABLES, non-transactional table. ½ STRICT_TRANS_TABLES. Si fuese ALL_TABLES no habría continuado tras el error
  37. (1, 0001), (10000, 10000) ✓
  38. (1, 22 as character, ?) ✗ (1, '22', 0000-00-00)
  39. (255, 'yoodo', 1001-12-31) because 1000 is truncated to unsigned TINYINT max value, 'yoodoo' truncated to 5 chars and 999 to its closest valid value (1000) ✗ (255, 'yoodo', 0000-00-00)
  40. (null, null, null) ✓
  41. (0, the character #10, null) ✗ (0, '10', 0000-00-00)
  42. (0, 0, '2000-02-29') ✗ (0, '-1', 0000-00-00)
  43. False. It's the opposite: one collation belongs to exactly one charset. One charset can have many collations, e.g. utf -> utf8_spanish_ci, utf8_swedish_ci ✓
  44. d ✓
  45. With the function DATE_FORMAT() ½ ...and TIME_FORMAT()
  46. ts1 TIMESTAMP DEFAULT NULL ✗ ts1 TIMESTAMP NULL
  47. NULL, since the field is declared as NULL ✓
  48. NULL, since it is the default value ✗ 0000-00-00 because 'string' is an invalid DATETIME value, so zero is inserted instead.
  49. ✗ 2020-02-02 08:21:39
  50. ✗ 2002-02-08 21:39:00
  51. ✗ 0000-00-00 00:00:00
  52. 2002-02-28 23:59:59 ✗ 0000-00-00 00:00:00
  53. 'Lennart', since NULL is treated as ''. ✗ NULL, because anything concatenated with NULL results in NULL
  54. '1 plus 1 equals 2' ✓
  55. 2, since ' equals 2' is converted to 0 ✓
  56. 3.1, since '1.1 equals GUESS!' is converted to 1.1 ✓
  57. 1, since NULL is converted to 0 ✗ NULL, because any arithmetic operation with NULLL results in NULL
  58. Africa, 0 ✗ 1
  59. NULL, NULL ✗ '', 0
  60. NULL, NULL ✗ '', 0 because it's not valid
  61. Africa ✗ '', 0 because it's not valid
  62. America ✗ 'Africa', 1 because Africa is the #1 member
  63. NULL ✗ 'Africa', because MySQL converts '1' to 1, which corresponds to Africa
  64. NULL ✓
  65. col1=NULL, col2=0, col3=42 since they are their defaults ✓
  66. col4=NULL, col5='', col6='yoo' ✓
  67. col7=NULL, col9='' ✓
  68. col9='00:00:00' ✓
  69. col10=NULL, col11='0000-00-00', col12='2002-02-08' ✓
  70. col13=NULL, col15='' ✗ col15='doo' because it's the first member
  71. col14=NULL, col16='' ✓
  72. Since it's AUTO_INCREMENT, it can be executed until maximum TINYINT value (127) is reached. Then, an error occurs because of duplicated primary key (127) ✓

Total: 38.5/72

6 Identifiers

  • Unquoted: letras, números, _ y $ (NO digitos solamente, NO expresiones como 1e5 o 0x1)
  • Quoted: cualquier carácter, excepto ascii(0) y ascii(255). NO espacio solo. NO . \ y / en nombres de BBDD y tablas
  • Todos los identificadores son case-insensitive, excepto los de BBDD y tablas, que obedecen al SO, aunque LOWER_CASE_TABLE_NAMES hace que sean case-insensitive también.
  • Los campos se pueden identificar con qualified names completos: bd.tabla.campo. Los triggers y procedimientos almacenados también se pueden calificar.
  • Se entrecomilla con ` o ' y si ANSI_QUOTES está activado, con "
  • No se deben usar nombres de funciones porque algunos coinciden con palabras reservadas y porque si IGNORE_SPACE está activado, expresiones con paréntesis podrían ser ambiguas, e.g. INSERT INTO COUNT (id) ...
  • Las palabras reservadas y nombres de funciones son case-sensitive.

Respuestas del test:

  1. a ✗ b
  2. a) only with ansi_quotes, b) idem, c) yes, d) only with ansi_quotes ✗ a) fail b), c) and d) succeed
  3. error. it must be quoted ✓
  4. succeed ✓
  5. succeed ✗ single quotes can be used for alias, but not table or DB names
  6. succeed ✓
  7. error ✓
  8. error ✗ error if IGNORE_SPACE is enabled
  9. succeed ✓
  10. succeed ✓
  11. succeed ✗ succeed only if the SO supports that characters
  12. succeed ✓
  13. succeed ✓
  14. It seems like database was created in a Windows server and moved to a UNIX one later. To solve it, enable LOWER_CASE_TABLE_NAMES. To prevent it, use consistent identifiers. ✓

Total: 9/13

7 Databases

  • Cada database directory contiene un fichero db.opt con propiedades como charset y collation.
  • No hay límite de BBDD
  • CREATE DATABASE [IF NOT EXISTS] nombre [CHARACTER SET charset] [COLLATE cotejamiento]
  • ALTER DATABASE [nombre] [CHARACTER SET charset] [COLLATE cotejamiento] si no hay nombre se aplica a la BD en uso
  • DROP DATABASE [IF EXISTS] nombre
  • SHOW CREATE DATABASE nombre
  • INFORMATION_SCHEMA.SCHEMATA.SCHEMA_NAME

Respuestas del test:

  1. c ✓
  2. b ✓
  3. b, d ✓
  4. DROP DATABASE test. No, there's no undo. ✓
  5. false ✓
  6. SHOW CREATE DATABASE [name], SELECT DEFAULT_CHARACTER_SET, DEFAULT_COLLATION_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '[name]' ✓
  7. true ✓
  8. CREATE DATABASE IF NOT EXISTS [name] ✓
  9. DROP DATABASE IF NOT EXISTS ✗ IF EXISTS

Total: 8/9

8 Tables and Indexes

  • Every table has a tablename.frm format file. Data files depend on storage engine:
    • MyISAM: tablename.MYD for data and tablename.MYI for indexes
    • InnoDB: multiple tables share the same files (tablespaces)
    • MEMORY: data not stored in files, but in memory
  • SHOW ENGINES
  • Límites: los del sistema operativo. Para evitarlos, se pueden usar tablas MERGE para unir varias tablas MyISAM, así como cambiar de FS o SO.
  • CREATE TABLE [IF NOT EXISTS] [bd.]nombre (campos, indices) ENGINE = motor
  • ALTER TABLE t ENGINE = motor
  • La variable storage_engine especifica el motor por defecto
  • Si al crear una tabla se especifica un motor no válido (por ejemplo, uno obsoleto), se asigna el motor por defecto y se lanza warning
  • CREATE TABLE nombre SELECT ... crea una nueva tabla con los campos del SELECT, pero no copia índices, PK ni AUTO_INCREMENT
  • CREATE TABLE nombre LIKE origen es como CREATE TABLE SELECT pero sí copia índices, PK y AUTO_INCREMENT. Sin embargo, NO copia foreign keys

Tablas temporales

  • CREATE TEMPORARY TABLE (misma sintaxis)
  • Se crean para cada sesión, por lo que distintos clientes pueden crear tablas temporales con el mismo nombre
  • Se puede crear una tabla temporal con el mismo nombre que una no-temporal, en cuyo caso la no-temporal quedará invisible durante la sesión
  • No se puede usar RENAME TABLE con tablas temporales, sino solo ALTER TABLE

ALTER

  • ALTER TABLE tabla DROP campo
  • ALTER TABLE tabla ADD definición_de_nuevo_campo [AFTER|BEFORE] campo_existente
  • ALTER TABLE tabla MODIFY campo definición_de_campo
  • ALTER TABLE tabla CHANGE campo nuevo_nombre definición_de_campo
  • ALTER TABLE tabla RENAME TO nuevo_nombre = RENAME tabla TO nuevo_nombre
  • ALTER TABLE operacion1, operacion2, operacion3 ... donde operacion es una de las operaciones anteriores

Eliminación

  • DROP TABLE t1, t2, ...
  • DROP TABLE IF EXISTS t1 (si t1 no existe, lanza warning)
  • DELETE FROM tabla
  • TRUNCATE tabla

Índices

  • Tres tipos: PRIMARY, UNIQUE, INDEX. Otros dos tipos adicionales, FULLTEXT y SPATIAL, no entran en el examen
  • CREATE TABLE nombre ( definición_de_campo1, PRIMARY KEY|UNIQUE|INDEX [nombre] (campo1) )
  • El campo con PRIMARY KEY debe ser NOT NULL
  • Campos UNIQUE pueden ser NULL, y contener varias filas con el valor NULL para el campo UNIQUE
  • También se puede especificar en le definición del campo: CREATE TABLE tabla (campo INT NOT NULL [PRIMARY KEY|UNIQUE])
  • Las PRIMARY KEY no tienen nombre nunca.
  • ALTER TABLE tabla ADD PRIMARY KEY|UNIQUE|INDEX [nombre] (campo)
  • CREATE [UNIQUE] INDEX [USING HASH|BTREE] nombre ON tabla (campo) (es obligatorio el nombre)
  • INDEX USING [HASH|BTREE] (campo) algoritmos: HASH (por defecto, mejor con valores únicos) o BTREE (mejor con valores repetidos)
  • Los algoritmos de indexación solo están disponibles en tablas MEMORY
  • DROP INEX indice ON tabla = ALTER TABLE tabla DROP INDEX indice, donde indice puede ser PRIMARY para PK.

Ver metadatos de las tablas

  • SHOW TABLES [FROM database] [LIKE 'patron']
  • SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
  • SHOW CREATE TABLE tabla
  • DESCRIBE tabla = SHOW FIELDS FROM tabla = SHOW COLUMNS FROM tabla
  • SHOW INDEX FROM tabla

Respuestas del test:

  1. false, there's a limit of 2,000,000,000 tables in the same tablespace ✓
  2. true ✓
  3. ALTER TABLE DROP PRIMARY KEY; DROP INDEX PRIMARY; ✗ DROP INDEX PRIMARY ON table;
  4. PRIMARY, UNIQUE, INDEX ✗ faltan FULLTEXT y SPATIAL
  5. The field must be NOT NULL, because UNIQUE indexes can contain multiple NULL values ✓
  6. DROP TABLE IF EXISTS table; it will raise a warning ✓
  7. true ✓
  8. false; they are empty by default ✓
  9. false; you can specify the database in the name of the new table: CREATE TABLE database.table ✓
  10. CREATE TABLE IF NOT EXISTS table ...
  11. It has no comma between PRIMARY KEY and name CHAR(10) ✓
  12. CREATE TABLE test.City SELECT * FROM World.City; CREATE TABLE test.City LIKE SELECT * FROM World.City; ✗ CREATE TABLE test.City LIKE world.City; INSERT INTO test.City SELECT * FROM world.City;
  13. true ✓
  14. false, to add rows you must use INSERT ✓
  15. true ✓
  16. false ✓
  17. RENAME TABLE a TO b; ALTER TABLE a RENAME TO b; ✓
  18. Performance (faster lookups), avoid equal values and identifying rows uniquely ✓
  19. yes, because the key can be unique if the other field is NOT NULL ✗ all PK fields must be NOT NUll
  20. ALTER TABLE mytable ADD col0 INT before col1, ADD col2 INT after col1, ADD col4 INT AFTER col3 ✓ "AFTER col3" sobra, y "before col1" puede ser FIRST
  21. SHOW INDEXES FROM table; SHOW CREATE TABLE table; ✗ SHOW INDEX FROM tbl, no "indexes"
  22. CREATE TABLE tbl (col1 INT NOT NULL, col2 INT NOT NULL, PRIMARY KEY(col1, col2)); ✓
  23. TRUNCATE TABLE tablename; ✓
  24. SHOW TABLES FROM test LIKE '%test%'; SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE '%test%'; ✗ AND TABLE_SCHEMA = 'test'
  25. SHOW COLUMNS FROM test.mytest LIKE 'id%'; SHOW FIELDS FROM test.mytest LIKE 'id%'; ✓
  26. SHOW CREATE TABLE test.mytest; ✓
  27. The default engine has been changed in the storage_engine variable. You can append ENGINE=MyISAM at the end of the CREATE TABLE statement to make sure that MyISAM is used for the table. ✓
  28. SET GLOBAL storage_engine = InnoDB; ✓
  29. Using a MERGE table with MyISAM tables; upgrading the file system; upgrading the operating system ✗ falta pasar de MyISAM a InnoDB
  30. ALTER TABLE tbl DROP INDEX idx_id; ALTER TABLE tbl ADD INDEX idx_id (id); ✓
  31. UNIQUE admits NULL values, even in more than 1 row; UNIQUE cannot be used with AUTO_INCREMENT; there can't be more than one AUTO_INCREMENT index on a table ✓
  32. PRIMARY KEY ✓
  33. You cannot create a table with no engine. If you don't specify it, it will be created with the default engine. If you want to change it later, you can do it with ALTER TABLE table ENGINE = engine_name; ✓ habla de bases de datos, no de motores!!!
  34. CREATE TABLE mytbl (col1 INT(10) UNSIGNED NOT NULL DEFAULT 0 PRIMARY KEY, col2 CHAR(50) NOT NULL UNIQUE, col3 CHAR(50) NOT NULL INDEX); ✓
  35. true ✓
  36. true ✓
  37. ALTER TABLE table ADD COL [type]; ✗ column names must be unique regardless of lettercase
  38. no, a UNIQUE index admits several NULL values ✓
  39. ALTER TABLE mytable ADD PRIMARY KEY (col1, col2); ✓
  40. An auto-generated INDEX name is assigned ✓ you have to specify a name if you use CREATE INDE
  41. no ✓
  42. ✗ RENAME TABLE t_archive TO t_archive_lastyear, t_active TO t_archive, t_template TO t_active;
  43. You can't rename temporary tables ✓
  44. SHOW TABLES FROM test; ✓
  45. SHOW COLUMNS FROM test.mytest; ✓
  46. The MySQL server was compiled without InnoDB, but since it is a valid engine name, it doesn't cause an error. ✗ ...or it was disabled at startup
  47. Changing the storage_engine option when launching the server or in my.cnf ✗ only in startup (although startup command can be stored in a file)
  48. SET storage_engine = InnoDB ✓

Total: 36/48

9 Querying for Data

  • Los alias pueden llevar comillas sencillas, dobles o tildes.
  • Los alias no se pueden usar en los WHERE
  • SELECT DISTINCT distingue los duplicados de cadenas aplicando el collation que toque.
  • COUNT(DISTINCT campo)
  • WITH ROLLUP aplica la función de agregación (COUNT, MAX, MIN, SUM) a todos los elementos
  • UNION puede unir tablas heterogéneas, siempre y cuando los SELECT tengan el mismo número de columnas. El tipo de las columnas finales será el menos restrictivo.
  • Con UNION, se puede usar ORDER BY en el resultset total si se pone también LIMIT

Respuestas del test:

  1. SELECT d FROM t ORDER BY d ASC; SELECT d FROM t ORDER BY d DESC; ✗ SELECT MIN(d) FROM t; SELECT MAX(d) FROM t;

  2. SELECT * FROM t ORDER BY d ASC; SELECT * FROM t ORDER BY d DESC; ✗ ...LIMIT 1

  3. SELECT Name FROM Country WHERE IndepYear IS NOT NULL ORDER BY IndepYear DESC; SELECT Name FROM Country WHERE IndepYear IS NOT NULL ORDER BY IndepYear ASC; ✗ ...LIMIT 1, ...LIMIT 1

  4. FROM, WHERE, GROUP BY, HAVING, ORDER BY, LIMIT ✓

  5. All except FROM ✓

  6. SELECT fields FROM world.City ✓

  7. SELECT * FROM City WHERE substr(Name, 0, 1) BETWEEN 'B' AND 'F' AND substr(Name, 0, 1) BETWEEN 'K' AND 'M' AND Population > 1000000 ORDER BY Name ASC; ✗ SELECT Name, Population FROM City WHERE ( (Name >= 'B' AND Name < 'G') OR (Name >= 'K' AND Name < 'N') ) AND Population > 1000000 ORDER BY Name ASC;

  8. SELECT name as Pet, MONTH(birth) as Month, YEAR(birth) as Year FROM petbirth ORDER BY birth DESC; ✓

  9. Unpredictable results (you don't really know which are the fields), performance issues (more information than needed). ½ If you want to retrieve the table columns in a particular order, you cannot use *.

    1. success, 2) fail, 3) success, 4) fail, 5) success ½ 4) unpredictable results
    1. SELECT c FROM t ORDER BY c COLLATE latin1_general_ci, 2) SELECT c FROM t ORDER BY c COLLATE latin1_general_cs, 3) SELECT c FROM t ORDER BY c COLLATE latin1_bin ✓
  10. SELECT CountryCode FROM CountryLanguage GROUP BY CountryCode; ✓

  11. SELECT name, birth FROM petbirth ORDER BY birth ASC LIMIT 1; ✓

  12. a) SELECT gender, COUNT() FROM pet WHERE gender GROUP IS NOT NULL; ✗ b) SELECT species, COUNT() individuals FROM pet GROUP BY species ORDER BY individuals DESC; ½ faltan alias c) SELECT species, COUNT() individuals FROM pet WHERE species IN ('dog', 'cat') GROUP BY species ORDER BY individuals DESC; ✓ c) SELECT species, COUNT() individuals FROM pet GROUP BY species HAVING species IN ('dog', 'cat') ORDER BY individuals DESC; ✓

  13. a) SELECT unit Unit, COUNT(pid) AS Employees, SUM(salary) AS Total, AVG(salary) Average FROM personnel GROUP BY unit ORDER BY Total DESC; ✓ b) SELECT unit Unit, MAX(salary) AS High, MIN(salary) as Low FROM personnel GROUP BY unit; ✓

  14. SELECT GROUP_CONCAT(Name) FROM Country WHERE Population > 100000000 GROUP BY Continent; ½ falta campo en FROM

  15. SELECT GROUP_CONCAT(District) AS Dutch Districts FROM City WHERE CountryCode = 'NLD'; ✗ GROUP_CONCAT(District ORDER BY District SEPARATOR " - ")

  16. a) 9, b) 8, c) 2, d) 5 ✓

  17. SELECT species as Species, gender as Gender, COUNT(species, gender) Total FROM pet GROUP BY species, gender ORDER BY species; ✓

  18. SELECT Continent, COUNT(*) FROM Country GROUP BY Continent WITH ROLLUP; ✓

  19. a) SELECT name TeamMember, job TeamTask FROM project1.user UNION (SELECT nick, task FROM project2.users) UNION (SELECT member, job FROM project3.members) ✗ UNION ALL b) SELECT name TeamMember, job TeamTask FROM project1.user UNION SELECT nick, task FROM project2.users UNION SELECT member, job FROM project3.members

  20. +------+--------------+ | unit | COUNT(grade) | +------+--------------+ | 42 | 2 | | 23 | 4 | +------+--------------+ ✓

  21. +------+------------+ | unit | SUM(grade) | +------+------------+ | 42 | 3 | | 23 | 4 | +------+------------+ ✓

  22. +------+------------+ | unit | AVG(grade) | +------+------------+ | 42 | 1.5 | | 23 | 1 | +------+------------+ ✓

  23. +------+----------+ | unit | COUNT(*) | +------+----------+ | 42 | 7 | | 23 | 6 | +------+----------+ ✓

  24. +------+-----------------------+ | unit | COUNT(DISTINCT grade) | +------+-----------------------+ | 42 | 2 | | 23 | 1 | +------+-----------------------+ ✓

Total: 21/26

Data types

TINYINT           1
SMALLINT          2
MEDIUMINT         3
INT               4
BIGINT            8
FLOAT             4
DOUBLE            8
DECIMAL(L)        L*4 / 9
BIT(L)            L/8 redondeado hacia arriba en Bytes

CHAR(L)           L
VARCHAR(L)        L+1 o L+2 si L>255
TINYTEXT(L)       < 255
TEXT              < 65535
MEDIUMTEXT        < 16M
LONGTEXT          < 4G
BINARY(L)         L
TINYBLOB          < 255
BLOB              < 65535
MEDIUMBLOB        < 16M
LONGBLOB          < 4G

ENUM              < 65535 members
SET               < 64 members

DATE              3
TIME              3
DATETIME          8 
TIMESTAMP         4
YEAR              1 1901-2155 (2), 1970-2069 (4)

Modos SQL

Modo por defecto: '' (no impone ninguna restricción)

Validación

  • STRICT_TRANS_TABLES: modo estricto para tablas transaccionales
  • STRICT_ALL_TABLES: modo estricto para todas las tablas
  • ERROR_FOR_DIVISION_BY_ZERO (estricto): error al dividir por cero
  • NO_ZERO_DATE (estricto): prohibidas fechas 0000-00-00
  • NO_ZERO_IN_DATE (estricto): prohibidas fechas con algún miembro 0

Sintaxis

  • IGNORE_SPACE: permite espacio entre el nombre de una función y los paréntesis.
  • ANSI QUOTES: dobles comillas en lugar de una.
  • ANSI: ANSI_QUOTES + operador || como concatenación (en vez de OR), otros.

UNION

  • (SELECT ...) UNION (SELECT ...) ORDER BY ... LIMIT ...
@ppinedo00
Copy link

estoy preparando el examen "MySQL Developer", te agradezco este material isra00. ¿Podrias explicarme k es cada seccion ?
¿A que te refieres con "Respuestas del test:"?¿donde esta ese test?

Te parecio muy dificil o con revisar el PDF es suficiente?¿Lo ves util para ofertas de trabajo(de certificaciones de DB solo se requieren SQLserver/ORACLE)? ¿Me puedes enviar(por privado mejor) mas recursos que tengas(VCEs, examenes on-line,Q&A))?

Gracias isra00, saludos:D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment