Mysql tables relationships / Foreign key? - php

I'm having a hard time figuring how to link database rows in a PHP / MySql project. My order submission script currently splits information and stores it into 2 tables.
The first one is called "Orders" and contains:
$OrderId, $CustomerName, $CustomerEmail, $OrderTotal, $OrderTaxes
//and other infos about the ORDER
The second one is called "Items" and contains all the BOUGHT products infos:
$ProductId, $OrderedQty
//for each one and such...
It has to be this way because the "Items" table will be searched by different "departments" who will only be shown the parts of the orders they are responsible for.
But they all have to get the "Orders" infos for shipping purposes.
Knowing that the "OrderId" column is a primary key generated on the "Orders" table itself, and that my INSERT TO commands are both executed at the same time, how can I link an "Order Id" column in both tables ?
Do I have to generate some random key to match them ?
If I were to use a foreign key, how would the database know which product goes with which order since they are submited at the same time ?
Or is it fast enough to INSERT in "Orders" -> SELECT $OrderID -> INSERT in "Items" ?
How does one usually do this ? Can't figure this one out.
Thanks in advance for your precious help!

The bought product info should have an extra column the bought product tables called orderid, so you know which products belong to which order.
As for the inserting in to the database this depends on what you are using to execute the queries. Some query classes allow you to run multiple query statements in one go, if this is the case you could run something similar to:
INSERT INTO Orders (OrderId, CustomerName, CustomerEmail, OrderTotal, OrderTaxes) Values(...)
SET #order_id = LAST_INSERT_ID();
INSERT INTO boughtItems (OrderId,ProductId,OrderedQty) Values (#order_id, :productid_1, :name_1),(#order_id, :productid_2, :name_2),(#order_id, :productid_3, :name_3) ....
In order cases you would need to run the insert statement on orders and then obtain the primary key.
Take a look at these links:
In other cases you could use a class which allows you to obtain the last inserted id. This id is connection bound so should give no issues (as long as the insert works, you are not doing multiple inserts in one query, do rollbacks or other weird stuff).
In this case you would do an insert and then call a secondary function to get the inserted id.
See these links:
mysqli insert id
pdo last insert id
mysql insert id
Alternatively you could also execute 2 queries. First the insert query followed by this query:
SELECT LAST_INSERT_ID() as id;
Other related links:
mysql - last_insert_id function
Related post on dba stackexchange

Related

Using OUTPUT-like clause after INSERT INTO in MySQL

I have a table which has id, name ,surname columns. When I add a new line to table, id increases by 1 since its AI and PK. Now how I get back latest id variable with OUTPUT command?
"INSERT INTO table (name, surname) VALUES ('mike', 'hensen') OUTPUT ?????? how to continue ????"
edit LAST_INSERT_ID() is not a very good method since in a big webpage there could be a lot adding per second.
I'm pretty sure that LAST_INSERT_ID() is exactly what you want. It returns the last id inserted on a per connection basis, not the last one inserted (documented here). Presumably, different web users would have different connections, so using the function does what you want.
If you want the last id that was inserted over all connections, but not necessarily from your most recent insert, then you can look at the auto_increment value in the metadata.

Issue in copying rows from one table to another

I am implementing a request mechanism where the user have to approve a request. For that i have implemented a temporary table and main table. Initially when the request is added the data will be inserted to the temporary table, on approval it will be copied to the main table.
The issue is there will be more than 5k rows to be moved to the main table after approval + another 3-5 row for each row in the detail table (stores the details).
My current implementation is like this
//Get the rows from temporary table (batch_temp)
//Loop through the data
//Insert the data to the main table (batch_main) and return the id
//Get the details row from the temporary detail table (batch_temp_detail) using detail_tempid
//Loop through the data
//Insert the details to the detail table (batch_main_detail) with the main table id amount_id
//End Loop
//End Loop
But this implementation would take atleast 20k queries. Is there any better ways to implement the same.
I tried to create a sqlfiddle but was unable to create one. So i have pasted the query in pgsql.privatepaste.com
I'm sorry that I'm not familiar with PostgreSQL. My solution is in MySQL, I hope it can help since if they (MySQL & PostgreSQL) are same.
First, we should add 1 more field into your batch_main table to track the origin batch_temp record for each batch_main record.
ALTER TABLE `batch_main`
ADD COLUMN tempid bigint;
Then, on approval, we will insert 5k rows by 1 query:
INSERT INTO batch_main
(batchid, userid, amount, tempid)
SELECT batchid, userid, amount, amount_id FROM batch_temp;
So, with each new batch_main record we have its origin batch_temp record's id. Then, insert the detail records
INSERT INTO `batch_main_detail`
(detail_amount, detail_mainid)
SELECT
btd.detail_amount, bm.amount_id
FROM
batch_temp_detail `btd`
INNER JOIN batch_main `bm` ON btd.detail_tempid = bm.tempid
Done!
P/S:
I'm confuse a bit about the way you name your fields, and since I do not know about PostgreSQL and by looking into your syntax, can you use same sequence for primary key of both table batch_temp & batch_main? If you can, it's no need to add 1 more field.
Hope this help,
Simply need to update your Schema. Instead of having two tables: one main and one temporary, you should have all the data in main table, but have a flag which indicates whether a certain record is approved or no. Initially it will be set to false, and once approved it will simply be set to true and then the data can display on your website etc. That way you will not need to write the data two times, or even have to move it from one table to another
You haven't specified RDBMS you are using, but good old INSERT with SELECT in it must do the trick in one command:
insert main (field1,...,fieldN) select field1,...,fieldN from temporary

Inserting mysql foreign keys and primary keys in a transaction.

Just looking for some tips and pointers for a small project I am doing. I have some ideas but I am not sure if they are the best practice. I am using mysql and php.
I have a table called nomsing in the database.
It has a primary key called row id which is an integer.
Then I have about 8 other tables referencing this table.
That are called nomplu, accsing,accplu, datsing, datplu for instance.
Each has a column that references the primary key of nomsing.
Withing my php code I have all the information to insert into the tables except one thing , the row id primary key of the nomsing table. So that php generates a series of inserts like the following.
INSERT INTO nomsing(word,postress,gender) VALUES (''велосипед","8","mask").
INSERT INTO nomplu(word,postress,NOMSING?REFERENCE) VALUES (''велосипеды","2",#the reference to the id of the first insert#).
There are more inserts but this one gets the point across. The second insert should reference the auto generated id for the first insert. I was this to work as a transaction so all inserts should complete or none.
One idea I have is to not auto generate the id and generate it myself in php. That way would know the id given before the transaction but then I would have to check if the id was already in the db.
Another idea I have is to do the first insert and then query for the row id of that insert in php and then make the second insert. I mean both should work but they don't seem like an optimal solution. I am not too familiar with the database transactional features but what would be the best approach to do in this case. I don't like the idea of inserting then querying for the id and then running the rest of the queries. Just seems very inefficient or perhaps I am wrong.
Just insert a row in the master table. Then you can fetch the insert id ( lastInserId when on PDO) and use that to populate your other queries.
You could use the php version as given by JvdBerg , or Mysql's LAST_INSERT_ID. I usually use the former option.
See a similar SO question here.
You could add a new column to the nomsing table, called 'insert_order' (or similar) with a default value of 0, then instead of generating one SQL statement per insert create a bulk insert statement e.g.
INSERT INTO nomsing(word,postress,gender, insert_order)
VALUES (''велосипед","8","mask",1), (''abcd'',"9","hat",2).....
you generate the insert_order number with a counter in your loop starting at one. Then you can perform one SELECT on the table to get the ids e.g.
SELECT row_id
FROM nomsing
WHERE insert_order > 0;
now you have all the IDs you can now do a bulk insert for your following queries. At the end of your script just do an update to reset the insert_order column back to 0
UPDATE nomsing SET insert_order = 0 WHERE insert_order > 0;
It may seem messy to add an extra column to do this but it will add a significant speed increase over performing one query at a time.

PHP -MySQL insert and select statements - how to make them atomic?

Im new to PHP and I was wondering how I can overcome this seemingly simple problem:
I have a database with several tables. Of them 1 table is called "order_header". Order header has a field called "orderID" which is the primaryKey and is auto-incremented. OrderID is used in other tables in the database (food_table, drinks_table, merchant_info, customer_info, etc)and is unique to a particular order.
Now I insert data into the order_header using the usual INSERT statement and the order_header generates a new orderID. But now I need to retrieve the orderID I just created and use it to insert data into other tables of that database.
The question is how can I do both inserting data and retrieving the resulting orderID in one atomic method? I cannot use the mySQL query to get the last orderID because what if another thread has inserted an entry in orderID in the meanwhile.
In Java I guess one could use locks and the word #synchronized, but how would one do this in PHP?
Use mysql_insert_id straight after the query. It doesn't run another query to find the last ID

splitting data into multiple tables

I am building a employees page.
Some of the information goes into an 'employees' table but some of it goes into a 'availability' table that is referenced to the 'employee' table:
availability:
id / employeeid (unique id from employees table) / monday available / and on and on /
So I don't have that unique ID from the employees table until I create them.
Is it fine to do a query where I set the employee info and then a query to get the last created row in the employee table and then use the unique id from that to set the availability...
Or is that messy and should I have a create employee page and THEN a set availability page?
So basically I want to know if it is cleaner and 'better' coding to separate the two functions?
Adding to #Quassnoi's answer:
You would add the employee record, then use the MySQL LAST_INSERT_ID() function to find the autoincremented unique id for the employee record you added. You can then feed that value back into the availability INSERT statement.
More details are on the MySQL manual page at http://dev.mysql.com/doc/refman/5.1/en/example-auto-increment.html
It's important that you not use a SELECT statement (e.g. SELECT MAX(employee.id)) since there might be other uses adding records as well. LAST_INSERT_ID() is specific to your connection
Of course create employee first, availability then.
If your tables are InnoDB, you can do it in a transaction so that you can rollback the whole update if something goes wrong.
Is it fine to do a query where I set
the employee info and then a query to
get the last created row in the
employee table and then use the unique
id from that to set the
availability...
Yes, that sounds OK. If you use an autoincrement column for employeeid, you can then use mysql_insert_id() or equivalent to retrieve that last inserted id safely. Don't do SELECT MAX(employeeid) FROM ...., because you might get problems when loads of people are using it concurrently.
You can easily get the last insered record via
mysql_insert_id()
After that, you can insert an availability record for the desired employee.
Note: I would choose a framework that takes care of these issues, like Symfony or Cake.
Using the "last created row" may not always work the way that you're expecting and may complicate things in the future if there's growth or if another programmer assumes the project. If I understand what you're looking for, you should instead have 3 tables. One table for employees, one table for availability, and a third table should be used to store unique records for the association. In the association table each row will have columns for : a unique ID, the employee id, the availability id.

Categories