Decompose relation into BCNF form - relational-database

Suppose we have
R(ABCDE) and functional dependencies: {AB -> C, B -> C, C -> D}, convert this into BCNF.
I see that the candidate key for R is ABE so this is clearly not in BCNF already.
To decompose, I created these relations:
R1(ABC)
R2(BC)
R3(CD)
R4(ABE)
Does this work?

If the functional dependencies given are a cover of the functional dependencies holding on R, applying the so-called “analysis” algorithm produces the following decomposition:
R2 (ABE)
R3 (CD)
R4 (BC)
We start by considering a minimal cover of the dependencies. This is:
B → C
C → D
(since in AB → C we can note that A is estraneous, since we have already that B → C).
So, since B → C violates the BCNF, we decompose R in two relations:
R1 (BCD), with candidate key B
R2 (ABE), with candidate key ABE
In the second relation there are no non-trivial functional dependency, so we leave it as is, while in R1 the only candidate key is B, so C → D violates the BCNF and we decompose it in:
R3 (CD)
R4 (BC)
so the final decomposition is R2, R3 and R4. Note that this decomposition preserves the functional dependencies (not always this is possible with this algorithm).

Related

What would be an ideal mysql database strcture for a multi-level subscription web application?

Currently I am developing a system that accepts multi-level subscribers. With Laravel 5.8, MySQL.
The idea is,
An user (A) will signup with the system.
This user can suggest N number of his friends (B,C,D,...).
And B, C, D,.. can suggest N number of friends them-self after signup with the system.
Now A have his subscribers and his subscriber's subscribers.
Note, B or C or D,.. also can include A as their friend.
A
|
/ / / \ \ \
B C D L M N
| |
/ | \ |
L A D |
|
/ | \
K L M
|
/ / / \ \ \
A B C P Q R
therefore:
A's network is the major network.
both B and M can access all of the members because they have A in their list.
L don't have any list
can access all users because M is friend of D and M is friend with A.
The Structure cannot be considered as hierarchical.
I guess, Many to many relationship and join table concept needs to be implemented.
MySQL Procedure needs to be used to retrieve information.
Requirements
I need to store this relational structure in mysql DB
I should be able to retrieve unique users for any given users (MySQL Procedure).
I hope the I can get a possible suggestions and advise to build this system properly. Thank you.
You could store tree by adding parent_id column. Than, use cache to store which users (for example) user C is subscribed to (M, D, A).
It sounds like a task for graph database. Mysql is not really a great solution to be used here. You 100% will have problems with perfomance. As option, you can store only relationships in graph database (column ids), and retrieve actual data from mysql.
I know that i am a bit late, but someone can find this question through google.

Creating a relational database containing zip codes that need to be matched to 3 diffrent suppliers

I am trying to make a price comparison module in php which pulls records from a database the comparison module makes a calculation based on user input.
One of these inputs are the first 3 digits of the zip code, the zip code then gets matched with the correct variables in order to make the calculation. The variables being: gasregion (1, 2, 3, 4, 5, 6,7,8) energysupplier: (a, b, c, d, e, f, g, h) gassupplier:(a, b, c, d, e, f).
zipcodes can be matched in all possible combinations e.g.:
zipcode 334 could be gasregion 3, energysupplier b and gassuplier d
zipcode 335 could be gasregion 3, energysupplier c and gassuplier e
to make matters more confusing energysupplier a, b, c, d, e, f are the same as gassupplier: a, b, c, d, e, f only have diffrent tarrifs for gas and energy.
I know how to code the comparison module the diffculty for me is designing the database as i have little experince with relational databases.
Could anyone give me a nod in the right direction?
The simplest way (for the programmer) to do this is to build a 1000-row table, with each row containing columns like these.
zip3 gasregion energysupplier gassuplier
000 2 q r
001 3 a b
002 7 w x
...
999 1 a z
Then you can join this table to a possible customer table.

What happens when we theta join or cross 2 relations with common attributes?

Relation 1 (r1):
ID | Name
1 John
2 Doe
3 Foo
Relation 2 (r2):
ID | Name
4 Johnny
5 Doey
6 Fooey
What will r1 theta join(r1.ID = r2.ID) r2 result in?
What will r1 cross r2 result in?
I'm just asking whether the resulting relations should change the names of the attributes to something else because there are 2 of each.
In relational algebra, product (cross join) is usually understood to be a special case of natural join where the joined relations happen to have no attributes in common. So it doesn't make sense to say A x B if A and B have common attributes. If A and B have attributes in common then A x B either means A ⋈ B or it means a mistake has been made and your DBMS or interpreter probably ought to report an error.
Theta join is a shorthand for natural join followed by a restriction. It must be preceded by a rename of some attribute(s) if the attributes in the theta expression would otherwise have the same names.

MySQL - Best approach to ensure unique values across multiple rows

