How I can get an auto incremented value - sql

I have here a table that corresponds to the orders of the customers. I use AUTO_INCREMENT to determine the ID of the order. I have this SQL code to the orders table:
CREATE TABLE IF NOT EXISTS `orders` (
`order_id` int(11) NOT NULL AUTO_INCREMENT,
`customer_id` int(11) NOT NULL,
`customer_name` varchar(500) NOT NULL,
`order_total_price` decimal(20, 2) NOT NULL,
`order_date` varchar(100) NOT NULL,
PRIMARY KEY (`order_id`)
) ENGINE=InnoDB
What I need is to insert each of the products of that order in another table with a Foreign Key order_id to specify what order that products belongs to. The SQL code for the purchased_products table is:
CREATE TABLE IF NOT EXISTS `purchased_products` (
`order_id` int (11) NOT NULL,
FOREIGN KEY (`order_id`) REFERENCES orders(`order_id`),
`product_name` varchar(500) NOT NULL,
`product_price` decimal(20, 2) NOT NULL,
`product_quantity` int(11) NOT NULL,
PRIMARY KEY (`order_id`)
)
When the user buy something, I use this to insert the data in the orders table:
INSERT INTO orders (customer_id, customer_name, order_total_price, order_date)
VALUES ('{$customer_id}', '{$customer['customer_name']}', '{$order_total_price}', '{$order_date}')";
And here is my problem. I need to insert in the purchased_products table the products with the Order ID generated:
INSERT INTO purchased_products (order_id, product_name, product_price, product_quantity)
VALUES ('*/The ID of the order need to goes here*/', '{$product['product_name']}', '{$product['product_price']}', '{$product['quantity']}')";
This is giving me a headache. I'm not really knowing how to do it. This should be done by a different way? How do I associate the order ID to the products belonging to it?

use function last_insert_id(). it will give you value that was auto-incremented as last one before call to it.

You can get the get the last inserted primary key value by using ##IDENTITY
Here's the MSDN article: https://msdn.microsoft.com/en-us/library/ms187342.aspx
USE AdventureWorks2012;
GO
--Display the value of LocationID in the last row in the table.
SELECT MAX(LocationID) FROM Production.Location;
GO
INSERT INTO Production.Location (Name, CostRate, Availability, ModifiedDate)
VALUES ('Damaged Goods', 5, 2.5, GETDATE());
GO
SELECT ##IDENTITY AS 'Identity';
GO
--Display the value of LocationID of the newly inserted row.
SELECT MAX(LocationID) FROM Production.Location;
GO
I would also recommend wrapping the statement in a TRANSACTION so that if any errors occur you can rollback.

As others have commented it depends on the RDBMS. In Oracle you typically use sequences. You create and store the sequence on the database and can use it on an INSERT by doing sequencename.nextval().
Sequences let you control starting values, increment/decrement size, caching and a lot more.

I did it by using PDO lastInsertId() to get the ID of last inserted order:
$sql = "INSERT INTO orders (customer_id, customer_name, order_total_price, order_date)
VALUES ('{$customer_id}', '{$customer['customer_name']}', '{$order_total_price}', '{$order_date}')";
$query = $connection->prepare($sql);
$query->execute();
$respective_order_id = $connection->lastInsertId();
And then:
INSERT INTO purchased_products (order_id, product_name, product_price, product_quantity)
VALUES ('{$respective_order_id}', '{$product['product_name']}', '{$product['product_price']}', '{$product['quantity']}')";
Thanks for all who tried to help! They put me in the right way!

you can use SCOPE_IDENTITY() to retrieve the last identity you inserted within the current sql session.
here is another question with a great description of all the differences:
identity scope Question

Related

manually updating primary key

We are dealing with legacy code that doesn't auto-increment the primary key (see serial) so I have to manually do it. What is the correct way to manually update the primary key field on insert. I am getting an error when I do the below
Table:
CREATE TABLE pizza (
id bigint not null,
price int
)
Insert statement:
INSERT INTO pizza
(id, price)
VALUES
(
(SELECT max(id) from pizza)+1,
1.75
)
Don't use max()+1 to generate a primary key. It's not safe for concurrent inserts and it doesn't really scale well.
Just create a sequence and use that:
create sequence pizza_id_seq;
Then synchronize it with the current values in the table:
select setval('pizza_id_seq', coalesce(max(id),1))
from pizza;
Then, instead of changing your INSERT statements to use the dreaded max() + 1, just use the sequence:
INSERT INTO pizza
(id, price)
VALUES
(nextval('pizza_id_seq'), 1.75)

