how to update child table in mysql - mysql

I have have here an example table.incident table
+-------------+----------------------+
| incident_id | incident_description |
+-------------+----------------------+
| 1 | Accident |
| 2 | Homicide |
| 3 | Theft |
+-------------+----------------------+
incident_detail table:
+--------------------+-------------+-------------+
| incident_detail_id | person_name | incident_id |
+--------------------+-------------+-------------+
| 1 | errol | 1 |
| 2 | neo | 1 |
| 3 | aj | 1 |
| 4 | mark | 2 |
| 5 | calma | 2 |
| 6 | allan | 2 |
| 7 | dave | 3 |
| 8 | paul | 3 |
+--------------------+-------------+-------------+
I am providing a grid view like view that would allow the user to remove and add items in the incident_detail table. My question is, how can i update the incident_detail table? i am ok with adding new items, but removal. I don't know. Should i empty the entire table and insert the new items that the user added. But the problem here is that the existing items that weren't removed will be deleted and inserted again.

If you don't care about the incident_detail_id column incrementing more than it needs to, you can simply delete and re-insert the records, regardless of whether you changed the details for an incident.
It makes for easier SQL code but it does mean on each edit your IDs will go up. Assuming you're auto-incrementing.
After adding detail to Homicide you'll end up with:
+--------------------+-------------+-------------+
| incident_detail_id | person_name | incident_id |
+--------------------+-------------+-------------+
| 1 | errol | 1 |
| 2 | neo | 1 |
| 3 | aj | 1 |
| 9 | mark | 2 |
| 10 | calma | 2 |
| 11 | allan | 2 |
| 12 | new | 2 |
| 7 | dave | 3 |
| 8 | paul | 3 |
+--------------------+-------------+-------------+
If you're happy with that:
DELETE FROM incident_detail WHERE incident_id = 2;
INSERT INTO incident_detail (person_name, incident_id)
VALUES
('mark', 2)
('calma', 2)
('allan', 2)
('new', 2);

Related

How do I join 2 tables to a third one which contains the primary key?

I have 4 tables: the first is the client table, which has customer info, and client_id as an auto-increment primary key.
The second and third are identical in structure: they are used to track attendance to 2 different therapy programs. They each have a primary key, and a client_id column to track the client. One of the fields contains units, which I want to sum.
The last table contains the therapists' info.
Basically I want to extract total amount of units for each client from the two attendance tables.
I have tried LEFT JOINS to no avail. I also tried a UNION ALL, but couldn't get it to sum the units.
This is how the tables look:
client:
+---------------------------------------+
| client_id | f_name | l_name | th_id |
|-----------|----------|--------|-------|
| 1 | sherlock | holmes | 1 |
| 2 | john | watson | 4 |
| 3 | hercule | poirot | 3 |
| 4 | jane | marple | 2 |
+---------------------------------------+
therapist:
+--------------------------+
| th_id | f_name | l_name |
|-------|---------|--------|
| 1 | james | kirk |
| 2 | mr | spock |
| 3 | bones | mccoy |
| 4 | nyota | uhura |
+--------------------------+
attendance it:
+-------------------------------+
| it_id | client_id | units |
|-----------|-----------|-------|
| 1 | 1 | 4 |
| 2 | 1 | 4 |
| 3 | 1 | 0 |
| 4 | 1 | 2 |
| 5 | 4 | 0 |
| 6 | 4 | 4 |
| 7 | 4 | 0 |
| 8 | 4 | 2 |
+-------------------------------+
attendance psr:
+-------------------------------+
| it_id | client_id | units |
|-----------|-----------|-------|
| 1 | 1 | 16 |
| 2 | 1 | 16 |
| 3 | 1 | 0 |
| 4 | 1 | 12 |
| 5 | 4 | 0 |
| 6 | 4 | 14 |
| 7 | 4 | 8 |
| 8 | 4 | 10 |
+-------------------------------+
The result should look like this:
+------------------------------------------------------------+
| client_id | total_units_it | total_units_psr | therapist |
|-----------|----------------|-----------------|-------------|
| 1 | 10 | 44 | james kirk |
| 4 | 6 | 32 | mr spock |
+------------------------------------------------------------+
Please excuse the primitive representations, and please don't ask why the tables are designed like that... ;-) Also, I obviously ignored many other fields which are not relevant to the question, such as dates, etc.
Any advice would be appreciated.
Thanks!
You can't use join or you will create Cartesian product and duplicate the rows.
Instead you do a subquery:
SELECT c.*
, (SELECT SUM(units) FROM attendance_it a WHERE a.client_id = c.client_id ) as total_units_it
, (SELECT SUM(units) FROM attendance psr a WHERE a.client_id = c.client_id ) as total_units_psr
, t.*
FROM client c
JOIN therapist t
ON c.th_id = t.th_id
use group by client_id to get the sum of each client. and no need to use join as you have already the ids in column.

