miércoles, 20 de octubre de 2010

Consultas SQL basadas en fecha y/o hora

Manejando SQL Server 2005, me encontre que tratando hacer consultas basadas en fechas, obtenía como resultado nada (empty). Esto se debía a que no tenía claro como trabajan los tipos de dato datetime y smalldatetime. Estos dos tipos de datos son muy similares, se diferencia en que datetime es más detallado a la hora de almacenar la fecha. Estas diferencias pueden ser vistas en la siguiente tabla:

Tipo

Minimo

Maximo

Precision

datetime

Ene 1, 1753
media-noche

Dic 31, 9999 23:59:59.997
(0.003 segundos hasta la media-noche)

Más cercano
3.33 millisegundos

smalldatetime

Ene 1, 1900
media-noche

Jun 6, 2079 23:59
(un minuto hasta la media-noche)

Más cercano al mínuto

Ambos, representan una fecha y hora que es igual al número de días en relación a una fecha base. En SQL Server la fecha base es la medianoche del 1 de Enero de 1900. Observando la tabla, el tipo de dato smalldatetime, puede solo representar fechas desde esta fecha base, en cambio el datetime puede representar fechas antes del 1 de enero de 1900. Para hacer esto, el almacena el valor como número negativo.

Para visualizar, como estos valores son guardados. Piensa en un valor decimal, cuya parte entera representa los días desde la fecha base y la parte fraccional (los numeros después del punto) representan la hora. Por ejemplo, el valor date/time mediodía del 4 de enero de 1900, es almacenado como 3.5, donde 3, representa tres días desde la fecha base y el 0.5, representa la mitad del día. Para ver esto en el SQL Server, ejecuta la siguiente consulta:
SELECT CAST(CAST(’1900-01-04 12:00′ AS datetime) AS float)

Otro datito importante es saber que el SQL Server no provee un tipo de dato que solo almacene fecha u hora. Es decir, que si tu almacenas un valor sin la hora (la parte fraccional) se le asigna el valor de cero (0). De igual forma, si tu almacenas un valor sin la fecha, la parte entera se le asigna automáticamente el valor de cero (0), que para la fecha significa 1 de enero de 1900. Para ejemplo, ejecuta la siguiente consulta:

SELECT CAST(’1900-01-04′ AS datetime), CAST(’10:00′ AS datetime)

el cual retornará el siguiente resultado:

1900-01-04 00:00:00.000 1900-01-01 10:00:00.000

Como Buscar Solo la Fecha

Para ilustrar usaremos la siguiente tabla:

ID DateVal
– ———————–
1 2001-02-28 10:00:00.000
2 2002-02-28 13:58:32.823
3 2002-02-29 00:00:00.000
4 2002-02-28 00:00:00.000

Si realizamos la siguiente consulta:

SELECT * FROM DateSample WHERE DateVal = ’2002-02-28′

El resultado solo traerá la fila #4, esto se debe a que el SQL Server buscará los datos cuya hora sea 00:00:00 (medianoche). El valor literal buscado (28 de febrero de 2002) implicítamente se le agregará la hora antes en mención. Entonces, como podemos evitar este suceso y obtener todos los registros cuya fecha sea 28 de febrero de 2002? Lo haremos de la siguiente forma:

Si la consulta es ejecuta frecuentemente, tú debes basar tu búsqueda en un rango de fechas, como la siguiente:

SELECT * FROM DateSample WHERE DateVal BETWEEN ’2002-02-28′ AND ’2002-02-28 23:59:59.997′

Nota: Ahora pensarás que yo soy un brutón porque debi usar como límite superior ’2002-02-29′ en vez de ’2002-02-28 23:59:59.997′. Pués no, si haces esto, la fila #3 será parte del resultado de tu consulta.

Otra forma de obtener el resultado de manera más sencilla (la que yo recomiendo), es de la siguiente manera:

SELECT * FROM DateSample WHERE DateVal >= ’2002-02-28′ AND DateVal < ’2002-02-29′

Como Buscar Solo por la Hora (How to search by time)

Para ilustrar, consideremos la siguiente tabla:

ID TimeVal
– ———————–
1 2002-02-28 10:00:00.000
2 1900-01-01 13:58:32.823
3 1900-01-01 09:59:59.997
4 1900-01-01 10:00:00.000

Si usamos la siguiente consulta para extraer las filas cuya hora es igual a las 10:00 AM:

SELECT * FROM TimeSample WHERE TimeVal = ’10:00:00′

solo conseguiremos la fila #4. La fila #1 no será parte del resultado, debido a que sucede lo mismo que con la fecha, pero en este caso el valor que es implicítamente agregado, es la fecha. En adición, la fila #3 no es parte del resultado porque es un valor super cerca, pero no igual a las 10:00 AM.

Para obviar la fecha, tu puedes crear una consulta que corte la parte entera del valor date/time, y solo deje la parte fraccional. Esta sería de la siguiente forma:

SELECT * FROM TimeSample WHERE TimeVal – CAST(FLOOR(CAST(TimeVal AS float)) AS datetime) = ’10:00′

Esta consulta nos devolvería la fila 1 y 4. Lamentablemente, no hay otra forma de conseguir este resultado sin usar esta combinación de formulas. Por tal motivo, hay que tomar mucho cuidado como se almacena la data datetime/smalldatetime que solo se usa para horas (time-only). Si tú necesitas realizar frecuentemente este tipo de búsqueda, te recomiendo que analices y reestructures el diseño de tu base de datos.

Si tú deseas hacer consultas basadas solo por horas para un intervalo de tiempo, bastaría con una simple consulta (query), esto; tomando en cuenta que se ha almacenado la data hora (time-only) consistentemente sin el componente fecha. La consulta sería algo como esto:

SELECT * FROM TimeSample WHERE TimeVal BETWEEN ’09:59′ AND ’10:01′

o

SELECT * FROM TimeSample WHERE TimeVal > ’09:59′ AND TimeVal < ’10:01′

Estas dos consultas retornarían los datos de la fila #3 y #4.

Si los datos de hora (time-only) han sido guardados en la base de datos inconsistemente, entonces se necesitará que la consulta evite o excluya la parte fecha de estos. Por ejemplo, tu podrías usar una consulta como esta:

SELECT * FROM TimeSample WHERE TimeVal – CAST(FLOOR(CAST(TimeVal AS float)) AS datetime) > ’09:59′ AND TimeVal – CAST(FLOOR(CAST(TimeVal AS float)) AS datetime) < ’10:01′

la cual nos devuelve las filas 1, 3 y 4. Recuerden que no podrías realizar correctamente la búsqueda sin estas funciones, cuando la data hora ha sido guardada inconsistentemente.

Nota: Toda esta información ha sido traducida del libro Murach’s SQL for SQL Server del autor Bryan Syverson.

Base datos para quiz

CREATE TABLE authors
(
au_id char(11) NOT NULL,
au_lname varchar(40) NOT NULL,
au_fname varchar(20) NOT NULL,
phone char(12) NOT NULL,
address varchar(40) NULL,
city varchar(20) NULL,
state char(2) NULL,
zip char(5) NULL,
contract bit NOT NULL,
PRIMARY KEY(au_id)
) TYPE=INNODB;

