Retrieve values in same row of SQL table - sql

I have a table that I use to calculate prices that looks up a table to get price per part and then multiplies that by number of parts ordered.
This number of parts ordered is in the same table however, and I can't seem to find a way to access values in the same row in a table when adding values.
Is this not possible, or are there better ways of doing this?
Here is the table this concerns:
CREATE TABLE PartOrder
(
OrderID INTEGER NOT NULL,
CustomerID INTEGER NOT NULL,
PartID INTEGER NOT NULL,
NumParts INTEGER NOT NULL,
Status CHAR(1) NOT NULL
CHECK (Status IN ('R', 'H',
'E', 'C')
OrderTime TIMESTAMP NOT NULL,
TotalCost DECIMAL,
CONSTRAINT partOrder_pk PRIMARY KEY (OrderID),
CONSTRAINT partOrder_fk1 FOREIGN KEY (CustomerID) REFERENCES Customer ON DELETE CASCADE,
CONSTRAINT partOrder_fk2 FOREIGN KEY (FlightID) REFERENCES Part ON DELETE CASCADE
);
I want it so that it will take the numParts value and multiply it by the price per part referenced in the parts table. however, I can't stick to hard values as the number ordered may change later, meaning that the totalPrice will change.
At the moment my insert statement is just:
INSERT INTO PartOrder VALUES (001, 001, 001, 4, 'R', NOW(), (4*(SELECT PricePerPart FROM Part WHERE PartID = 001)));

You might want to give a look at SELECT INTO as well
http://www.postgresql.org/docs/8.1/static/sql-selectinto.html
Or You can go with
INSERT INTO PartOrder
SELECT (1,1,1,4,'R',NOW, (4*Part.PricePerPart))
FROM Part
WHERE Part.PartId = 1;

Related

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

Relational Databases Check Constraint ORACLE

I am working on a project for Uni and I don't have much knowledge or experience with databases. I am trying to create a database in Oracle with a table that contains manufactured parts that can be of 2 types, say 1 and 2. When the part is of type 1 I will store in the table its location, when it's of type 2 I will store in the same table the lead time. Thus I will have null values for the other column in both cases (I am aware of the issues with the null values, but after thinking about it and researching what is the best way of dealing with this, I decided to do it like this, as I have only a small amount of atributes). My problem is in the CHECK CONSTRAINT. I tried to do it this way:
CREATE TABLE manufactured (
PID INT NOT NULL,
PARTTYPE NUMBER (1) NOT NULL,
CHECK (PARTTYPE IN (1,2)),
CONSTRAINT REFMAN FOREIGN KEY (PID, PARTTYPE) REFERENCES PART (PID, PARTTYPE),
LOCATION VARCHAR (50),
CONSTRAINT LOC CHECK (PARTTYPE=1 AND LOCATION IS NOT NULL),
CONSTRAINT LOC2 CHECK(PARTTYPE=2 AND LOCATION IS NULL),
LEAD_TIME VARCHAR (50),
CONSTRAINT LEADTIME CHECK (PARTTYPE=2 AND LEAD_TIME IS NOT NULL),
CONSTRAINT LEADTIME2 CHECK (PARTTYPE=1 AND LEAD_TIME IS NULL),
CONSTRAINT PK_MAN PRIMARY KEY (PID));
This is not working.
I tried to insert a record as follows:
insert into manufactured(PID, PARTTYPE, LOCATION) values(101,1,'Warehouse1');
And I get the error:
ORA-02290: check constraint (*****.LEADTIME) violated
I also tried:
insert into manufactured values (101,1,'Warehouse1');
And I get the error:
ORA-00947: not enough values
And finally with this:
insert into manufactured(PID, PARTTYPE, LEAD_TIME) VALUES (102, 2, '2 WEEKS');
I get the following error:
ORA-02290: check constraint (****.LEADTIME2) violated
Thank you in advance for your help.
This insert statement:
insert into manufactured(PID, PARTTYPE, LOCATION)
values(101,1,'Warehouse1');
...fails because your LEADTIME constraint requires that PARTTYPE=2. (It's an AND condition, so if PARTTYPE=1 the constraint will fail regardless of the value for LEAD_TIME.)
This is what I think you are looking for:
CREATE TABLE manufactured (
PID INT NOT NULL,
PARTTYPE NUMBER (1) NOT NULL,
CHECK (PARTTYPE IN (1,2)),
CONSTRAINT REFMAN FOREIGN KEY (PID, PARTTYPE) REFERENCES PART (PID, PARTTYPE),
LOCATION VARCHAR (50),
--CONSTRAINT LOC CHECK (PARTTYPE=1 AND LOCATION IS NOT NULL),
--CONSTRAINT LOC2 CHECK(PARTTYPE=2 AND LOCATION IS NULL),
CONSTRAINT LOC CHECK (PARTTYPE=1 AND LOCATION IS NOT NULL OR PARTTYPE=2 AND LOCATION IS NULL),
LEAD_TIME VARCHAR (50),
--CONSTRAINT LEADTIME CHECK (PARTTYPE=2 AND LEAD_TIME IS NOT NULL),
--CONSTRAINT LEADTIME2 CHECK (PARTTYPE=1 AND LEAD_TIME IS NULL),
CONSTRAINT LEADTIME CHECK (PARTTYPE=1 AND LEAD_TIME IS NULL OR PARTTYPE=2 AND LEAD_TIME IS NOT NULL),
CONSTRAINT PK_MAN PRIMARY KEY (PID));
Basically, make one constraint on each column that enforces the whole set of logic for that column.
If you really want two constraints on each column, you can do that too. If so, post a comment and I'll update this answer. I don't want to clutter/confuse the issue otherwise.
I don't know which RDBMS you use. For example in Oracle CHECK constraint accepts nulls.
As i see there are different attributes/datatypes for each party type. There are two approach:
split data into two separate tables. In this solution some triggers may be needed.
tab1: manufactured_1 (attributes+constraints for PID 1)
tab2: manufactured_2 (attributes+constraints for PID 2)
use "after insert/update" trigger - it'll set unnecessary data to null. For example, if in the table will be time for PID = 1 than trigger will set time value to null.
The Error ORA-00947: not enough values for
insert into manufactured values (101,1,'Warehouse1'); is obvious,
since the last column (lead_time) of the table(manufactured) is missing for the values list.
The Errors ORA-02290: check constraint stem from the dependent
conditions among the check constraints LEADTIME and LEADTIME2,
those should be combined as
CONSTRAINT LEADTIME CHECK ((PARTTYPE=2 AND LEAD_TIME IS NOT NULL) OR (PARTTYPE=1 AND LEAD_TIME IS NULL)).
The same logic works also for constraints LOC and LOC2 which should yield
CONSTRAINT LOC CHECK ((PARTTYPE=1 AND LOCATION IS NOT NULL) OR (PARTTYPE=2 AND LOCATION IS NULL))

How do I check the value of a foreign key on insert?

I'm teaching myself SQL using Sqlite3, well suited for my forever-game project (Don't we all have one?) and have the following tables:
CREATE TABLE equipment_types (
row_id INTEGER PRIMARY KEY,
type TEXT NOT NULL UNIQUE);
INSERT INTO equipment_types (type) VALUES ('gear'), ('weapon');
CREATE TABLE equipment_names (
row_id INTEGER PRIMARY KEY,
name TEXT NOT NULL UNIQUE);
INSERT INTO equipment_names (name) VALUES ('club'), ('band aids');
CREATE TABLE equipment (
row_id INTEGER PRIMARY KEY,
name INTEGER NOT NULL UNIQUE REFERENCES equipment_names,
type INTEGER NOT NULL REFERENCES equipment_types);
INSERT INTO equipment (name, type) VALUES (1, 2), (2, 1);
So now we have a 'club' that is a 'weapon', and 'band aids' that are 'gear'. I now want to make a weapons table; it will have an equipment_id that references the equipment table and weapon properties like damage and range, etc. I want to constrain it to equipment that is a 'weapon' type.
But for the life of me I can't figure it out. CHECK, apparently, only allows expressions, not subqueries, and I've been trying to craft a TRIGGER that might do the job, but in short, I can't quite figure out the query and syntax, or how to check the result that as I understand it will be in the form of a table, or null.
Also, are there good online resources for learning SQL more advanced than W3School? Add them as a comment, please.
Just write a query that looks up the type belonging to the new record:
CREATE TRIGGER only_weapons
BEFORE INSERT ON weapons
FOR EACH ROW
WHEN (SELECT et.type
FROM euqipment_types AS et
JOIN equipment AS e ON e.type = et.equipment_type_id
WHERE e.row_id = NEW.equipment_id
) != 'weapon'
BEGIN
SELECT RAISE(FAIL, "not a weapon");
END;
The foreign key references should be to the primary key and to the same time. I would phrase this as:
CREATE TABLE equipment_types (
equipment_type_id INTEGER PRIMARY KEY,
type TEXT NOT NULL UNIQUE
);
INSERT INTO equipment_types (type) VALUES ('gear'), ('weapon');
CREATE TABLE equipment_names (
equipment_name_id INTEGER PRIMARY KEY,
name TEXT NOT NULL UNIQUE
);
INSERT INTO equipment_names (name) VALUES ('club'), ('band aids');
CREATE TABLE equipment (
equipment_id INTEGER PRIMARY KEY,
equipment_name_id INTEGER NOT NULL UNIQUE REFERENCES equipment_names(equipment_name_id),
equipement_type_id INTEGER NOT NULL REFERENCES equipment_types(equipement_type_id)
);
I would not use the name row_id for the primary key. That is the built-inn default, so the name is not very good. In SQLite, an integer primary key is automatically auto-incremented (see here).

How I can get an auto incremented value

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

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 :)