add foreign key with on update cascade

Let's say, I have 2 tables
user
+----+--------+
| id | status |
+----+--------+
| 1 | A |
| 2 | A |
+----+--------+
article
+----+-----+--------+
| id | uid | status |
+----+-----+--------+
| 1 | 1 | A |
| 2 | 2 | A |
| 3 | 2 | A |
| 4 | 2 | A |
| 5 | 1 | A |
| 6 | 2 | A |
| 7 | 2 | A |
| 8 | 1 | A |
| 9 | 2 | A |
| 10 | 2 | A |
+----+-----+--------+
How can I add a foreign key that if I run this query:
UPDATE user SET status='B' WHERE id=1 OR id=2;
the result will be:
user
+----+--------+
| id | status |
+----+--------+
| 1 | B |
| 2 | B |
+----+--------+
article
+----+-----+--------+
| id | uid | status |
+----+-----+--------+
| 1 | 1 | B |
| 2 | 2 | B |
| 3 | 2 | B |
| 4 | 2 | B |
| 5 | 1 | B |
| 6 | 2 | B |
| 7 | 2 | B |
| 8 | 1 | B |
| 9 | 2 | B |
| 10 | 2 | B |
+----+-----+--------+
Or in other words, if I update column user.status, MySQL will automatically update column article.status with the respective value.
How can I create this foreign key?
That job is not foreign key could finish. Use an update trigger, but for better Database compatibility, do this action on you code is preferred.
Trigger code:
CREATE TRIGGER SetArticleStatus AFTER UPDATE ON user
FOR EACH ROW
BEGIN
UPDATE `article`
SET status = NEW.status
WHERE uid = NEW.id
END
Since your FOREIGN KEY is only uid and doesn't know about status the thing you want can't be accomplished using only foreign-keys. This looks like a good use-case for a on-update-trigger.

Mysql - pivot indeterminate number of rows to multiple columns

Given the following two tables:
+- Members -+
| ID | Name |
+----+------+
| 1 | Bob |
| 2 | Jim |
| 3 | Judy |
etc...
This table represents the members' children. Each parent may have many or no children
+- Children -------------+-----+
| ID | ParentID | Name | Age |
+----+----------+--------+-----+
| 1 | 3 | Jeff | 4 |
| 2 | 3 | Casey | 3 |
| 3 | 1 | Steven | 10 |
| 4 | 2 | Mary | 7 |
| 5 | 1 | Esther | 8 |
| 6 | 2 | Abe | 11 |
| 7 | 3 | Paul | 6 |
etc...
I need to create a table that looks like this:
+----+------+--------+------+---------+------+--------+------+
| ID | Name | Child1 | Age1 | Child2 | Age2 | Child3 | Age3 |
+----+------+--------+------+---------+------+--------+------+
| 1 | Bob | Steven | 10 | Esther | 8 | | |
| 2 | Jim | Abe | 11 | Mary | 7 | | |
| 3 | Judy | Paul | 6 | Jeff | 4 | Casey | 3 |
+----+------+--------+------+---------+------+--------+------+
I've tried various pivot table approaches, but every one that I've seen requires a known number of rows in the second table for each row in the first table. I essentially need an unknown number of columns. A group_concat isn't going to meet my requirements.
Is this possible with MySQL or do I need to do this in the backend?

mysql update rows in table after one of them is deleted

So i'm developing a website which allows users to create a project A.K.A "guide" and then add steps to that created project.
For example my steps table structure:
------------------------------------
| id | projectid | stepOrder |
| 1 | 103 | 1 |
| 2 | 103 | 2 |
| 3 | 103 | 3 |
| 4 | 103 | 4 |
| 5 | 104 | 1 |
| 6 | 104 | 2 |
| 7 | 104 | 3 |
-----------------------------------
So as you can see this table has 3 fields: id, projectID (references project id in another table) and stepOrder. Now if the user decided to delete step 2 from 103 project we would be left with something like this:
------------------------------------
| id | projectid | stepOrder |
| 1 | 103 | 1 |
| 3 | 103 | 3 |
| 4 | 103 | 4 |
| 5 | 104 | 1 |
| 6 | 104 | 2 |
| 7 | 104 | 3 |
-----------------------------------
As you can see since we deleted step 2 it now jumps from step 1 directly to step 3.But instead i need it to be like this:
------------------------------------
| id | projectid | stepOrder |
| 1 | 103 | 1 |
| 3 | 103 | 2 |
| 4 | 103 | 3 |
| 5 | 104 | 1 |
| 6 | 104 | 2 |
| 7 | 104 | 3 |
-----------------------------------
So how can i achieve this?
Usually this is done application-side as a subsequent update:
DELETE FROM guide_steps WHERE id=?
UPDATE guide_steps SET stepOrder=stepOrder-1 WHERE stepOrder>? AND projectid=?
You can lock this inside a transaction to avoid one step being done without the other.
It's also possible to wrap this up in a trigger, but that's usually a bad idea as it can be complicated to maintain those, and it's easy to get "trigger happy".