I have 3 tables:
Molecule:
id
Atom:
id
MoleculeAtom: # Composite primary key
molecule_id
atom_id
My goal is to ensure that no combination of atoms which make up a molecule, are repeated. For example, the water molecule, I would store two rows in the MoleculeAtom table; 1 row for a hydrogen atom and 1 row for an oxygen atom. As you can see, I need to ensure that no other molecule has JUST hydrogen and oxygen, even though there may be other molecules which include hydrogen and oxygen.
At this point I have a query which identifies which molecules includes either hydrogen or oxygen, and only having 2 atoms in the MoleculeAtom table.
SELECT
m.id, m.name, (SELECT count(*) from molecule_atom where molecule_id = m.id group by molecule_id) as atomCount
FROM
molecule AS m
INNER JOIN
molecule_atom AS ma ON ma.molecule_id = m.id
WHERE
ma.atom_id IN (1,2)
HAVING atomCount = 2;
Which returns (demonstrative snippet):
+----+----------------------------+-----------+
| id | name | atomCount |
+----+----------------------------+-----------+
| 53 | Carbon Dioxide | 2 |
| 56 | Carbon Monoxide | 2 |
+----+----------------------------+-----------+
(I know, that both CO and CO2 have the same exact atoms, in differing quantities, but dis-regard that, as I am tracking the quantities as a another column in the same table.)
As of now I am pulling the above results and checking their atom_ids via PHP, which means I have to issue a separate query for each molecule, which seems inefficient, so I was looking to see if it's possible to do this checking using strictly SQL.
Excuse any mistakes which may be chemical related, it's been a long time since chem101.
What you are asking for is a table-level constraint and these are not available in MySQL. In SQL-92 standard, there is ASSERTION, which is actually even more general (a constraint across more than 1 table). See the asnwers in this question: Why don't DBMS's support ASSERTION for details and for info about some products (MS-Access) that have such functionality with limitations.
In MySQL, you could try with a trigger to imitate such a constraint.
Update:
Firebird documentation says it allows subqueries in CHECK constraints.
A unique index might be helpful on the molecule_atom table. That would prevent duplicates at that level. You're still going to need to do some checks via SQL statements. Another option depending on the size of your list would be to load it in memory in a hash table and then run the checks from there.
The idea here is to find pairs of molecules whose lists of atoms are not the same:
select m1.molecule_id as m1id, m2.molecule_id as m2id
from molecule_atom as m1, molecule_atom as m2,
(select atom_id from molecule_atom as m where m.molecule_id=m1id) as m1a,
(select atom_id from molecule_atom as m where m.molecule_id=m2id) as m2a,
where m1id < m2id and (((m1a - m2a) is not null) or ((m2a - m1a) is not null))
As ypercube mentioned, MySQL doesn't support assertions, so I ended writing a query to find all molecules having at least one of the atoms which belong to the new molecule I am trying to create, and having the same number of atoms. After querying for matches, the application steps through each molecule and determines if they have the same exact atoms as the new molecule. Query looks like this (assumes I am trying to create a new molecule with 2 atoms):
SELECT
m.id,
m.name,
(SELECT GROUP_CONCAT(ma.atom_id) FROM molecule_atom AS ma WHERE ma.molecule_id = m.id GROUP BY ma.molecule_id HAVING (SELECT COUNT(ma.atom_id)) = 2) AS atoms
FROM
molecule AS m
INNER JOIN
molecule_atom AS mas ON mas.molecule_id = m.id
WHERE
mas.atom_id IN (1,2)
Then in code (PHP) I do:
foreach ($molecules as $molecule) {
if (isset($molecule['atoms'])) {
$diff = array_diff($newAtomIds, explode(',', $molecule['atoms']));
// If there is no diff, then we have a match
if (count($diff) === 0) {
return $molecule['name'];
}
}
}
Thanks for everyone's response.

How to fill a column based on first column

I am making a mySQL table which lists ~70 products and information on whether they are compatible or not. For the sake of simplifying the question, I will pretend there were only four products.
Product1 Product2 Compatible?
A A Yes
A B No
A C Maybe
A D Yes
B A Yes
B B Yes
B C Yes
B D No
C A Yes
C B Maybe
C C Yes
C D Yes
D A Yes
D B No
D C Yes
D D Yes
If I already have a table like (every product is obviously compatible with itself)
Product1 Product2 Compatible?
A A Yes
B B Yes
C C Yes
D D Yes
Is there a way I can quickly fill out the first two columns so they follow the correct pattern? (so I dont have to be doing it manually)
One way to do this would be to use nested loops: If you know how many products you have, lets call it n products.
2^n total rows will be in your table. Additionally, product 1 will have each inventory item n times. (In your example 4 items, so 2^4 = 16 total rows and each item occurs in product1 column n=4 times.
Thus a nested loop can be achieved to do the insert...
$inventory = array(A, B, C, D);
for(i=0;i<2^n;i++){
for(j=0; j<n; j++){
//insert Column1=$inventory[i], Column2=$inventory[j];
}
}
Insert-After triggers!
And when inserting with phpMyadmin leave the column blank. let the trigger fill last column.
insert into compatibleProducts
select distinct p1.ProductID, p2.ProductID, 'Maybe'
from productTable p1
join productTable p2 on p1.ProductID <> p2.ProductID
I assumed that you already have them compatible with themselves, based on your second list.