CREATE TABLE publishers
(
pub_id char(4) NOT NULL,
pub_name varchar(40) NULL,
city varchar(20) NULL,
state char(2) NULL,
country varchar(30) NULL,
PRIMARY KEY(pub_id)
) TYPE=INNODB;

CREATE TABLE titles
(
title_id char(6),
title varchar(80) NOT NULL,
type char(12) NOT NULL DEFAULT 'UNDECIDED',
pub_id char(4) NULL,
price int NULL,
advance int NULL,
royalty int NULL,
ytd_sales int NULL,
notes varchar(200) NULL,
pubdate timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY(title_id),
FOREIGN KEY(pub_id) REFERENCES publishers(pub_id)
) TYPE=INNODB;

CREATE TABLE titleauthor
(
au_id char(11),
title_id char(6),
au_ord tinyint NULL,
royaltyper int NULL,
PRIMARY KEY (au_id, title_id),
FOREIGN KEY (au_id) REFERENCES authors (au_id),
FOREIGN KEY (title_id) REFERENCES titles (title_id)
) TYPE=INNODB;

CREATE TABLE stores
(
stor_id char(4) NOT NULL,
stor_name varchar(40) NULL,
stor_address varchar(40) NULL,
city varchar(20) NULL,
state char(2) NULL,
zip char(5) NULL,
PRIMARY KEY (stor_id)
) TYPE=INNODB;

CREATE TABLE sales
(
stor_id char(4) NOT NULL,
ord_num varchar(20) NOT NULL,
ord_date timestamp NOT NULL,
qty smallint NOT NULL,
payterms varchar(12) NOT NULL,
title_id char(6),
FOREIGN KEY (stor_id) REFERENCES stores(stor_id),
FOREIGN KEY (title_id) REFERENCES titles(title_id),
PRIMARY KEY (stor_id,ord_num,title_id)
) TYPE=INNODB;

CREATE TABLE roysched
(
title_id char(6),
lorange int NULL,
hirange int NULL,
royalty int NULL,
FOREIGN KEY (title_id) REFERENCES titles(title_id)
) TYPE=INNODB;

CREATE TABLE discounts
(
discounttype varchar(40) NOT NULL,
stor_id char(4) NULL,
lowqty smallint NULL,
highqty smallint NULL,
discount dec(4,2) NOT NULL,
FOREIGN KEY (stor_id) REFERENCES stores(stor_id)
) TYPE=INNODB;

CREATE TABLE jobs
(
job_id smallint NOT NULL,
job_desc varchar(50) NOT NULL DEFAULT 'New Position - title not formalized yet',
min_lvl tinyint NOT NULL,
max_lvl tinyint NOT NULL,
PRIMARY KEY (job_id)
) TYPE=INNODB;


CREATE TABLE employee
(
emp_id char(9),
fname varchar(20) NOT NULL,
minit char(1) NULL,
lname varchar(30) NOT NULL,
job_id smallint NOT NULL DEFAULT 1,
job_lvl tinyint NOT NULL DEFAULT 10,
pub_id char(4) NOT NULL DEFAULT '9952',
hire_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (emp_id),
FOREIGN KEY (pub_id) REFERENCES publishers(pub_id),
FOREIGN KEY (job_id) REFERENCES jobs(job_id)
) TYPE=INNODB;

insert into authors values('409-56-7008', 'Bennet', 'Abraham', '415 658-9932', '6223 Bateman St.', 'Berkeley', 'CA', '94705', 1);
insert into authors values('213-46-8915', 'Green', 'Marjorie', '415 986-7020', '309 63rd St. #411', 'Oakland', 'CA', '94618', 1);
insert into authors values('238-95-7766', 'Carson', 'Cheryl', '415 548-7723', '589 Darwin Ln.', 'Berkeley', 'CA', '94705', 1);
insert into authors values('998-72-3567', 'Ringer', 'Albert', '801 826-0752', '67 Seventh Av.', 'Salt Lake City', 'UT', '84152', 1);
insert into authors values('899-46-2035', 'Ringer', 'Anne', '801 826-0752', '67 Seventh Av.', 'Salt Lake City', 'UT', '84152', 1);
insert into authors values('722-51-5454', 'DeFrance', 'Michel', '219 547-9982', '3 Balding Pl.', 'Gary', 'IN', '46403', 1);
insert into authors values('807-91-6654', 'Panteley', 'Sylvia', '301 946-8853', '1956 Arlington Pl.', 'Rockville', 'MD', '20853', 1);
insert into authors values('893-72-1158', 'McBadden', 'Heather', '707 448-4982', '301 Putnam', 'Vacaville', 'CA', '95688', 0);
insert into authors values('724-08-9931', 'Stringer', 'Dirk', '415 843-2991', '5420 Telegraph Av.', 'Oakland', 'CA', '94609', 0);
insert into authors values('274-80-9391', 'Straight', 'Dean', '415 834-2919', '5420 College Av.', 'Oakland', 'CA', '94609', 1);
insert into authors values('756-30-7391', 'Karsen', 'Livia', '415 534-9219', '5720 McAuley St.', 'Oakland', 'CA', '94609', 1);
insert into authors values('724-80-9391', 'MacFeather', 'Stearns', '415 354-7128', '44 Upland Hts.', 'Oakland', 'CA', '94612', 1);
insert into authors values('427-17-2319', 'Dull', 'Ann', '415 836-7128', '3410 Blonde St.', 'Palo Alto', 'CA', '94301', 1);
insert into authors values('672-71-3249', 'Yokomoto', 'Akiko', '415 935-4228', '3 Silver Ct.', 'Walnut Creek', 'CA', '94595', 1);
insert into authors values('267-41-2394', 'O''Leary', 'Michael', '408 286-2428', '22 Cleveland Av. #14', 'San Jose', 'CA', '95128', 1);
insert into authors values('472-27-2349', 'Gringlesby', 'Burt', '707 938-6445', 'PO Box 792', 'Covelo', 'CA', '95428', 3);
insert into authors values('527-72-3246', 'Greene', 'Morningstar', '615 297-2723', '22 Graybar House Rd.', 'Nashville', 'TN', '37215', 0);
insert into authors values('172-32-1176', 'White', 'Johnson', '408 496-7223', '10932 Bigge Rd.', 'Menlo Park', 'CA', '94025', 1);
insert into authors values('712-45-1867', 'del Castillo', 'Innes', '615 996-8275', '2286 Cram Pl. #86', 'Ann Arbor', 'MI', '48105', 1);
insert into authors values('846-92-7186', 'Hunter', 'Sheryl', '415 836-7128', '3410 Blonde St.', 'Palo Alto', 'CA', '94301', 1);
insert into authors values('486-29-1786', 'Locksley', 'Charlene', '415 585-4620', '18 Broadway Av.', 'San Francisco', 'CA', '94130', 1);
insert into authors values('648-92-1872', 'Blotchet-Halls', 'Reginald', '503 745-6402', '55 Hillsdale Bl.', 'Corvallis', 'OR', '97330', 1);
insert into authors values('341-22-1782', 'Smith', 'Meander', '913 843-0462', '10 Mississippi Dr.', 'Lawrence', 'KS', '66044', 0);