I have come across an error in SQL and cannot fix this foreign key error. See desc for more information

I have been receiving the error code 1452, i am trying to add keys to a table to keep data unqiue and useable in other tables. i have created the tables and can use the information already entered but i want to make the databases properly so i am trying to use the keys. please refer to the code below.
CREATE TABLE CUSTOMERS (
CustID varchar(50) NOT NULL,
Client_Name varchar(50) NOT NULL,
Client_Address varchar(80) NOT NULL,
PRIMARY KEY (CustID)
);
CREATE TABLE ORDERS (
Order_ID VARCHAR(10) NOT NULL,
Client_NameID varchar(50) NOT NULL,
Dates varchar(10) NOT NULL,
PRIMARY KEY (Order_ID),
FOREIGN KEY (Client_NameID) REFERENCES CUSTOMERS(CustID)
);
SELECT * FROM CUSTOMERS;
SELECT * FROM ORDERS;
DESCRIBE Orders; /*Used to display the Table*/
ALTER TABLE ORDERS ADD Dates VARCHAR(10); /*Used to add columns into the table*/
ALTER TABLE ORDERS DROP COLUMN Date; /*Used to remove column from the table*/
INSERT INTO CUSTOMERS (CustID, Client_Name, Client_Address) VALUES
('168', 'Coventry Building Services', 'Units 2-4, Binley Industrial Estate, CV3 2WL'), /*Used to insert values into the columns*/
('527', 'Allied Construction LTD', '34, Lythalls La Industrial Estate, NG18 5AH'),
('169', 'Ricoh Builds Ltd', 'Unit 12, Stoneleigh Park, CV8 2UV'),
('32', 'British Embassy in Tehran', '198 Ferdowski Avenue Tehran 11316-91144 Iran');
INSERT INTO ORDERS (Order_ID, Client_NameID, Dates) VALUES
('CON-2237', 'Coventry Building Services', '2014-12-14'),
('CON-3664', 'Allied Construction LTD', '2015-01-16'),
('CON-2356', 'Ricoh Builds Ltd', '2015-02-12'),
('CON-1234', 'British Embassy in Tehran', '2015-04-16');
DELETE FROM ORDERS WHERE Client_Name='Coventry Building Services'; /*Used to delete specific
data from the specific row and column wherever applicable*/
DROP TABLE CUSTOMERS;
DROP TABLE ORDERS;
Below are the tables im trying to work with, all of them will pretty much have a key that links them together if necessary
The CustomerS Table which only includes a Primary Key
The Orders Table which includes a Primary and Foreign key
The problem is with the inserts into table orders. Your foreign key on Client_NameIDreferencesCUSTOMERS(CustID), but you are giving the CUSTOMERS(Client_Name) instead.
You probably want:
INSERT INTO ORDERS (Order_ID, Client_NameID, Dates) VALUES
('CON-2237', 'CON-2237', '2014-12-14');
('CON-3664', 'CON-3664', '2015-01-16');
('CON-2356', 'CON-2356', '2015-02-12');
('CON-1234', 'CON-1234', '2015-04-16');
Notes:
You can perform all inserts in a single query by passing several tuples of values, as shown above
Don't store dates as strings; instead, use the date datatype, which exists for that purpose. I changed the query so it uses proper date literals, which would fit in a date column
it is unclear why you want to use the same value for the primary key of customers and orders - to me, this makes things harder to follow. I would recommend just using auto-incremented primary keys

Dataintegrity between tables in SQL Server

