I know there must be an answer to this, but I can't seem to put the search terms together properly.
Say I have an existing table 'foo'
foo
| id | data1 | data2 | ... |
----------------------------
|1 | abc | def | ghi |
|2 | abc | def | ghi |
...
And I want to create a new table, bar that has a 1 to 1 relationship with foo where foo gets a new foreign key column called barId, and each entry of foo MUST have a related barID so the end result looks like:
foo
| id | data1 | data2 | ... | barID |
------------------------------------
|1 | abc | def | ghi | 1 |
|2 | abc | def | ghi | 2 |
...
bar
| id | dataA | dataB |
----------------------
| 1. | null | null |
| 2. | null | null |
The trouble I'm having is that after I define bar I am having trouble creating a row for each entry of foo, and subsequently setting foo.barId for each newly created bar record.
If I were to do this in a procedural language, I would write something like the pseudocode below
createTable(bar);
foo.createColumn("barId");
for each (entry in foo) {
barEntry = bar.createNewEntry();
entry.setBarId(barEntry.ID);
}
How can I accomplish this goal with MySQL?
What part(s) of the problem does the following fail to address?
DROP TABLE IF EXISTS users;
CREATE TABLE users
(user_id SERIAL PRIMARY KEY
,user_name VARCHAR(12) UNIQUE
);
DROP TABLE IF EXISTS user_role;
CREATE TABLE user_role
(user_id INT NOT NULL PRIMARY KEY
,role ENUM('guest','user','administrator')
);
INSERT INTO users VALUES (NULL,'John');
INSERT INTO user_role VALUES (LAST_INSERT_ID(),'administrator');
SELECT * FROM users;
+---------+-----------+
| user_id | user_name |
+---------+-----------+
| 1 | John |
+---------+-----------+
1 row in set (0.00 sec)
SELECT * FROM user_role;
+---------+---------------+
| user_id | role |
+---------+---------------+
| 1 | administrator |
+---------+---------------+
EDIT: And extending this idea, consider the following...
INSERT INTO users (user_name) VALUES ('Paul'),('George'),('Ringo');
INSERT IGNORE INTO user_role SELECT user_id, 'guest' FROM users;
SELECT * FROM users;
+---------+-----------+
| user_id | user_name |
+---------+-----------+
| 1 | John |
| 2 | Paul |
| 3 | George |
| 4 | Ringo |
+---------+-----------+
SELECT * FROM user_role;
+---------+---------------+
| user_id | role |
+---------+---------------+
| 1 | administrator |
| 2 | guest |
| 3 | guest |
| 4 | guest |
+---------+---------------+
Note that it's slightly unusual to store 1-1 relations in separate tables, but there can be valid reasons for doing so - particularly relating to permissions.
Related
I've two tables "sample" and "processes" and i want to get all the processes of given sample in one single column.
Table "sample" example:
----------------------------------------
| Sample Table |
| |
|id | timestamp | other columns... |
--------------------------------------
|1 | 24/04/1994 | ... |
|2 | 25/04/1994 | ... |
|... |... | .... |
----------------------------------------
Table "processes" example:
----------------------------------------
| Processes Table |
| |
|id | sample_id | process_name |
--------------------------------------
|1 | 1 | facebook |
|2 | 1 | tinder |
|3 | 1 | clash royale |
|4 | 2 | uno |
|5 | 2 | whatsapp |
|... |... | .... |
----------------------------------------
Result:
------------------------------------------------------------
| Result Table |
| |
|sample_id | timestamp | processes |
-----------------------------------------------------------
|1 | 24/04/1994 | [facebook, tinder, clash royale] |
|2 | 25/04/1994 | [uno, whatsapp] |
------------------------------------------------------------
Is it possible to this through SQL query? HOW?
P.S: I know that i can get all the processes of given sample with:
SELECT sample_id, timestamp, process_name
FROM sample, processes
WHERE sample.id = processes.sample_id
But this gives me too much unnecessary rows
You can try to use GROUP_CONCAT with CONCAT function.
Schema (MySQL v5.7)
CREATE TABLE sample(
id INT,
timestamp DATE
);
INSERT INTO sample VALUES (1,'1994/04/24');
INSERT INTO sample VALUES (2,'1994/04/25');
CREATE TABLE processes(
id INT,
sample_id INT,
process_name VARCHAR(50)
);
INSERT INTO processes VALUES (1 ,1,'facebook');
INSERT INTO processes VALUES (2 ,1,'tinder');
INSERT INTO processes VALUES (3 ,1,'clash');
INSERT INTO processes VALUES (4 ,2,'uno');
INSERT INTO processes VALUES (5 ,2,'whatsapp');
Query #1
SELECT sample_id, timestamp, CONCAT('[',GROUP_CONCAT(process_name),']') processes
FROM sample JOIN processes ON sample.id = processes.sample_id
GROUP BY sample_id, timestamp;
| sample_id | timestamp | processes |
| --------- | ---------- | ----------------------- |
| 1 | 1994-04-24 | [tinder,clash,facebook] |
| 2 | 1994-04-25 | [uno,whatsapp] |
View on DB Fiddle
NOTE
I would use JOIN instead of use , because JOIN have emphasize relationship about connect two tables.
Here are my tables.
Student Table
+++++++++++++++++++++++++++++++++++++++++++++++++++
| s_id | name | lname | fname | c_id |
+++++++++++++++++++++++++++++++++++++++++++++++++++
| 1 | ali | ahmadi | ahmad | 1 |
| 2 | Hussain | Sharan | Skekib | 2 |
| 3 | Mahmood | Shekibayee | Jahangir | 1 |
+++++++++++++++++++++++++++++++++++++++++++++++++++
Student_course Table
+++++++++++++++++++++++
| sc_id | s_id | c_id |
++++++++++++++++++++++
| 1 | 1 | 1 |
| 2 | 2 | 1 |
| 3 | 3 | 2 |
++++++++++++++++++++++
Now I want to have a trigger that:
When I insert new student into `student` table it should insert `s_id` and `c_id` into student_Course
table.
I am quite new to PHP and MySQL; any help will be highly appreciated.
Thanks in advance.
This could be fairly simple assuming that the sc_id is auto incremented primary key on Student_course
delimiter //
create trigger ins_student_course after insert on Student
for each row
begin
insert into Student_course (s_id,c_id) values (new.s_id,new.c_id);
end ;//
delimiter ;
I have problem
I want to ask, how to change the data that has been entered into the table rekap_nilai. which is where the table is rekapan rekap_nilai total of table nilai_student.
I enter a table B based on trigger
mysql> select * from nilai_student;
+----+-------+------+-------+
| id | name | idmp | nilai |
+----+-------+------+-------+
| 1 | Udin | 1 | 80 |
| 2 | Udin | 2 | 60 |
| 3 | Mamat | 1 | 75 |
+----+-------+------+-------+
table rekap_nilai
mysql> desc rekap_nilai;
+-----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| idstudent | int(11) | YES | | NULL | |
| name | varchar(100) | YES | | NULL | |
| nilai | double | YES | | NULL | |
+-----------+--------------+------+-----+---------+----------------+
mysql> select * from rekap_nilai;
+----+-----------+-------+-------+
| id | idstudent | name | nilai |
+----+-----------+-------+-------+
| 1 | 1 | Udin | 140 |
| 2 | 2 | Mamat | 75 |
+----+-----------+-------+-------+
2 rows in set (0.00 sec)
What if there was a remedial student conduct and when update table nilai_student in column nilai, automatically in table rekap_nilai in column nilai
example
now name 'Udin' have nilai 60 in id 2, and he want remedial. when he was remedial, I want to update he's nilai = 70 , and then in table rekap_nilai. udin automatically update to nilai = 150
You can write a trigger which gets executed on update of table nilai_student , some thing like below
Delimiter ///
create trigger update_rekap_nilai after update on nilai_student
for each row begin
update recap_nilai set nilai = nilai - Old.nilai + New.nilai where name=Old.name
end;
///
Delimiter ;
Hope this helps !!
In mysql i need to get enum fields side by side in a column when i run a query with group by , just like as follows.
There is table as like below
mysql> describe tabex;
+---------+----------------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+----------------------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| personid| int(11) | YES | | NULL | |
| color | enum('red','blue','white') | YES | | NULL | |
+---------+----------------------------+------+-----+---------+----------------+
there are different shirts , the column personid describes the that person id and color indicates the color of his shirt..
the data in table is as follows
mysql> select * from tabex;
+----+----------+-------+
| id | personid | color |
+----+----------+-------+
| 1 | 1 | red |
| 2 | 1 | white |
| 3 | 2 | blue |
| 4 | 2 | red |
+----+----------+-------+
4 rows in set (0.00 sec)
when i ran a query i am getting results like this
mysql> select personid , color from tabex group by personid;
+----------+-------+
| personid | color |
+----------+-------+
| 1 | red |
| 2 | blue |
+----------+-------+
but i want the result like below
+----------+-------------+
|personid | color |
+----------+-------------+
|1 | red,white |
|2 | blue,red |
| | |
+----------+-------------+
how can i get the result as above by using group by and aggregation (if any for enum).
that is here i want to get the result for enum fields as like we will get by using count or sum functions and group by .
The GROUP_CONCAT() aggregate function does what you want:
SELECT personid, GROUP_CONCAT(color) colors
FROM tabex
GROUP BY personid
This works with any kind of field, not just ENUM.
Here is my goods table.
+----------------------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+---------------+------+-----+---------+-------+
| ID | decimal(18,0) | NO | PRI | | |
| gkey | varchar(255) | YES | MUL | NULL | |
| GOODS | decimal(18,0) | YES | MUL | NULL | |
Column ID is auto-increment.
GOODS is the id of a goods category.
Here is the goods category table.
+-------+---------------------+
| ID | NAME |
+-------+---------------------+
| 1 | book |
| 2 | phone |
+-------+---------------------+
My question is in goods table I need the gkey is also an unique key with prefix-id(here id is started from 1.) Like BOOK-1,BOOK-2....PHONE-1,PHONE-2... when insert a new goods record into goods table.
Like that:
+--------------------+---------------+------+-----+---------+-------+
| ID | GKEY |GOODS | PRI | COUNTRY | Extra |
+--------------------+---------------+------+-----+---------+-------+
| 1 | BOOK-1 | 1 | 10 | | |
| 2 | PHONE-1 | 2 | 12 | | |
| 3 | BOOK-2 | 1 | 13 | | |
| 4 | BOOK-3 | 1 | 10 | | |
| 5 | PHONE-2 | 2 | 10 | | |
| 6 | PHONE-3 | 2 | 20 | | |
+--------------------+---------------+------+-----+---------+-------+
How to get that GKEY in PHP+MYSQL?
thanks.
You can use the UNIQUE constraint. For more information check here.
I don't think you want to be doing this at all. Instead, good.gkey should be a foreign key to goods_category.id. If the insertion order is important, you can add an insert_date date field to the goods table.
From there you can run all sorts of queries, with the added bonus of having referential integrity on your tables.
First you should do everything Database side. So no php. That would be my advice.
Then not having sequence in MySQL that what I would Suggest you :
SELECT COUNT(id)
FROM GOODS
WHERE GKEY LIKE('BOOK-%')
Then you insert
INSERT INTO goods (id, "BOOK-" || SELECT MAX(SUBSTR(LENGTH(GKEY -1), LENGTH(GKEY))FROM GOODS WHERE GKEY LIKE('BOOK-%') + 1, ...)
This way you will always have the next number available.
You can do it, but you need to be quite careful to make sure that two simultaneous inserts don't get given the same gkey. I'd design it with these two design points:
In the GoodsCategory table, have a counter which helps to generate the next gkey.
Use locks so that only one process can generate a new key at any one time.
Here's the details:
1. Add a couple of columns to the GoodsCategory table:
+----------------------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+---------------+------+-----+---------+-------+
| ID | TINYINT | NO | PRI | | |
| NAME | VARCHAR(80) | NO | | | |
| KeyCode | CHAR(5) | NO | | | |
| NextID | INT | NO | | 0 | |
+----------------------+---------------+------+-----+---------+-------+
The KeyCode has 'BOOK' or 'PHONE', and the NextID field stores an int which is used to generate the next key of that type i.e. if the table looks like this:
+----------------+------------+---------+--------+
| ID | NAME | KeyCode | NextID |
+----------------+------------+---------+--------+
| 1 | book | BOOK | 3 |
| 2 | phone | PHONE | 7 |
+----------------+------------+---------+--------+
Then the next time you add a book, it should be given gkey 'BOOK-3', and NextID is incremented to 4.
2: The locking will need to be done in a stored routine, because it involves multiple statements in a transaction and uses local variables too. The core of it should look something like this:
START TRANSACTION;
SELECT KeyCode, NextID INTO v_kc, v_int FROM GoodsCategory WHERE ID = 2 FOR UPDATE;
SET v_newgkey = v_kc + '-' + CAST(v_int AS CHAR);
INSERT INTO goods (gkey, goods, ...) VALUES (v_newgkey, 2, etc);
UPDATE GoodsCategory SET NextID = NextID + 1 WHERE ID = 2;
COMMIT;
The FOR UPDATE bit is crucial; have a look at the Usage Examples in the mysql manual where it discusses how to use locks to generate an ID without interference from another process.