mysql - Schema design for a table having one column pointing towards multiple tables -


consider following schema:

create schema testschema; use testschema;  create table (     id int not null auto_increment,     name varchar (50),     primary key(id));  create table b (     id int not null auto_increment,     name varchar (50),     primary key(id));  create table c (     id int not null auto_increment,     name varchar (50),     primary key(id));  create table main (     id int not null auto_increment,     typeid int,     type varchar(50),     tablemappingsid int,     primary key (id) );   create table tablemappings (     id int not null auto_increment,     tablename varchar(50),     primary key (id) );  insert (name) values  ('usa'), ('uk'), ('uno');  insert b (name) values  ('earth'), ('mars'), ('jupiter');  insert c (name) values  ('1211'), ('12543'), ('345');  insert main (typeid, type, tablemappingsid) values (1,'tablea',1), (2,'tableb',2), (3,'tablec',3);  insert tablemappings (tablename) values ('a'),('b'),('c'); 

description:-

i have 3 tables a, b , c have id , name.

in main table, type tells table (a or b or c) have read name property. typeid tells id within table(a or b or c). have created tablemappings table has tablenames. in main table have created column tablemappingsid points tablemappings.

is correct approach? , how can write query following in mysql:-

select (name property) table pointed row , mapped tablemappings?

about design

if think in object-oriented manner, have base class constituted of attributes recorded in main table, , derivated a, b , c additionnal attributes. want avoid having many attributes in single table nulls depending on records types. approach. method implement can improved.

answer question

you want select table (a, b or c) depending on value of field. far know cant done without "preparing" query.

"preparing" query can done in multiple manners :

example prepared statement :

set @idtoselect = 2;  select     concat('select name ', tablemappings.tablename, ' id = ', main.tablemappingsid)     @statement     main         inner join tablemappings on tablemappings.tablename = replace(main.type, 'table', '')     main.id = @idtoselect;  prepare stmt @statement;  execute stmt; 

note : have translate 'tablea', 'tableb'... in main.type match 'a', 'b'... in tablemappings.tablename, not ideal.

but not convenient , efficient.

other approaches , comments

selecting multiple tables : not big deal

basically, want avoid select'ing tables dont need read from. keep in mind if schema correctly indexed, not big deal. mysql runs query optimizer. left join of tables , select right table depending on 'type' value :

set @idtoselect = 2;  select     ifnull(a.name, ifnull(b.name, c.name)) name      main         left join on main.type = 'tablea' , a.id = main.tablemappingsid         left join b on main.type = 'tableb' , b.id = main.tablemappingsid         left join c on main.type = 'tablec' , c.id = main.tablemappingsid      main.id = @idtoselect; 

note didn't use tablemappings table

useless tablemappings trick

you can avoid using kind of mapping using same id in "children" table in main table. how many orm's implement inheritance. give example later in answer.

a bit irrelevant example

in question, want select "name" property regardless of type of record. bet if have different types of records, each type holds different set of properties. if "name" common property between types, should in main table. assume provided "name" simplified example. think in real case, you'll have select field regardless of type of object.

other thing : in data example, provide records a, b , c tables not match main records

final proposition

drop schema testschema; create schema testschema; use testschema;  create table main (     id int not null auto_increment,     typeid int,     common_data varchar(50),     primary key (id) );  create table (     id int not null,     specific_dataa varchar (50),     primary key(id),     foreign key fk_a (id) references main (id) );  create table b (     id int not null,     specific_datab varchar (50),     primary key(id),     foreign key fk_b (id) references main (id) );  create table c (     id int not null,     specific_datac varchar (50),     primary key(id),     foreign key fk_c (id) references main (id) );  insert main (typeid, common_data) values (1, 'abc'), (2, 'def'), (3, 'ghi');  insert (id, specific_dataa) values  (1, 'usa');  insert b (id, specific_datab) values  (2, 'mars');  insert c (id, specific_datac) values (3, '345'); 

some comments :

  • typeid in main table optionnal, depending on queries have useful retrieve type of object. 1 field enough, dont need typeid integer , type varchar.

  • id's in a, b , c tables not auto_increment because have match main id's

  • this design irrelevant if there no common attributes, put common data field in main table

  • i materialized relations defining foreign keys

queries examples :

i want common data field id 1 :

select common_data main id = 1; 

i know id 2 type b , want specific data b :

select specific_datab b id = 2; 

i know id 3 type c , want common data , specific data c :

select common_data, specific_datab main inner join b on b.id = main.id main.id = 2; 

(best match case) dont know type of object 3 want specific data depending on type :

select ifnull(     a.specific_dataa,     ifnull(         b.specific_datab,         c.specific_datac     ) ) main     left join on a.id = main.id     left join b on b.id = main.id     left join c on c.id = main.id main.id = 3 

Comments

Popular posts from this blog

magento2 - Magento 2 admin grid add filter to collection -

Android volley - avoid multiple requests of the same kind to the server? -

Combining PHP Registration and Login into one class with multiple functions in one PHP file -