insert into publishers values('0736', 'New Moon Books', 'Boston', 'MA', 'USA');
insert into publishers values('0877', 'Binnet & Hardley', 'Washington', 'DC', 'USA');
insert into publishers values('1389', 'Algodata Infosystems', 'Berkeley', 'CA', 'USA');
insert into publishers values('9952', 'Scootney Books', 'New York', 'NY', 'USA');
insert into publishers values('1622', 'Five Lakes Publishing', 'Chicago', 'IL', 'USA');
insert into publishers values('1756', 'Ramona Publishers', 'Dallas', 'TX', 'USA');
insert into publishers values('9901', 'GGG&G', 'Munchen', NULL, 'Germany');
insert into publishers values('9999', 'Lucerne Publishing', 'Paris', NULL, 'France');

insert into titles values ('PC8888', 'Secrets of Silicon Valley', 'popular_comp', '1389', 20.00, 8000.00, 10, 4095, 'Muckraking reporting on the world''s largest computer hardware and software manufacturers.', '06/12/94');
insert into titles values ('BU1032', 'The Busy Executive''s Database Guide', 'business', '1389', 19.99, 5000.00, 10, 4095, 'An overview of available database systems with emphasis on common business applications. Illustrated.', '06/12/91');
insert into titles values ('PS7777', 'Emotional Security: A New Algorithm', 'psychology', '0736', 7.99, 4000.00, 10, 3336, 'Protecting yourself and your loved ones from undue emotional stress in the modern world. Use of computer and nutritional aids emphasized.', '06/12/91');
insert into titles values ('PS3333', 'Prolonged Data Deprivation: Four Case Studies', 'psychology', '0736', 19.99, 2000.00, 10, 4072, 'What happens when the data runs dry? Searching evaluations of information-shortage effects.', '06/12/91');
insert into titles values ('BU1111', 'Cooking with Computers: Surreptitious Balance Sheets', 'business', '1389', 11.95, 5000.00, 10, 3876, 'Helpful hints on how to use your electronic resources to the best advantage.', '06/09/91');
insert into titles values ('MC2222', 'Silicon Valley Gastronomic Treats', 'mod_cook', '0877', 19.99, 0.00, 12, 2032, 'Favorite recipes for quick, easy, and elegant meals.', '06/09/91');
insert into titles values ('TC7777', 'Sushi, Anyone?', 'trad_cook', '0877', 14.99, 8000.00, 10, 4095, 'Detailed instructions on how to make authentic Japanese sushi in your spare time.', '06/12/91');
insert into titles values ('TC4203', 'Fifty Years in Buckingham Palace Kitchens', 'trad_cook', '0877', 11.95, 4000.00, 14, 15096, 'More anecdotes from the Queen''s favorite cook describing life among English royalty. Recipes, techniques, tender vignettes.', '06/12/91');
insert into titles values ('PC1035', 'But Is It User Friendly?', 'popular_comp', '1389', 22.95, 7000.00, 16, 8780, 'A survey of software for the naive user, focusing on the ''friendliness'' of each.', '06/30/91');
insert into titles values('BU2075', 'You Can Combat Computer Stress!', 'business', '0736', 2.99, 10125.00, 24, 18722, 'The latest medical and psychological techniques for living with the electronic office. Easy-to-understand explanations.', '06/30/91');
insert into titles values('PS2091', 'Is Anger the Enemy?', 'psychology', '0736', 10.95, 2275.00, 12, 2045, 'Carefully researched study of the effects of strong emotions on the body. Metabolic charts included.', '06/15/91');
insert into titles values('PS2106', 'Life Without Fear', 'psychology', '0736', 7.00, 6000.00, 10, 111, 'New exercise, meditation, and nutritional techniques that can reduce the shock of daily interactions. Popular audience. Sample menus included, exercise video available separately.', '10/05/91');
insert into titles values('MC3021', 'The Gourmet Microwave', 'mod_cook', '0877', 2.99, 15000.00, 24, 22246, 'Traditional French gourmet recipes adapted for modern microwave cooking.', '06/18/91');
insert into titles values('TC3218', 'Onions, Leeks, and Garlic: Cooking Secrets of the Mediterranean', 'trad_cook', '0877', 20.95, 7000.00, 10, 375, 'Profusely illustrated in color, this makes a wonderful gift book for a cuisine-oriented friend.', '10/21/91');
insert into titles (title_id, title, pub_id) values('MC3026', 'The Psychology of Computer Cooking', '0877');
insert into titles values ('BU7832', 'Straight Talk About Computers', 'business', '1389', 19.99, 5000.00, 10, 4095, 'Annotated analysis of what computers can do for you: a no- hype guide for the critical user.', '06/22/91');
insert into titles values('PS1372', 'Computer Phobic AND Non-Phobic Individuals: Behavior Variations', 'psychology', '0877', 21.59, 7000.00, 10, 375, 'A must for the specialist, this book examines the difference between those who hate and fear computers and those who don''t.', '10/21/91');
insert into titles (title_id, title, type, pub_id, notes) values('PC9999', 'Net Etiquette', 'popular_comp', '1389', 'A must-read for computer conferencing.');


insert into titleauthor values('409-56-7008', 'BU1032', 1, 60);
insert into titleauthor values('486-29-1786', 'PS7777', 1, 100);
insert into titleauthor values('486-29-1786', 'PC9999', 1, 100);
insert into titleauthor values('712-45-1867', 'MC2222', 1, 100);
insert into titleauthor values('172-32-1176', 'PS3333', 1, 100);
insert into titleauthor values('213-46-8915', 'BU1032', 2, 40);
insert into titleauthor values('238-95-7766', 'PC1035', 1, 100);
insert into titleauthor values('213-46-8915', 'BU2075', 1, 100);
insert into titleauthor values('998-72-3567', 'PS2091', 1, 50);
insert into titleauthor values('899-46-2035', 'PS2091', 2, 50);
insert into titleauthor values('998-72-3567', 'PS2106', 1, 100);
insert into titleauthor values('722-51-5454', 'MC3021', 1, 75);
insert into titleauthor values('899-46-2035', 'MC3021', 2, 25);
insert into titleauthor values('807-91-6654', 'TC3218', 1, 100);
insert into titleauthor values('274-80-9391', 'BU7832', 1, 100);
insert into titleauthor values('427-17-2319', 'PC8888', 1, 50);
insert into titleauthor values('846-92-7186', 'PC8888', 2, 50);
insert into titleauthor values('756-30-7391', 'PS1372', 1, 75);
insert into titleauthor values('724-80-9391', 'PS1372', 2, 25);
insert into titleauthor values('724-80-9391', 'BU1111', 1, 60);
insert into titleauthor values('267-41-2394', 'BU1111', 2, 40);
insert into titleauthor values('672-71-3249', 'TC7777', 1, 40);
insert into titleauthor values('267-41-2394', 'TC7777', 2, 30);
insert into titleauthor values('472-27-2349', 'TC7777', 3, 30);
insert into titleauthor values('648-92-1872', 'TC4203', 1, 100);