Is it possible to add data integrity between columns in different tables in SQL Server?
I have table Pay with column Date and table Orders with column DateofOrder. And I would like to add the data integrity so the Date cannot be earlier than the DateofOrder.
And when the user insert there the same date or even earlier database would show error.
I think you mean something like this, here done with a trigger;
CREATE TRIGGER trig_pay ON Pay
FOR INSERT, UPDATE
AS
IF EXISTS(SELECT *
FROM [Order] o
JOIN inserted i
ON o.id = i.payment_id
WHERE DateOfOrder>[date])
BEGIN
RAISERROR ('Sorry, Dave', 16, 1)
ROLLBACK;
RETURN;
END
INSERT INTO [Order] values (1, GETDATE()); -- Order today
INSERT INTO Pay values (1, DATEADD(dd, -1, getdate())); -- Pay yesterday
> Sorry, Dave
Yes, you can do it by using INSTEAD OF INSERT Trigger.
You would have to use an INSTEAD OF or AFTER trigger to enforce this, you can't do it declaratively. Well you could use a check constraint with a TVF or something but I've never tried that.
I'd show sample code but I'm not sure what payroll has to do with orders. If a new order comes in, what pay date must be later than or equal to the order date? Is there some other column that relates these two tables?
It is possible without resorting to triggers.
The idea is to add the DateofOrder in the Orders table to its existing key -- let's call it order_id -- to create a compound superkey, then reference this superkey (rather than the simple key solely order_id) in the Pay table.
Here are the bare bones:
CREATE TABLE Orders
(
order_id CHAR(10) NOT NULL,
DateofOrder DATE NOT NULL,
UNIQUE (order_id), -- simple candidate key
UNIQUE (DateofOrder, order_id) -- compund superkey
);
CREATE TABLE Pay
(
order_id CHAR(10) NOT NULL,
DateofOrder DATE NOT NULL,
FOREIGN KEY (DateofOrder, order_id)
REFERENCES Orders (DateofOrder, order_id),
DateOfPayment DATE NOT NULL,
CHECK (DateofOrder < DateOfPayment),
UNIQUE (order_id)
);

How can I insert a set of child records while updating the parent?