Tricky database design

I need to design a database to store user values : for each user, there is a specific set of columns.
For instance, Jon wants to store values in a table with 2 columns : name, age.
And Paul wants to store values in a 3 columns table : fruit, color, weight.
At this point, I have 2 options.
Option 1 - Store data as text values
I would have a first table 'profiles' with the users' preferences :
+----+---------+--------+-------------+
| id | user_id | label | type |
+----+---------+--------+-------------+
| 1 | 1 | name | VARCHAR(50) |
| 2 | 1 | age | INT |
| 3 | 2 | fruit | VARCHAR(50) |
| 4 | 2 | color | VARCHAR(50) |
| 5 | 2 | weight | DOUBLE |
+----+---------+--------+-------------+
And then store the datas as text in another table :
+----+------------+--------+
| id | id_profile | value |
+----+------------+--------+
| 1 | 1 | Aron |
| 2 | 2 | 17 |
| 3 | 1 | Vince |
| 4 | 2 | 27 |
| 5 | 1 | Elena |
| 6 | 2 | 78 |
| 7 | 3 | Banana |
| 8 | 4 | Yellow |
| 9 | 5 | 124.8 |
+----+------------+--------+
After that, I would programatically create and populate a clean table.
Option 2 - One column per type
On this option, I would have a first table 'profiles2' like that :
+----+---------+--------+------+
| id | user_id | label | type |
+----+---------+--------+------+
| 1 | 1 | name | 3 |
| 2 | 1 | age | 1 |
| 3 | 2 | fruit | 3 |
| 4 | 2 | color | 3 |
| 5 | 2 | weight | 2 |
+----+---------+--------+------+
with the type corresponding of a set of type : 1=INT , 2=DOUBLE , 3=VARCHAR(50)
And a data table like that :
+----+-------------+-----------+--------------+---------------+
| id | id_profile2 | int_value | double_value | varchar_value |
+----+-------------+-----------+--------------+---------------+
| 1 | 1 | NULL | NULL | Aron |
| 2 | 2 | 17 | NULL | NULL |
| 3 | 1 | NULL | NULL | Vince |
| 4 | 2 | 27 | NULL | NULL |
| 5 | 1 | NULL | NULL | Elena |
| 6 | 2 | 78 | NULL | NULL |
| 7 | 3 | NULL | NULL | Banana |
| 8 | 4 | NULL | NULL | Yellow |
| 9 | 5 | NULL | 124.8 | NULL |
+----+-------------+-----------+--------------+---------------+
Here I have cleaner tables, but still a programmatic trick to implement to get everything in order.
The questions
Have anyone ever face this situation ?
What do you think of my 2 options ?
Is there a better solution, less tricky ?
Tx a lot!
Edit
Hi again,
My model had a bug : impossible to retrieve a "line" of information; i.e. the informations in the "values" table are not sortables.
After some wanredings around the EAV model, it showed not suitable because it's not designed to store datas, but specific infos.
Then I ended with this model :
Firt table 'labels' :
+----+------------+------+----------+
| id | profile_id | name | datatype |
+----+------------+------+----------+
| 1 | 1 | 1 | Nom |
| 2 | 1 | 1 | Age |
| 3 | 2 | 2 | Fruit |
| 4 | 2 | 2 | Couleur |
| 5 | 2 | 2 | Poids |
+----+------------+------+----------+
Then a very simple 'nodes' talbe, just to keep track of the lines of infos :
+----+------------+
| id | profile_id |
+----+------------+
| 1 | 1 |
| 2 | 1 |
| 3 | 2 |
| 4 | 2 |
+----+------------+
and a set of tables corresponding to different datatypes :
+----+---------+----------+--------+
| id | node_id | label_id | value |
+----+---------+----------+--------+
| 1 | 1 | 1 | John |
| 2 | 2 | 1 | Doe |
| 3 | 3 | 3 | Orange |
| 4 | 3 | 4 | Orange |
| 5 | 4 | 3 | Banane |
| 6 | 4 | 4 | Jaune |
+----+---------+----------+--------+
With this model, queries are ok. Data input is a bit tricky but I will manage with a clean code.
Cheers
Take a look at EAV data models.
Option 3: make two different tables.
One table is obviously for people. The other is obviously for fruit. They should be in different tables.
Why not just have a user table with name and ID, the a userValues table that has key value pairs? that was John can have key "fruit" and value "mango, and another key "tires" and value "goodyear". Bob can have key "coin" and value "penny" and key "age" and value "42". Anyone can have any value they like and you have maximum flexibility. Speed won't be great, and you'll have to cast string to values, but it's always a tradeoff.
Cheers,
Daniel