insert into stores values('7066','Barnums','567 Pasadena Ave.','Tustin','CA','92789');
insert into stores values('7067','News & Brews','577 First St.','Los Gatos','CA','96745');
insert into stores values('7131','Doc-U-Mat: Quality Laundry and Books', '24-A Avogadro Way','Remulade','WA','98014');
insert into stores values('8042','Bookbeat','679 Carson St.','Portland','OR','89076');
insert into stores values('6380','Eric the Read Books','788 Catamaugus Ave.', 'Seattle','WA','98056');
insert into stores values('7896','Fricative Bookshop','89 Madison St.','Fremont','CA','90019');

insert into sales values('7066', 'QA7442.3', '09/13/94', 75, 'ON invoice','PS2091');
insert into sales values('7067', 'D4482', '09/14/94', 10, 'Net 60','PS2091');
insert into sales values('7131', 'N914008', '09/14/94', 20, 'Net 30','PS2091');
insert into sales values('7131', 'N914014', '09/14/94', 25, 'Net 30','MC3021');
insert into sales values('8042', '423LL922', '09/14/94', 15, 'ON invoice','MC3021');
insert into sales values('8042', '423LL930', '09/14/94', 10, 'ON invoice','BU1032');
insert into sales values('6380', '722a', '09/13/94', 3, 'Net 60','PS2091');
insert into sales values('6380', '6871', '09/14/94', 5, 'Net 60','BU1032');
insert into sales values('8042','P723', '03/11/93', 25, 'Net 30', 'BU1111');
insert into sales values('7896','X999', '02/21/93', 35, 'ON invoice', 'BU2075');
insert into sales values('7896','QQ2299', '10/28/93', 15, 'Net 60', 'BU7832');
insert into sales values('7896','TQ456', '12/12/93', 10, 'Net 60', 'MC2222');
insert into sales values('8042','QA879.1', '5/22/93', 30, 'Net 30', 'PC1035');
insert into sales values('7066','A2976', '5/24/93', 50, 'Net 30', 'PC8888');
insert into sales values('7131','P3087a', '5/29/93', 20, 'Net 60', 'PS1372');
insert into sales values('7131','P3087a', '5/29/93', 25, 'Net 60', 'PS2106');
insert into sales values('7131','P3087a', '5/29/93', 15, 'Net 60', 'PS3333');
insert into sales values('7131','P3087a', '5/29/93', 25, 'Net 60', 'PS7777');
insert into sales values('7067','P2121', '6/15/92', 40, 'Net 30', 'TC3218');
insert into sales values('7067','P2121', '6/15/92', 20, 'Net 30', 'TC4203');
insert into sales values('7067','P2121', '6/15/92', 20, 'Net 30', 'TC7777');

insert into roysched values('BU1032', 0, 5000, 10);
insert into roysched values('BU1032', 5001, 50000, 12);
insert into roysched values('PC1035', 0, 2000, 10);
insert into roysched values('PC1035', 2001, 3000, 12);
insert into roysched values('PC1035', 3001, 4000, 14);
insert into roysched values('PC1035', 4001, 10000, 16);
insert into roysched values('PC1035', 10001, 50000, 18);
insert into roysched values('BU2075', 0, 1000, 10);
insert into roysched values('BU2075', 1001, 3000, 12);
insert into roysched values('BU2075', 3001, 5000, 14);

insert into roysched values('BU2075', 5001, 7000, 16);
insert into roysched values('BU2075', 7001, 10000, 18);
insert into roysched values('BU2075', 10001, 12000, 20);
insert into roysched values('BU2075', 12001, 14000, 22);
insert into roysched values('BU2075', 14001, 50000, 24);
insert into roysched values('PS2091', 0, 1000, 10);
insert into roysched values('PS2091', 1001, 5000, 12);
insert into roysched values('PS2091', 5001, 10000, 14);
insert into roysched values('PS2091', 10001, 50000, 16);
insert into roysched values('PS2106', 0, 2000, 10);

insert into roysched values('PS2106', 2001, 5000, 12);
insert into roysched values('PS2106', 5001, 10000, 14);
insert into roysched values('PS2106', 10001, 50000, 16);
insert into roysched values('MC3021', 0, 1000, 10);
insert into roysched values('MC3021', 1001, 2000, 12);
insert into roysched values('MC3021', 2001, 4000, 14);
insert into roysched values('MC3021', 4001, 6000, 16);
insert into roysched values('MC3021', 6001, 8000, 18);
insert into roysched values('MC3021', 8001, 10000, 20);
insert into roysched values('MC3021', 10001, 12000, 22);

insert into roysched values('MC3021', 12001, 50000, 24);
insert into roysched values('TC3218', 0, 2000, 10);
insert into roysched values('TC3218', 2001, 4000, 12);
insert into roysched values('TC3218', 4001, 6000, 14);
insert into roysched values('TC3218', 6001, 8000, 16);
insert into roysched values('TC3218', 8001, 10000, 18);
insert into roysched values('TC3218', 10001, 12000, 20);
insert into roysched values('TC3218', 12001, 14000, 22);
insert into roysched values('TC3218', 14001, 50000, 24);
insert into roysched values('PC8888', 0, 5000, 10);
insert into roysched values('PC8888', 5001, 10000, 12);

insert into roysched values('PC8888', 10001, 15000, 14);
insert into roysched values('PC8888', 15001, 50000, 16);
insert into roysched values('PS7777', 0, 5000, 10);
insert into roysched values('PS7777', 5001, 50000, 12);
insert into roysched values('PS3333', 0, 5000, 10);
insert into roysched values('PS3333', 5001, 10000, 12);
insert into roysched values('PS3333', 10001, 15000, 14);
insert into roysched values('PS3333', 15001, 50000, 16);
insert into roysched values('BU1111', 0, 4000, 10);
insert into roysched values('BU1111', 4001, 8000, 12);
insert into roysched values('BU1111', 8001, 10000, 14);

insert into roysched values('BU1111', 12001, 16000, 16);
insert into roysched values('BU1111', 16001, 20000, 18);
insert into roysched values('BU1111', 20001, 24000, 20);
insert into roysched values('BU1111', 24001, 28000, 22);
insert into roysched values('BU1111', 28001, 50000, 24);
insert into roysched values('MC2222', 0, 2000, 10);
insert into roysched values('MC2222', 2001, 4000, 12);
insert into roysched values('MC2222', 4001, 8000, 14);
insert into roysched values('MC2222', 8001, 12000, 16);

insert into roysched values('MC2222', 12001, 20000, 18);
insert into roysched values('MC2222', 20001, 50000, 20);
insert into roysched values('TC7777', 0, 5000, 10);
insert into roysched values('TC7777', 5001, 15000, 12);
insert into roysched values('TC7777', 15001, 50000, 14);
insert into roysched values('TC4203', 0, 2000, 10);
insert into roysched values('TC4203', 2001, 8000, 12);
insert into roysched values('TC4203', 8001, 16000, 14);
insert into roysched values('TC4203', 16001, 24000, 16);
insert into roysched values('TC4203', 24001, 32000, 18);