I'm using SQL Server 2005 and wish to create a number address records, updating the contact records with the new Id's:
Take the following tables
create table contact(id int primary key identity, home_address_id int, work_address_id int)
create table address(id int primary key identity, street varchar(25), number int)
And foreign keys:
ALTER TABLE dbo.contact ADD CONSTRAINT FK_contact_address1 FOREIGN KEY (home_address_id) REFERENCES dbo.address(id)
ALTER TABLE dbo.contact ADD CONSTRAINT FK_contact_address2 FOREIGN KEY (work_address_id) REFERENCES dbo.address(id)
some dummy data
insert into contact default values
insert into contact default values
insert into contact default values
How can I insert a default empty address record for all contacts who have no home address, and update the home_address_id in one go?
The first part is simple:
insert into address(street) select null from contact where home_address_id is null
I can even get the newly create address id's:
declare #addressTable table(id int)
insert into address(street)
OUTPUT INSERTED.Id INTO #addressTable
select null from contact where home_address_id is null
Here's the new id's
select * from #addressTable
But how to update the contact table with these new Id's?
If possible, I would suggest normalizing your database by adding a Contact_Addresses table:
CREATE TABLE Contact_Addresses
(
contact_id INT NOT NULL,
address_id INT NOT NULL,
address_type VARCHAR(10) NOT NULL,
CONSTRAINT PK_Contact_Addresses PRIMARY KEY CLUSTERED (contact_id, address_id, address_type),
CONSTRAINT FK_ContactAddresses_Contacts (contact_id) REFERENCES Contacts (id),
CONSTRAINT FK_ContactAddresses_Addresses (address_id) REFERENCES Addresses (id),
CONSTRAINT CK_ContactAddresses_address_type CHECK address_type IN ('HOME', 'WORK')
)
Next, I would suggest not putting "dummy" records in your database. It's going to end up causing headaches down the road. The database should contain an accurate record of the data in your system. If you want to display some value by default when no address exists in the system for a contact then handle that in your UI.
If you really must though, then the following code should do the trick:
;WITH C_CTE AS
(
SELECT
id,
home_address_id,
ROW_NUMBER() OVER(ORDER BY id) AS seq
FROM
Contacts
),
(
SELECT
id,
ROW_NUMBER() OVER(ORDER BY id) AS seq
FROM
Addresses
)
UPDATE
C_CTE
SET
home_address_id = A.id
FROM
C_CTE C
INNER JOIN A_CTE A ON A.seq = C.seq
I would do it from the moment you get a new contact, thusly:
[receive contact information]
//prior to inserting contact
declare #homeAddress int, #workAddress int
[insert home address here (real or default based on input)]
set #homeAddress = ##Identity
[insert work address here (real or default)]
set #workAddress = ##Identity
[insert contact here referencing #homeAddress & #workAddress]
For the stuff already in your table, you're going to have to associate all of your null value ids to a contact id. Or, you could clear out your null value addresses, and modify the above statement to an update somehow (brain's not working at the moment, so all I'm coming up with is a cursor, and cursors are evil).

How can I insert into tables with relations?

I have only done databases without relations, but now I need to do something more serious and correct.
Here is my database design:
Kunde = Customer
Vare = Product
Ordre = Order (Read: I want to make an order)
VareGruppe = ehm..type? (Read: Car, chair, closet etc.)
VareOrdre = Product_Orders
Here is my SQL (SQLite) schema:
CREATE TABLE Post (
Postnr INTEGER NOT NULL PRIMARY KEY,
Bynavn VARCHAR(50) NOT NULL
);
CREATE TABLE Kunde (
CPR INTEGER NOT NULL PRIMARY KEY,
Navn VARCHAR(50) NOT NULL,
Tlf INTEGER NOT NULL,
Adresse VARCHAR(50) NOT NULL,
Postnr INTEGER NOT NULL
CONSTRAINT fk_postnr_post REFERENCES Post(Postnr)
);
CREATE TABLE Varegruppe (
VGnr INTEGER PRIMARY KEY,
Typenavn VARCHAR(50) NOT NULL
);
CREATE TABLE Vare (
Vnr INTEGER PRIMARY KEY,
Navn VARCHAR(50) NOT NULL,
Pris DEC NOT NULL,
Beholdning INTEGER NOT NULL,
VGnr INTEGER NOT NULL
CONSTRAINT fk_varegruppevgnr_vgnr REFERENCES Varegruppe(VGnr)
);
CREATE TABLE Ordre (
Onr INTEGER PRIMARY KEY,
CPR INTEGER NOT NULL
CONSTRAINT fk_kundecpr_cpr REFERENCES Kunde(CPR),
Dato DATETIME NOT NULL,
SamletPris DEC NOT NULL
);
CREATE TABLE VareOrdre (
VareOrdreID INTEGER PRIMARY KEY,
Onr INTEGER NOT NULL
CONSTRAINT fk_ordrenr_onr REFERENCES Ordre(Onr),
Vnr INTEGER NOT NULL
CONSTRAINT fk_varevnr_vnr REFERENCES Vare(Vnr),
Antal INTEGER NOT NULL
);
It should work correctly.
But I am confused about Product_Orders.
How do I create an order? For example, 2 products using SQL INSERT INTO?
I can get nothing to work.
So far:
Only when I manually insert products and data into Product_Orders and then add that data to Orders = which makes it complete. Or the other way around (create an order in with 1 SQL, then manually inserting products into Product_orders - 1 SQL for each entry)
You should first create an order and then insert products in the table Product_Orders. This is necessary because you need an actual order with an id to associate it with the table Product_Orders.
You always should create a record in the foreign-key table before being able to create one in your current table. That way you should create a "Post", customer, type, product, order and product_order.
Try this ...
first you have to insert a customer
insert into kunde values(1, 'navn', 1, 'adresse', 1)
then you insert a type
insert into VareGruppe values(1, 'Type1')
then you insert a product
insert into vare values(1, 'product1', '10.0', 1, 1)
then you add an order
insert into ordre values(1, 1, '20090101', '10.0')
then you insert a register to the product_orders table
insert into VareOrdre values (1, 1, 1, 1)
I think this is it. :-)
As the primary keys are autoincrement, don't add them to the insert and specify the columns like this
insert into vare(Nav, Pris, Beholdning, VGnr) values('product1', '10.0', 1, 1)
Use Select ##identity to see the onr value
I think you already have the hang of what needs to happen. But what I think you are getting at is how to ensure data integrity.
This is where Transactions become important.
http://www.sqlteam.com/article/introduction-to-transactions
Is it the SalesPrice (I'm guessing that's what SamletPris means) that's causing the issue? I can see that being a problem here. One common design solution is to have 2 tables: Order and OrderLine. The Order is a header table - it will have the foreign key relationship to the Customer table, and any other 'top level' data. The OrderLine table has FK relationships to the Order table and to the Product table, along with quantity, unit price, etc. that are unique to an order's line item. Now, to get the sales price for an order, you sum the (unit price * quantity) of the OrderLine table for that order. Storing the SalesPrice for a whole order is likely to cause big issues down the line.
A note just in case this is MySQL: If you're using MyISAM, the MySQL server ignores the foreign keys completely. You have to set the engine to InnoDB if you want any kind of integrity actually enforced on the database end instead of just in your logic. This isn't your question but it is something to be aware of.
fbinder got the question right :)