I have two tables operation and source in mysql database.
In operation I have 10 rows(possibility) and in source just 3 rows(possibility) and between them there is a many-to-many relationship.
Question: Is it necessary to add this extra table or just add a foreign key of source in operation.
operation can be subscribe request, subscribe enabled , subscribe disabled , subscribe canceled , payment ok , subscribe deal ok , subscribe start.
source can be from internet , from agent
there is common operations and independent operations from source.
the operaion subscribe enabled can be done from internet subscribe or from agent subscribe and operation : subscribe deal ok can be just from agent and subscribe request can be just from internet.
In a relational database you need 3 tables to make a many to many relationship. Two containing the primary keys and the join table. There's no other way.
For the short and brief answer, normally, with an rdbms like mysql, where only one-to-many relations are supported, you need a 3rd (junction, or cross-reference) table to implement a many-to-many relation between two entities.
But....
Since you don't have too many records, you can map your many-to-many relation between source and operation with just one additional column in source and without redundant data storage. However, you may possibly loose some performance (e.g.: less powerful indexes) and definitely make your life harder working with these tables...
The trick is to use specific binary values as primary key values in your operation table, and add an integer column to the source table where you use its bits to map the relations. So one bit of this column describes one relation between the actual source record and the corresponding operation record.
For your sample operation table, you can create a table with a pri key of a bit type, with a size equal to your estimated number of rows. You say that you are going to have ~10 rows, so use bit(10) as data type. Since, mysql would store int on 4 bytes, you don't loose on the storage size here (instead, compared to int, you may actually win some, but it is really a matter of how the dbe is able to compress the records. actually, you could simply use int as well, if you wish.)
create table operation (id bit(10) primary key, title varchar(50));
insert into operation values (b'0', 'none');
insert into operation values (b'1', 'subscribe request');
insert into operation values (b'10', 'subscribe enabled');
insert into operation values (b'100', 'subscribe disabled');
insert into operation values (b'1000', 'subscribe canceled');
insert into operation values (b'10000', 'payment ok');
insert into operation values (b'100000', 'subscribe deal ok');
insert into operation values (b'1000000', 'subscribe start');
Now, suppose that you have the following in your source table:
create table source (id int primary key, value int, operations bit(10));
insert into source values (1, 1, b'0');
insert into source values (2, 2, b'1'); -- refers to subscribe request
insert into source values (3, 3, b'10'); -- refers to subscribe enabled
insert into source values (4, 4, b'10011'); -- refers to payment ok, subscribe request, subscribe enabled
insert into source values (5, 5, b'1110011'); -- refers to subscribe deal ok, subscribe start, payment ok, subscribe request, subscribe enabled
Now, if you want to select all the relations, join these two tables as follows:
select source.id, operation.title
from source
join operation
on (source.operations & operation.id);
id operation.title
2 subscribe request
4 subscribe request
5 subscribe request
3 subscribe enabled
4 subscribe enabled
5 subscribe enabled
4 payment ok
5 payment ok
5 subscribe deal ok
5 subscribe start
If you want to add a new relation, you may take advantage of the on duplicate key update clause of insert, so you don't have to worry about existing relations:
insert into source (id,value,operations)
values (2,2,(select id from operation where title = 'subscribe start'))
on duplicate key update operations = operations
| (select id from operation where title = 'subscribe start');
If you want to delete a relation:
update source set operations = operations
& ~(select id from operation where title = 'subscribe start') where source.id=2;
All in all, it is not a nice, but a possible way to map your many-to-many relation to just two tables.
Your question can have many answers depending on your real needs.
In fact, in the described situation, you can have just one table "operation" with a source column defined as a MySQL SET type. You will then be able to select 0 to many sources for each opeartion.
You might then alter your table operation to set a source column
ALTER TABLE operation ADD source SET('from internet', 'from agent');
If you really need to have two tables (let suppose your "source" table contain other fields), you should have a third table to make the relation between them.
But, technically, there are situations where, for performance reasons for instance, you could prefer to store your foreign keys in a varchar() field of one of the table, with a coma delimitor, and use PHP to retrieve the data. But it's not the good way of doing it, although it is possible as long as your retrieval of the data is done in one only direction, and you're really sure what you're doing.
For instance, in this "hacky-way", you can imagine an ActiveRecord-like PHP class, where you might wish to retrieve your sources with a method like this
public function getSources() {
private $_sources;
if (!isset($this->_sources)) {
$this->_sources=DBSource::findByPks(explode(",", $this->sources));
}
return $this->_sources;
}
According to the problem you describe, it seems you don't necessarily have a many-to-many relationship as both 'source' and 'operation' are enumerations ( a constant set of values ). Therefore, 'source' and 'operation' do not act as a table but as a data type (i.e. a column type).
You might take a look to Enums in mySQL and to create your own 'source' and 'operation' enum and place them into a table that keeps that "virtual many-to-many relation".
Please, keep in mind that for the solution I am proposing I am assuming that 'source' and 'operation' have a constant and known set of values. In case that was not true, then you would get into trouble as you would have a non-normalized database.
I suggest that you take most simple approach to the problem, it is usually the best one. Use many to many relationship only when it is really needed.
You wrote:
in source just 3 rows(possibility)
source can be from internet , from agent
Those are only two options.
Why not have source like this:
from internet
from agent
from internet & agent
Basically if you are pretty sure that the set of sources will not grow you can hardcode all variants. It gets optimized this way but you loose flexibility. Something similar to #lp_ 's answer.
If you know that in the source table there are at maximum 3 rows you can map the relationship as many to 3 (instead of many to many) with operation table like the following
operation
---------
id_source_1
id_source_2
id_source_3
If you don't know how many rows there are in source you need a third table, because a many to many relationship can be mapped only with a third table.
I want to use the EF (4.2) in the following scenario:
There exists a database already (so I chose the database-first approach) and it is a SQL Anywhere DB.
I want to use persistence-ignorant business objects, so I use the DbContext Template to generate POCO classes from the EDM.
There is one simple inheritance hierarchy among my entities: an abstract base entity and two concrete derived entities.
In the database there is one table for each type of the inheritance hierarchy (Table-Per-Type Strategy).
Each of these three tables has a primary key column (Id, type:integer), and the association of a concrete entity to the base entity is done by having the same Id in both tables (that means that the primary key (Id) of the concrete type tables is at the same time a foreign key to the base table; a pretty common approach I think).
I had to define the Inheritance manually in the designer, since the EDM assistant does not automatically recognize, that is want to have an inheritance association between the described entities.
Until this point there wasn't any bigger problem. Now to the issue at hand:
There is a restriction for the database I use: Primarykey values have to be generated by the database, using a database function.
I want to call this function in a before-insert-trigger defined on the base-table.
To let the entity framework know that a value is generated by the database, I set the StoreGeneratedPattern property of the Id Property of the base-entity to Identity (As I understood, this is the way to tell EF to get the generated value after inserting a new instance of an entity).
When I create a new instance of a derived entity, add it to the corresponding DbSet of the DbContext and call SaveChanges on the context, a DbUpdateException is thrown, stating that a foreignkey constraint is violated.
By checking the request-log of the DB, I see that the base entity got inserted in the base table, but on inserting the row in the derived table, the above mentioned error occurs, because it obviously doesn't use the newly generated Id of the new entry in the base table.
Since I don't think there is much I can do on a database level against that, the question is, if the EDM or DbContext can be configured (or modified) to insert the base row first, then take the generated Id and use it for insertion of the derived row.
I know there are several way to avoid this situation (not using inheritance, using a stored procedure to insert a new derived entity, calling the id-generating db-function before inserting and set the Id property myself on the entity), but at the moment the above-described behavior would be the most preferable, so I want to make sure not to overlook something before deciding for any "plan B".
Any suggestions on this topic are much appreciated,
Thanks in advance.
Here is the code of the trigger:
ALTER TRIGGER "TRG_GENERATE_ID" before insert order 1 on
BASE_TABLE
referencing new as NewEntry
for each row
begin
declare NewID integer;
set NewID = F_GET_NEW_ID('BASE_TABLE', NewEntry.SOME_OTHER_ID);
set NewEntry.ID = NewID
end
The function "F_GET_NEW_ID" is called in the trigger to generate the new ID for a new entry in the base table. It has two parameters:
"Tablename" -> The name of the table for which a new ID should be generated,
and a second parameter that takes the value of a standardcolumn in all tables of the database (it is required to generate the new ID).
I'm using Spring (Roo specifically) to develop an application and for one entity I have a drop down list that is based on a set of enums (i.e. enum(Blue,Pink,Red)). When stored in MYSQL database these enums are stored as numbers (obviously). I want these to be stored as the actual string values instead of numbers in the database (so in MYSQL I want "pinK" to be under "color" instead of simply "2".Is this possible? Thanks
edit:
Let me try asking it a different way. Say when I'm retrieving the data from MYSQL. Instead of the symbolic values I want the actual words is there any way to do this?
I'd try labeling your field with #Enumerated(EnumType.STRING) annotation like:
#Enumerated(EnumType.STRING)
private MyEnumType myEnumField;
You can store the values as text, then use an insert trigger to validate that the stored values are one of the allowed values (since MySQL doesn't support check constraints).
You can also index the minimum number of characters to provide uniqueness, to make your indexing overhead smaller. In your example, you'd only need to index the first character, since 'B', 'P', and 'R' are unique. If you add 'Brown' to the list, you'll need to index the first two characters ('Bl','Pi','Re','Br').
EDIT
My original suggestion was to store the values as their actual text representations, rather than as a number.
Another way to do what you're asking, though, is to add a 'colors' table:
id INT
name VARCHAR
Then have your 'enum' column be a foreign key to the colors table. Then when you do your select:
SELECT ...,colors.name AS color
FROM table t
JOIN colors c ON t.color = c.id
I have a property definition table and second one that holds the actual property values:
table propdef: id, name, description
table props: id, propdefid, userid, value
This way i can dynamically create properties for my users. When I want to update a property for a user I have to check the props table if a propdefid/userid row exists and then either use update or create on this.
Right now I am first querying the db and then deciding on what to do in my java code. Is there a way to do that in the ibatis sqlmap - without extra logic in my java code?
I am using mysql as db.
before you go any farther, you need to stop and read this article: http://tonyandrews.blogspot.com/2004/10/otlt-and-eav-two-big-design-mistakes.html
if you still decide that EAV is the way to go, there is still hope. i can't advise at the ibatis/java level, but i can tell you to look at INSERT ... ON DUPLICATE KEY UPDATE. this change your two statements in to one.
I'm sure this is either totally impossible or really easy:
If I'm creating a table and I want one of the columns to have limited options, it seems that I use either the ENUM or SET value type. But I have to define the possible values at that moment. What if I have another table which has two columns, a primary key column and a data column, and I want the ENUM for my new table to be set to the primary key of the already existing column?
I'm sure I can just write in the values long-hand, but ideally what I need is for new values to be entered into the list table and for the table with the enum column to just accept that the value choices will include anything new added to that list table.
Is this possible without needing to manipulate the structure of the new table each time something is added to the list?
i think this link help :
http://dev.mysql.com/doc/refman/5.0/en/enum.html
have a discussion of it
in the user comments
start :
"In MySQL 5.0, you can convert an enum's values into a dynamically-defined table of values, which then provides effectively a language-neutral method to handle this kind of conversion (rather than relying on PHP, Tcl, C, C++, Java, etc. specific code).
"
he do it with stored PROCEDURE
The easiest way is to use a regular column without contraints. If you're interested in all the current values, use DISTINCT to query them:
select distinct YourColumn from YourTable
That way, you don't have any maintenance and can store whatever you like in the table.
The foreign key table you mention is also a good option. The foreign key will limit the original column. Before you do the actual insert, you run a query to expand the "enum" table:
insert into EnumTable (name)
select 'NewEnumValue'
where not exists (select * from EnumTable where name = 'NewEnumValue')
Not sure what exactly you're trying to achieve btw; limit the column, but automatically expand the choices when someone breaks the limit?