insert into roysched values('TC4203', 32001, 40000, 20);
insert into roysched values('TC4203', 40001, 50000, 22);
insert into roysched values('BU7832', 0, 5000, 10);
insert into roysched values('BU7832', 5001, 10000, 12);
insert into roysched values('BU7832', 10001, 15000, 14);
insert into roysched values('BU7832', 15001, 20000, 16);
insert into roysched values('BU7832', 20001, 25000, 18);
insert into roysched values('BU7832', 25001, 30000, 20);
insert into roysched values('BU7832', 30001, 35000, 22);
insert into roysched values('BU7832', 35001, 50000, 24);

insert into roysched values('PS1372', 0, 10000, 10);
insert into roysched values('PS1372', 10001, 20000, 12);
insert into roysched values('PS1372', 20001, 30000, 14);
insert into roysched values('PS1372', 30001, 40000, 16);
insert into roysched values('PS1372', 40001, 50000, 18);

insert into discounts values('Initial Customer', NULL, NULL, NULL, 10.5);
insert into discounts values('Volume Discount', NULL, 100, 1000, 6.7);
insert into discounts values('Customer Discount', '8042', NULL, NULL, 5.0);

insert into jobs values (1, 'New Hire - Job not specified', 10, 10);
insert into jobs values (2, 'Chief Executive Officer', 200, 250);
insert into jobs values (3, 'Business Operations Manager', 175, 225);
insert into jobs values (4, 'Chief Financial Officier', 175, 250);
insert into jobs values (5, 'Publisher', 150, 250);
insert into jobs values (6, 'Managing Editor', 140, 225);
insert into jobs values (7, 'Marketing Manager', 120, 200);
insert into jobs values (8, 'Public Relations Manager', 100, 175);
insert into jobs values (9, 'Acquisitions Manager', 75, 175);
insert into jobs values (10, 'Productions Manager', 75, 165);
insert into jobs values (11, 'Operations Manager', 75, 150);
insert into jobs values (12, 'Editor', 25, 100);
insert into jobs values (13, 'Sales Representative', 25, 100);
insert into jobs values (14, 'Designer', 25, 100);

insert into employee values ('PTC11962M', 'Philip', 'T', 'Cramer', 2, 215, '9952', '11/11/89');
insert into employee values ('AMD15433F', 'Ann', 'M', 'Devon', 3, 200, '9952', '07/16/91');
insert into employee values ('F-C16315M', 'Francisco', '', 'Chang', 4, 227, '9952', '11/03/90');
insert into employee values ('LAL21447M', 'Laurence', 'A', 'Lebihan', 5, 175, '0736', '06/03/90');
insert into employee values ('PXH22250M', 'Paul', 'X', 'Henriot', 5, 159, '0877', '08/19/93');
insert into employee values ('SKO22412M', 'Sven', 'K', 'Ottlieb', 5, 150, '1389', '04/05/91');
insert into employee values ('RBM23061F', 'Rita', 'B', 'Muller', 5, 198, '1622', '10/09/93');
insert into employee values ('MJP25939M', 'Maria', 'J', 'Pontes', 5, 246, '1756', '03/01/89');
insert into employee values ('JYL26161F', 'Janine', 'Y', 'Labrune', 5, 172, '9901', '05/26/91');
insert into employee values ('CFH28514M', 'Carlos', 'F', 'Hernadez', 5, 211, '9999', '04/21/89');
insert into employee values ('VPA30890F', 'Victoria', 'P', 'Ashworth', 6, 140, '0877', '09/13/90');
insert into employee values ('L-B31947F', 'Lesley', '', 'Brown', 7, 120, '0877', '02/13/91');
insert into employee values ('ARD36773F', 'Anabela', 'R', 'Domingues', 8, 100, '0877', '01/27/93');
insert into employee values ('M-R38834F', 'Martine', '', 'Rance', 9, 75, '0877', '02/05/92');
insert into employee values ('PHF38899M', 'Peter', 'H', 'Franken', 10, 75, '0877', '05/17/92');
insert into employee values ('DBT39435M', 'Daniel', 'B', 'Tonini', 11, 75, '0877', '01/01/90');
insert into employee values ('H-B39728F', 'Helen', '', 'Bennett', 12, 35, '0877', '09/21/89');
insert into employee values ('PMA42628M', 'Paolo', 'M', 'Accorti', 13, 35, '0877', '08/27/92');
insert into employee values ('ENL44273F', 'Elizabeth', 'N', 'Lincoln', 14, 35, '0877', '07/24/90');
insert into employee values ('MGK44605M', 'Matti', 'G', 'Karttunen', 6, 220, '0736', '05/01/94');
insert into employee values ('PDI47470M', 'Palle', 'D', 'Ibsen', 7, 195, '0736', '05/09/93');
insert into employee values ('MMS49649F', 'Mary', 'M', 'Saveley', 8, 175, '0736', '06/29/93');
insert into employee values ('GHT50241M', 'Gary', 'H', 'Thomas', 9, 170, '0736', '08/09/88');
insert into employee values ('MFS52347M', 'Martin', 'F', 'Sommer', 10, 165, '0736', '04/13/90');
insert into employee values ('R-M53550M', 'Roland', '', 'Mendel', 11, 150, '0736', '09/05/91');
insert into employee values ('HAS54740M', 'Howard', 'A', 'Snyder', 12, 100, '0736', '11/19/88');
insert into employee values ('TPO55093M', 'Timothy', 'P', 'O''Rourke', 13, 100, '0736', '06/19/88');
insert into employee values ('KFJ64308F', 'Karin', 'F', 'Josephs', 14, 100, '0736', '10/17/92');
insert into employee values ('DWR65030M', 'Diego', 'W', 'Roel', 6, 192, '1389', '12/16/91');
insert into employee values ('M-L67958F', 'Maria', '', 'Larsson', 7, 135, '1389', '03/27/92');
insert into employee values ('PSP68661F', 'Paula', 'S', 'Parente', 8, 125, '1389', '01/19/94');
insert into employee values ('MAS70474F', 'Margaret', 'A', 'Smith', 9, 78, '1389', '09/29/88');
insert into employee values ('A-C71970F', 'Aria', '', 'Cruz', 10, 87, '1389', '10/26/91');
insert into employee values ('MAP77183M', 'Miguel', 'A', 'Paolino', 11, 112, '1389', '12/07/92');
insert into employee values ('Y-L77953M', 'Yoshi', '', 'Latimer', 12, 32, '1389', '06/11/89');
insert into employee values ('CGS88322F', 'Carine', 'G', 'Schmitt', 13, 64, '1389', '07/07/92');
insert into employee values ('PSA89086M', 'Pedro', 'S', 'Afonso', 14, 89, '1389', '12/24/90');
insert into employee values ('A-R89858F', 'Annette', '', 'Roulet', 6, 152, '9999', '02/21/90');
insert into employee values ('HAN90777M', 'Helvetius', 'A', 'Nagy', 7, 120, '9999', '03/19/93');
insert into employee values ('M-P91209M', 'Manuel', '', 'Pereira', 8, 101, '9999', '01/09/89');
insert into employee values ('KJJ92907F', 'Karla', 'J', 'Jablonski', 9, 170, '9999', '03/11/94');
insert into employee values ('POK93028M', 'Pirkko', 'O', 'Koskitalo', 10, 80, '9999', '11/29/93');
insert into employee values ('PCM98509F', 'Patricia', 'C', 'McKenna', 11, 150, '9999', '08/01/89');

