I'd like to know the right and proper practice to handle auto_increment in this table structure problem. Let's say I have these table:
StudentMaster
ID auto_increment
name varchar(100)
Status int(11)
StudentDetail
ID varchar(10)
examID varchar(20)
examDate date
When I insert a data to StudentMaster and StudentDetail in one action, how to make the ID in StudentDetail has the same value with StudentMaster? Because in the new form, there is no textbox containing ID to be inputted.
Data example:
ID Name Status
1 Roy 1
2 Nicole 2
ID examID examDate
1 A1 2017-05-15
1 A2 2017-05-15
1 A5 2017-05-17
2 A2 2017-05-15
1 A3 2017-05-16
P.S: I am in the database structure phase. The PHP form is not created yet.
Related
I want to know if I do something like this:
INSERT INTO
projects(name, start_date, end_date)
VALUES
('AI for Marketing','2019-08-01','2019-12-31'),
('ML for Sales','2019-05-15','2019-11-20');
into a table
CREATE TABLE projects(
project_id INT AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
start_date DATE,
end_date DATE,
PRIMARY KEY(project_id)
);
if the project_id of the second entry ('ML for Sales','2019-05-15','2019-11-20') will always be bigger (inserted after the other one) than the first? It's not about if the ids are +1 - just a > b.
So when I do a SELECT project_id, name FROM projects ORDER BY project_id it will always be:
-------------------------------------
| project_id | name |
|-----------------------------------|
| 1 | AI for Marketing |
| 1 + x | ML for Sales |
-------------------------------------
example taken from here: https://www.mysqltutorial.org/mysql-insert-multiple-rows/
Yes, its guaranteed that a > b.
b can never be inserted before a in at least Mysql.
You can look up to the documentation of VALUES and AUTO_INCREMENT
https://dev.mysql.com/doc/refman/8.0/en/values.html
https://dev.mysql.com/doc/refman/8.0/en/example-auto-increment.html
There is no explicit mention about the order but lets assume that on any existing language, the creation of elements on an array is sequential by essence.
The following two tables are not liked by any type of constraint.
First i have a table called subscription_plans that looks like this:
name | price | ID
-------------------
plan_A | 9.99 | 1
Plan_B | 19.99 | 2
plan_C | 29.99 | 3
I have a second table called pricing_offers. The subscription_plan_ID is a of type SET and can only contain values that match the ID's of the subscription_plans.ID (column from the above table). This table looks like this:
p_o_name | subscription_plan_ID | ID
-----------------------------------------
free donuts | 1 | 1
extra sauce | 1,2,3 | 2
pony ride | 3 | 3
bus fare -50% | 1,2,3 | 4
I'm trying to do a query to select everything (all fields *) from the first table and all names from the second table and the resulting rows should look like this:
name | price | p_o_name | ID
-------------------------------------------------------------
plan_A | 9.99 | free donuts, extra sauce, bus fare -50% | 1
Plan_B | 19.99 | extra_sauce, bus fare -50% | 2
plan_C | 29.99 | extra_sauce, pony ride, bus fare -50% | 3
The idea being that it should, for each row in the subscription_plans table, look ID field. Then go trough the second table and see what rows contain in the subscription_plan_ID, the ID of the row above. Gather those into a field caller p_o_name and insert its values to the matching response rows.
I tried doing this:
SELECT subscription_plans.*, pricing_offers.name
FROM subscription_plans INNER JOIN pricing_offers ON
FIND_IN_SET(subscription_plans.ID,subscription_plan_ID)
but i get instead of:
plan_A | 9.99 | free donuts, extra sauce, bus fare -50% | 1
this:
plan_A | 9.99 | free donuts | 1
plan_A | 9.99 | extra sauce | 1
plan_A | 9.99 | bus fare -50% | 1
Note: i get a response with all rows, but i just put the first one here to exemplify the difference.
Now, while i could do the processing in the response on my PHP page, i'm interested in knowing if i get the DB engine to output my desired result.
Do i need to create a type of constraint between the tables? If so how would i do it? I would be grateful for any help that would help me get to my proffered output result (even a better title for the question!).
If there are any unclear points, please let me know and i will clarify them.
Example of junction/intersect table usage.
create table subscription_plans
(
id int not null auto_increment primary key, -- common practice
name varchar(40) not null,
description varchar(255) not null,
price decimal(12,2) not null
-- additional indexes:
);
create table pricing_offers
(
id int not null auto_increment primary key, -- common practice
name varchar(40) not null,
description varchar(255) not null
-- additional indexes:
);
create table so_junction
( -- intersects mapping subscription_plans and pricing_offers
id int not null auto_increment primary key, -- common practice
subId int not null,
offerId int not null,
-- row cannot be inserted/updated if subId does not exist in parent table
-- the fk name is completely made up
-- parent row cannot be deleted and thus orphaning children
CONSTRAINT fk_soj_subplans
FOREIGN KEY (subId)
REFERENCES subscription_plans(id),
-- row cannot be inserted/updated if offerId does not exist in parent table
-- the fk name is completely made up
-- parent row cannot be deleted and thus orphaning children
CONSTRAINT fk_soj_priceoffer
FOREIGN KEY (offerId)
REFERENCES pricing_offers(id),
-- the below allows for only ONE combo of subId,offerId
CONSTRAINT soj_unique_ids unique (subId,offerId)
-- additional indexes:
);
insert into subscription_plans (name,description,price) values ('plan_A','description',9.99);
insert into subscription_plans (name,description,price) values ('plan_B','description',19.99);
insert into subscription_plans (name,description,price) values ('plan_C','description',29.99);
select * from subscription_plans;
insert into pricing_offers (name,description) values ('free donuts','you get free donuts, limit 3');
insert into pricing_offers (name,description) values ('extra sauce','extra sauce');
insert into pricing_offers (name,description) values ('poney ride','Free ride on Wilbur');
insert into pricing_offers (name,description) values ('bus fare -50%','domestic less 50');
select * from pricing_offers;
insert so_junction(subId,offerId) values (1,1); -- free donuts to plans
insert so_junction(subId,offerId) values (1,2),(2,2),(3,2); -- extra sauce to plans
insert so_junction(subId,offerId) values (3,3); -- wilbur
insert so_junction(subId,offerId) values (1,4),(2,4),(3,4); -- bus to plans
select * from so_junction;
-- try to add another of like above to so_junction
-- Error Code 1062: Duplicate entry
-- show joins of all
select s.*,p.*
from subscription_plans s
join so_junction so
on so.subId=s.id
join pricing_offers p
on p.id=so.offerId
order by s.name,p.name
-- show extra sauce intersects
select s.*,p.*
from subscription_plans s
join so_junction so
on so.subId=s.id
join pricing_offers p
on p.id=so.offerId
where p.name='extra sauce'
order by s.name,p.name
Basically you insert and delete from the junction table (no good really updating ever in this example).
Clean and fast joins without having to mess with slow, unwieldy sets without indexes
No one can ride the Wilbur the Poney anymore? Then
delete from so_junction
where offerId in (select id from pricing_offers where name='poney ride')
Ask if you have any questions.
And good luck!
I have 2 tables
account
id | desc
Prices
id | desc
Table account stores users info while table prices stores several prices depending type of service.
Now, I need to assign prices that apply to each account.
I would like to display a result containg prices and an extra column that tells (in form of a list) the accounts that apply that service...
I was thinking on
CREATE TABLE `account` (
`id_account` smallint(2) unsigned PRIMARY KEY AUTO_INCREMENT,
`user` VARCHAR(55) ,
`pass` VARCHAR(55) ,
`descr` VARCHAR(250)
);
INSERT INTO account VALUES
(1,'67395' , 'pass1','DrHeL'),
(2,'12316' , 'pass2','DeHrL'),
(3,'92316' , 'pass3','EfL');
CREATE TABLE `prices`(
`id_price` smallint(2) unsigned PRIMARY KEY AUTO_INCREMENT,
`service` VARCHAR(40),
`cost_1_1Kg` double ,
`cost_4_1Kg` double ,
`cost_8_1Kg` double
);
INSERT INTO prices VALUES
(1,'laundry', 1.50, 2.00,5.00),
(2,'walk.' , 2.50, 3.00,4.00);
CREATE TABLE `account_prices` (
`id_account` smallint(2) unsigned NOT NULL,
`id_price` smallint(2) unsigned NOT NULL,
`descr` VARCHAR(250)
) ;
INSERT INTO account_prices VALUES
(1,1,'apply SERVICE WITH ID 1 AND SERVICE WITH ID 2'),
(2,1,'apply SERVICE WITH ID 1 AND SERVICE WITH ID 2'),
(3,1,'apply SERVICE WITH ID 1 AND SERVICE WITH ID 2'),
(1,2,'apply SERVICE WITH ID 1 AND SERVICE WITH ID 2'),
(2,2,'apply SERVICE WITH ID 1 AND SERVICE WITH ID 2'),
(3,2,'apply SERVICE WITH ID 1 AND SERVICE WITH ID 2');
This gives me
ID_ACCOUNT ID_PRICE DESCR USER PASS SERVICE COST_1_1KG COST_4_1KG COST_8_1KG
1 1 apply SERVICE WITH ID 1 AND SERVICE WITH ID 2 67395 pass1 laundry 1.5 2 5
2 1 apply SERVICE WITH ID 1 AND SERVICE WITH ID 2 12316 pass2 laundry 1.5 2 5
3 1 apply SERVICE WITH ID 1 AND SERVICE WITH ID 2 92316 pass3 laundry 1.5 2 5
1 2 apply SERVICE WITH ID 1 AND SERVICE WITH ID 2 67395 pass1 walk. 2.5 3 4
2 2 apply SERVICE WITH ID 1 AND SERVICE WITH ID 2 12316 pass2 walk. 2.5 3 4
3 2 apply SERVICE WITH ID 1 AND SERVICE WITH ID 2 92316 pass3 walk. 2.5 3 4
However I would like somethink like:
ID_PRICE SERVICE COST_1_1KG COST_4_1KG COST_8_1KG descr
1 laundry 1.5 2 5 acount 1, account 2, account 3
2 walk. 2.5 3 4 acount 1, account 2, account 3
How to do It?
Please take a look at the corresponding fiddle:
http://sqlfiddle.com/#!2/16f05/3
You can get your desired output with this query:
select ap.id_price
, p.service
, p.cost_1_1Kg
, p.cost_4_1Kg
, cost_8_1Kg
, group_concat(
concat('account ', ap.id_account)
order by ap.id_account
separator ', '
) as descr
from account_prices ap
inner join prices p using (id_price)
group by ap.id_price
Result:
| ID_PRICE | SERVICE | COST_1_1KG | COST_4_1KG | COST_8_1KG | DESCR |
|----------|---------|------------|------------|------------|---------------------------------|
| 1 | laundry | 1.5 | 2 | 5 | account 1, account 2, account 3 |
| 2 | walk. | 2.5 | 3 | 4 | account 1, account 2, account 3 |
Check updated SQL fiddle
How this works:
You only need to join account_prices with prices to get all the data you need.
To get the account x stuff, concatenate "account " with the value of id_account using the concat() function
Finally, to get a concatenated group of values, use the group_concat() function. It works like any other aggregate function, but instead of performing an operation (like sum() or count()), it concatenates the values of the column (or expression). You can define the order you want for the output and a custom separator (the default separator is ,.
Hope this helps you.
how to set an unique primary key to all the table of database?
for example i don't wanted to repeat any primary key of different table.
table A:
----------
id | name
----------
1 | aaa
3 | bbb
5 | ccc
table B:
-------------
id | surname
-------------
7 | ddd
2 | eee
9 | fff
table C:
-------------
id | nickname
-------------
4 | ggg
6 | hhh
8 | iii
all id are primary key and auto_increment.
All the data is entered dynamically.I am using MYSQL in PHPMYADMIN.
You may add a new table to your schema called ID_Table that will have only one numeric column called current_id with default value of 0 ,when adding a new row to any other table of the schema you have to call a select on the ID_Table returning ID_Table.current_id + 1 as new id value.
Then updating ID_Table must be done
Update ID_Tableset ID_Table.current_id = ID_Table.current_id + 1
the GetNewId function could be implemented by
locking the ID_Table
Updating ID_Table
returning NewID
something like this (I have used Oracle syntax)
create table ID_Table(
current_id number
);
Insert into ID_Table values(0);
CREATE OR REPLACE Function GetNewId RETURN number is
new_id ID_Table.current_id%type;
row_count number;
begin
select nvl(ID_Table.current_id, 0) + 1
INTO new_id
FROM ID_Table
for update;
update ID_Table set ID_Table.Current_Id = new_id;
commit;
RETURN new_id;
end GetNewId;
You can get maximum ID from all three tables then add it in your insert query. But you have to remove the auto_increment attribute.
INSERT INTO TableA
SELECT MAX(ID)+1, 'jjj'
FROM
(SELECT MAX(ID) AS ID FROM TableA
UNION
SELECT MAX(ID) AS ID FROM TableB
UNION
SELECT MAX(ID) AS ID FROM TableC
) A;
See this SQLFiddle
Use the same sequence as the id generator for each inserted row, regardless of the table. Assuming you're using a DB that allows a sequence to be named as the id generator for the field.
This looks like it will do what you want in MySQL: http://devzone.zend.com/1786/mysql-sequence-generator/
Look at using Sequence. I'm not sure what DB you are using. Postgresql and Oracle have sequence that you can share between tables.
I have four columns in a table
Id Int
Name varchar(2)
Address varchar (4)
Active bit
and the source table with the same columns but have the varchar data type.
Id varchar(100)
Name varchar(100)
Address varchar (100)
Active varchar(100)
I have to transfer data from source table to destination table, but while transfering I need to check if the row I have has the correct data type for the destination. If not I need to transfer that complete row to some error table. ex.:
ID Name Address Active
1 A A 1
C B B 0
3 AAA C 1
4 D D 0
5 K K 102
if above represnt the source table and only rows 1 and 4 are eligible to tranfer to the destination table other rows will be moved to error table (may be with valid description, if possible)
Something like this
insert into destination
select * from source
where (isnumeric(ID)=1
and
(ID not like '%[^0-9]%')
and
RIGHT('00000000000'+ID,10) <= '2147483647'
)
and
len(name)<=2
and
len(Address)<=4
and
active in ('0','1')
So to insert into ERRORS table use NOT in WHERE
insert into ERRORS
select * from source
where
NOT
(
(isnumeric(ID)=1
and
(ID not like '%[^0-9]%')
and
RIGHT('00000000000'+ID,10) <= '2147483647'
)
and
len(name)<=2
and
len(Address)<=4
and
active in ('0','1')
)
SQLFiddle demo