FAQ Bases de datos

ntroducción

Este tema suele traer grandes dolores de cabeza cuando se trata de ser abordado usualmente, ya que muchos tutoriales parten de la base que uno sabe que es una base de datos, los diferentes tipos y como se usan. Así que este tutorial no pretende ser de ayuda para desarrollar ningún sistema, sino que su fin es el de explicar el sentido de las bases de datos y sus conceptos más básicos para así poder adentrarse cómodamente en el desarrollo de sistemas con bases de datos.

Primero vamos a partir con una serie de preguntas frecuentes que me fui encontrando:

FAQ

¿Qué es una DB?
Data Base = Base de datos en inglés

¿Qué es una BBDD o BD?
Base de datos

¿Para qué sirve una DB?
Almacenar datos

¿Cómo se aprende a programar en mySQL?
No se aprende, mySQL es una base de datos, no un lenguaje

¿SQL es una base de datos?
SQL server sí, pero SQL es un lenguaje

¿Cuántos tipos hay?
Muchos, pero los habituales en web son Access, mySQL y SQL Server 2000

¿Necesito algún lenguaje especial para conectarme?
Sí, SQL es el lenguaje para interactuar con las bases de datos

¿Qué es un Query?
Una consulta a la base de datos

¿Qué es ABM?
Alta, Baja y Modificación de cualquier cosa. Usualmente de una base de datos que contiene datos.

¿Qué es CMS?
Control Managment System : Un panel de control que administra un web site, y a menudo una base de datos.

Ahora, aclaradas estas dudas básicas, vamos al grano. Separaré en varios items la explicación a fin de un mejor orden.

Funcionalidad de un DB

Una base de datos (sea cual sea) es un soporte digital que tiene como fin el almacenamiento masivo de información en formato texto plano. No es capaz de almacenar imágenes como se cree, sino que almacena las rutas (path) de dichas fotos; ni almacena otro tipo de datos; sino que almacena sus rutas de acceso de ser necesario.

Las bases de datos, son utilizadas en sistemas que requieren una interacción fluida con la aplicación; estas se encargan muchas veces de administrar, editar, y dar de alta. Usualmente la base de datos, esta ligada a la programación directa del site, causando que una edición en ella cause una modificación directa en lo que ve el usuario.

Ejemplos de aplicación de una base de datos (entiéndase que están ligadas a un lenguaje dinámico como PHP o ASP):
E – comerce, Agendas, Libros de visitas, foros, portales, etc

Estructura normal de una DB

Una base de datos, a fin de ordenar la información de manera lógica, posee un orden que debe ser cumplido para acceder la información de manera coherente.

Cada base de datos tiene una o más tablas, las cuales cumplen la función de contener los campos. Un ejemplo de tabla sería “contactos”. Para entender mejor esto, sería como un libro en el excel. Mientras que los campos serían las columnas del excel donde se ordena cada datos insertado al libro. Ejemplo “id, nombres, apellidos, teléfono”. Y luego finalmente tenemos las filas (row), que son la información propiamente dicha.

Por consiguiente una base de datos posee el siguiente orden jerárquico:

  • Tablas
  • Campos
  • Registros

Tipos usuales de bases de datos en la Web

En la web, se suelen usar 3 tipos de bases de datos:

Access: Es una base de datos desarrollada por Microsoft comúnmente utilizada bajo el lenguaje ASP (Active Server Pages). Esta base de datos, debe ser creada bajo el programa access, el cual crea archivo .mdb con la estructura ya explicada. El programa usa un entorno gráfico normal, y es muy parecido a usar excel.

MySQL: Es una base de datos con licencia GPL basada en un servidor, puede ser sólo creada por código. Usualmente se utiliza el programa phpMyAdmin como soporte para administrar la base de datos en el nivel de programación (a un usuario normal le resultaría complicado utilizarla desde linea de comandos).

SQL Server: Es una base de datos más potente que access desarrollada por Microsoft también, que se supone es recomendable arriba del millon datos.

PostgreSQL / Oracle: Son realmente mucho más poderosas que todas las antes mencionadas, aunque también se duplican los problemas. Administra muy bien grandes cantidades de datos, y suelen ser utilizadas en intranets y sistemas de gran calibre.

Lenguaje SQL

Este es el lenguaje que se utiliza para conectarse a una base de datos. Son sentencias, que realizan un query (consulta) a la DB a fin de que esta les responda con una cantidad de datos limitada según lo buscado. Básicamente, existen muchísimas funciones de SQL, pero detallaré las más usuales, con las cuales se pueden lograr una interacción buena con la DB.

Insertar Datos a una Tabla especifica:

INSERT INTO `Nombre Tabla` (` Nombre Campo ` , ` Nombre Campo ` , `Nombre Campo`) VALUES ('Valor', ' Valor', ' Valor ');

Editar Datos de una fila especifica

UPDATE ` Nombre Tabla ` SET ` Nombre Campo ` = 'Valor', ` Nombre Campo ` = ' Valor',` Nombre Campo ` = ' Valor' WHERE `id` = 'Numero Fila';

Nota: Siempre se incluye el campo id, a fin de identificar con un valor numérico una fila.

Borrar una Fila

DELETE FROM ` Nombre Tabla ` WHERE `id`='Numero Fila';

Seleccionar datos de una Fila

SELECT Nombre Campo, Nombre Campo FROM Nombre Tabla where id = Numero Fila;

Buscar datos dentro de una tabla

SELECT Nombre Campo FROM Nombre Tabla where Nombre Campo LIKE '%".Concepto de Búsqueda."%;

Contar Registros totales en un campo

SELECT COUNT (Nombre Campo) FROM Nombre Tabla;

Conclusión

Las bases de datos son soportes capaces de almacenar grandes cantidades de datos usando SQL como el lenguaje “consultor” de esos datos.

miércoles, 6 de octubre de 2010

Entendiendo los Mysql JOIN


Este es un problema bastante común para los desarrolladores que trabajan sobre bases de datos:

Llaman un set de resultados y se encuentran que uno de los campos no es mas sino un listado de ID’s. Ahora como traigo los datos de ese campo?

Muy a menudo me encuentro con desarrolladores SQL que aplican la siguiente lógica para solucionar este problema:

SELECT * FROM países

foreach($países as $país) {
SELECT * FROM ciudades WHERE país = $país
foreach ($ciudades as $ciudad) {

Que como pueden ver, no solo es difícil de manejar sino que es imposible de crecer logicamente y en ultimas, confuso de leer. Mas que genera una cantidad de gasto de memoria tanto en el PC corriendo php como en la base de datos que genera la busqueda especifica.

Afortunadamente, tenemos la flexibilidad de una función MySQL hecha precisamente para llamar datos entre dos tablas conectadas con un campo en común: JOIN

Por ejemplo, usando JOIN, llamar un set de resultados de direcciones a base de país requeriría del siguiente query:

SELECT * FROM direcciones. AS dir
JOIN países AS p ON p.país = dir.pais
WHERE … cualquier condicion

Mejor! Esta búsqueda generaría el siguiente set hipotético de resultados para presentar usando php (ojo que esta organizado por las columnas de “país”):

 p.id  |  p.pais   | dir.id  | dir.pais  | dir.direccion
1 | USA | 3 | USA | 200 West Chadderdon Avenue
2 | Mexico | 4 | Mexico | 823 Monte Libano
4 | Colombia | 2 | Colombia | Carrera 9B Bis #117-32
3 | Colombia | 1 | Colombia | Calle 127 #42-45

Fácil, no? Bueno, a simple vista si, pero con esto estamos tan solo raspando la superficie del problema en el que nos podemos encontrar si tenemos dos tablas que no necesariamente contengan datos simétricos.

Para solucionar este problema, hay que considerar el juego de herramientas JOIN entero:
LEFT JOIN, RIGHT JOIN, INNER JOIN y OUTER JOIN.

Cuando me lo cruce originalmente, este post de Jeff Atwood que explica como funcionan los JOIN me soluciono una cantidad de problemas, hoy en día ya lo he reenviado tanto que decidí colgarlo aquí:

JOIN, una explicacion visual

Entonces, para lograr entender entonces que tan poderosa es la utilidad JOIN, voy a visualizar dos tablas que contengan tan solo algunos datos en común:

id nombre       id  nombre
-- ---- -- ----
1 Pirata 1 Rutabaga
2 Mico 2 Pirata
3 Ninja 3 Darth Vader
4 Spaghetti 4 Ninja

Listo? ahora veamos a ver como como caen las mezclas de datos usando JOIN

INNER JOIN

SELECT * FROM TablaA
INNER JOIN TablaB
ON TablaA.name = TablaB.name

id name id name
-- ---- -- ----
1 Pirata 2 Pirata
3 Ninja 4 Ninja

Este genera una lista de resultados que existan tanto en A como en B simultaneamente


FULL OUTER JOIN
SELECT * FROM TablaA
FULL OUTER JOIN TablaB
ON TablaA.name = TablaB.name
id    name       id    name
-- ---- -- ----
1 Pirata 2 Pirata
2 Mico null null
3 Ninja 4 Ninja
4 Spaghetti null null
null null 1 Rutabaga
null null 3 Darth Vader

Genera un listado que incluya todos los resultados en A y en B, asi no exista relacion entre algun campo


LEFT OUTER JOIN
SELECT * FROM TablaA
LEFT OUTER JOIN TablaB
ON TablaA.name = TablaB.name
id  name       id    name
-- ---- -- ----
1 Pirata 2 Pirata
2 Mico null null
3 Ninja 4 Ninja
4 Spaghetti null null

Entrega todos los resultados que encuentra en la tabla A, pero tambien trae los resultados que empaten que aparezcan en la tabla B.


Usos y Derivados

… Conociendo como funcionan los JOIN, estos son otros ejemplos que se pueden generar usando la sintáxis JOIN completa.

SELECT * FROM TablaA
LEFT OUTER JOIN TablaB
ON TablaA.name = TablaB.name
WHERE TablaB.id IS null

id name id name
-- ---- -- ----
2 Mico null null
4 Spaghetti null null

Solo quiero ver los records unicos que existan en la tabla A

SELECT * FROM TablaA
FULL OUTER JOIN TablaB
ON TablaA.name = TablaB.name
WHERE TablaA.id IS null
OR TablaB.id IS null


id name id name
-- ---- -- ----

2 Mico null null
4 Spaghetti null null
null null 1 Rutabaga
null null 3 Darth Vader
Muestrame los records que no tengan relacion alguna entre la tabla A y la tabla B


Y ojo que el LEFT JOIN es intercambiable en sintaxis (mas no en logica) con un RIGHT JOIN donde
SELECT * FROM TablaA
LEFT JOIN TablaB
ON TablaA.name = TablaB.name

… es equivalente a

SELECT * FROM TablaB
RIGHT JOIN TablaA
ON TablaA.name = TablaB.name
Descargar ejemplo de una base de datos aqui

miércoles, 11 de agosto de 2010

Taller #1 base de datos

Saludos a todos!!!

Desarrollar en siguiente taller segun la informacion que se encuentra registrada en este blog....


enlace al taller http://tickipedia.com/ejercicios/Taller1.pdf
Si bien este tema es objeto de numerosos teóricos y asignatura fundamental en las más importantes escuelas de informática del mundo, afrontemos el diseño relacional de nuestras bases de datos desde un punto de vista ameno y práctico, plagado de ejemplos, sin renunciar en nungún caso al rigor.

Table of Contents [hide]

1. Relaciones "uno a uno"
2. Relaciones de "uno a varios"
3. Relaciones de "varios con varios"
4. Conclusión

Las diferentes formas de relación entre diversas bases de datos que podemos encontrar son:
Relaciones "uno a uno"

Estas relaciones entre bases de datos se dan cuando cada campo clave aparece sólo una vez en cada una de las tablas.

Tomando un ejemplo del mundo real, una clara relación de "uno a uno" podría ser, el nombre de cualquier persona y su número de teléfono. Si partimosdel supuesto en que cada persona tiene un solo número de teléfono, se podría hablar de una relación "uno a uno".

Gráficamente, se podría representar de la siguiente manera:

Este tipo de relaciones se caracteriza poque cad uno de los campos define a aquél con el que se relaciona. Es decir, conociendo el nombre de una persona podemos conocer su número telefónico. O si sabemos su número telefónico, podemos identificar al dueño. En estos cases, se suele aconsejar incluir todos los datos dentro de una sola tabla.
Relaciones de "uno a varios"

El ejemplo del caso anterior (cada persona, un teléfono), si bien es correcto teóricamente, es muy improbable desde el punto de vista de la realidad. Conla gran expansión de los teléfonos, por lo general, cada persona tiene un número de teléfono fijo, y ademas del teéfono móvil. Debemos tener en cuenta que de el de su casa también tendrá un número de teléfono de empresa, y que quizá también sus móviles estén divididos en ocio y trabajo.

Por ello, debemos tener nuestras bases de datos preparadas para ello. Este tipo de relaciones es conocido como "uno a varios", y se podría representar de la siguiente manera:

En este caso, lo aconsejable no es almacenar todos los datos en una sola tabla, sino lo eficiente es hacerlo en tablas separadas, utilizando el identificador ID para relacionarlas.

Echemos un vistazo a la figura anterior. En la taba Nombre almacenamos el nombre y apellido, con su ID o número identificador. En la otra tabla, Teléfonos, almacenamos únicamente números de teléfono, con su correspondiente número identificador, en este caso TID. La manera en que se relaciona una con otra es mediante el identificador ID, que está presente en ambas tablas.

A simple vista podemos advertir que la primera de las personas de la tabla nombres, Juan Timaná, tiene 2 números telefónicos, pues su ID, que en este caso es 1, aparece en dos de los teléfonos de la otra tabla.

De este modo será mucho mas sencillo cambiar, eliminar o ampliar los números de teléfono en la misma tabla.

Si estas tablas están creadas en MySQL, la sentencia que nos ayudaría a encontrar todos los teléfonos de una determinada persona sería:
SELECT n.nombre, t.telf
FROM nombre n
INNER JOIN telefonos t ON n.id = t.id
WHERE n.nombre = "Juan Timaná"
Relaciones de "varios con varios"

La última de la relaciones que podemos encontrar es la de "varios con varios". Dado que en la vida las cosas rara vez son sencillas, éste será el tipo de relación que nos encontraremos más a menudo.

Volviendo al tema de los teéfonos, hemos encontrado la manera de relacionar cada una de las personas con sus diversos teléfonos: el de su casa, el de su empresa, el móvil. Pero no será extraño tener en nuestra base de datos diversas personas que trabajen en la misma empresa, por lo que el número de su trabajo será el mismo, o miembros de una misma familia, por lo que compartirán el mismo teléfono de su hogar.

¿Cómo tratar este tipo de relaciones? Si nos limistamos a repetir dicho número de tablas, estaremos creando problemas de redundancia de datos, que a largo plazo lastrarán la rapidez y eficacia de nuestras tablas.

Este tipo de relaciones podría ilustrarse de la siguiente manera:

Como vemos, cada elemento de la bas de datos puede relacionarse libremente con uno o varios miembros de las distintas tablas.

En estos casos no hay una regla fija a la que podamos acogernos, pero lo aconsejable es aproximarse lo más posible a la realidad, y no dudar en establecer tablas intermedias que nos ayuden a asociar mejor los datos.

Volviendo al tema de los teléfonos, imaginemos que varias personas de nuestra tabla trabajan en la misma empresa ACME Productions tiene varias líneas, por lo que los números de teléfono de trabajo de estas personas serían varios. ¿Cómo representarlo en nuestra base de datos?

En este caso hemos creado una tabla intermedia llamada "empresas". En la tabla "nombres" incluimos un nuevo campo TID, que se relaciona con la tabla "empresas", y es esta tabla la que se relaciona directamente con los teléfonos. De esta manera, podemos almacenar todos los datos con facilidad sin tener que repetir un sólo número telefónico.
Conclusión

Por muy complicadas que parezcan las relaciones en el mundo real, tengamos por seguro que cuando queramos plasmarlas en nuestra base de datos corresponderá alguna de las tres opciones que hemos presentado. Por ello, no dudemos en invertir el tiempo que sea necesario hasta encontrar la combinación de bases de datos óptima que nos permita modelar la realidad sin repetir ninguno de los datos.

El tiempo que invirtamos en este proceso lo recuperaremos con creces durante el proceso de programación, pues nos facilitará enormemente las cosas.
Objetivos de los sistemas de bases de datos.
Los objetivos principales de un sistema de base de datos es disminuir los siguientes
aspectos:
Redundancia e inconsistencia de datos.
Puesto que los archivos que mantienen almacenada la información son creados por
diferentes tipos de programas de aplicación existe la posibilidad de que si no se controla
detalladamente el almacenamiento, se pueda originar un duplicado de información, es
decir que la misma información sea más de una vez en un dispositivo de
almacenamiento. Esto aumenta los costos de almacenamiento y acceso a los datos,
además de que puede originar la inconsistencia de los datos - es decir diversas copias de
un mismo dato no concuerdan entre si -, por ejemplo: que se actualiza la dirección de un
cliente en un archivo y que en otros archivos permanezca la anterior.
Dificultad para tener acceso a los datos.
Un sistema de base de datos debe contemplar un entorno de datos que le facilite al
usuario el manejo de los mismos. Supóngase un banco, y que uno de los gerentes
necesita averiguar los nombres de todos los clientes que viven dentro del código postal
78733 de la ciudad. El gerente pide al departamento de procesamiento de datos que
genere la lista correspondiente. Puesto que esta situación no fue prevista en el diseño del
sistema, no existe ninguna aplicación de consulta que permita este tipo de solicitud, esto
ocasiona una deficiencia del sistema.
Aislamiento de los datos.
Puesto que los datos están repartidos en varios archivos, y estos no pueden tener
diferentes formatos, es difícil escribir nuevos programas de aplicación para obtener los
datos apropiados.
Anomalías del acceso concurrente.
Para mejorar el funcionamiento global del sistema y obtener un tiempo de respuesta
más rápido, muchos sistemas permiten que múltiples usuarios actualicen los datos
simultáneamente. En un entorno así la interacción de actualizaciones concurrentes
puede dar por resultado datos inconsistentes. Para prevenir esta posibilidad debe
mantenerse alguna forma de supervisión en el sistema.

Objetivos de los sistemas de bases de datos.
Los objetivos principales de un sistema de base de datos es disminuir los siguientes
aspectos:
Redundancia e inconsistencia de datos.
Puesto que los archivos que mantienen almacenada la información son creados por
diferentes tipos de programas de aplicación existe la posibilidad de que si no se controla
detalladamente el almacenamiento, se pueda originar un duplicado de información, es
decir que la misma información sea más de una vez en un dispositivo de
almacenamiento. Esto aumenta los costos de almacenamiento y acceso a los datos,
además de que puede originar la inconsistencia de los datos - es decir diversas copias de
un mismo dato no concuerdan entre si -, por ejemplo: que se actualiza la dirección de un
cliente en un archivo y que en otros archivos permanezca la anterior.
Dificultad para tener acceso a los datos.
Un sistema de base de datos debe contemplar un entorno de datos que le facilite al
usuario el manejo de los mismos. Supóngase un banco, y que uno de los gerentes
necesita averiguar los nombres de todos los clientes que viven dentro del código postal
78733 de la ciudad. El gerente pide al departamento de procesamiento de datos que
genere la lista correspondiente. Puesto que esta situación no fue prevista en el diseño del
sistema, no existe ninguna aplicación de consulta que permita este tipo de solicitud, esto
ocasiona una deficiencia del sistema.
Aislamiento de los datos.
Puesto que los datos están repartidos en varios archivos, y estos no pueden tener
diferentes formatos, es difícil escribir nuevos programas de aplicación para obtener los
datos apropiados.
Anomalías del acceso concurrente.
Para mejorar el funcionamiento global del sistema y obtener un tiempo de respuesta
más rápido, muchos sistemas permiten que múltiples usuarios actualicen los datos
simultáneamente. En un entorno así la interacción de actualizaciones concurrentes
puede dar por resultado datos inconsistentes. Para prevenir esta posibilidad debe
mantenerse alguna forma de supervisión en el sistema.