SQL database design advice needed - sql

My Database:
CREATE DATABASE `cars` /*!40100 DEFAULT CHARACTER SET latin1 */;
DROP TABLE IF EXISTS `cars`.`employees`;
CREATE TABLE `cars`.`employees` (
`emp_id` int(11) NOT NULL AUTO_INCREMENT,
`first_name` varchar(40) DEFAULT NULL,
`last_name` varchar(40) DEFAULT NULL,
PRIMARY KEY (`emp_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
DROP TABLE IF EXISTS `cars`.`products`;
CREATE TABLE `cars`.`products` (
`prod_id` int(11) NOT NULL AUTO_INCREMENT,
`prod_name` varchar(40) DEFAULT NULL,
`prod_price` varchar(40) DEFAULT NULL,
PRIMARY KEY (`prod_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
That is my database query. I have task to create database of CARS which contains informations about employees and cars, also the database must contain information about which car is sold and which worker sold it.
My Question: How can I store a sale, so that I record which employee has sold which cars.

Possibly create a table for holding which employees sold which cars?
EmployeeSales
---------------
emp_id
prod_id
OtherInfo

This is a design decision that goes over the 1NF direction you ( or somebody else over your organization ) must considerate prior to development. To respond your concrete question, this is the typical case where a XRef table is needed to put together all the Customer-Vehicle associations along with extra details refered to the solds.
Ie:
Sale table:
-----------------------------
sale_id autonumeric(1,1) PK
, emp_id int FK
, prod_id int FK
, price decimal(10,2)
, sold_date datetime(2)
, other_interesting_sale_details
This is one possible solution that will keep historical info about which car was sold by a specific employee plus additional details it may be of interest for the particular business.
I hope it helps.

depends on how expansive you want to go... you have a products table... will this be it for your cars and every car will just be added to this directly? If so, then you could just tack on two fields
In the products table, add a column "SoldBy" as integer. This could be a link to the employees table Employee ID.
if the value is populated, it's sold, and if sold, it is the employee who sold it.

Related

SQL - cannot add or update a child row: a foreign key constraint fails

I keep getting the error:
Cannot add or update a child row: a foreign key constraint fails
(myWork.Bookingss, CONSTRAINT Bookingss_ibfk_1 FOREIGN KEY
(CustomersID) REFERENCES Customers (CustomersID))
I have spent a while researching as this is apart of a school assignment and can not seem to resolve the problem.
Here is my SQL code:
USE myWork ;
DROP TABLE IF EXISTS Bookingss ;
DROP TABLE IF EXISTS Customers ;
CREATE TABLE myWork.Customers
(
CustomersID INT NOT NULL AUTO_INCREMENT,
Surname CHAR(30) NOT NULL ,
FirstName CHAR(30) NOT NULL ,
Title CHAR(10),
DOB DATE,
HouseNumber INT,
StreetName CHAR(30),
Town CHAR(30),
PostCode CHAR(9),
Telephone INT,
PRIMARY KEY (CustomersID)
) ;
CREATE TABLE myWork.Bookingss
(
BookingsID INT NOT NULL AUTO_INCREMENT,
CustomersID INT NOT NULL,
AdultsBooked INT NOT NULL,
ChildrenBooked INT NOT NULL,
Check_In DATE,
Check_Out DATE,
PRIMARY KEY (BookingsID),
FOREIGN KEY (CustomersID)
REFERENCES myWork.Customers (CustomersID)
) ;
SHOW TABLES ;
INSERT INTO myWork.Bookingss ( CustomersID, AdultsBooked , ChildrenBooked , Check_In , Check_Out )
VALUES ("1", "2", "3", "2022-04-10", "2022-04-13" ) ;
INSERT INTO myWork.Customers ( Surname , FirstName , Title , DOB )
VALUES ( "smith" , "ryan" , "Mr" , "1998-02-16" ) ;
SELECT * FROM Customers , Bookingss;
You got the order wrong and some challenges to overcome. You are trying to insert a booking first, and this with an id for a customer that does not yet exist in the customer table at that moment.
You have to insert the customer first, then use the customer's id to insert the booking for the customer (using his id).
And there is the first challenge. The customer id is an auto increment field. You would not know the id when you insert a customer in the table.
You would have to fetch the customer and use the id of that customer to insert a booking for the customer. How do you fetch the customer? Selecting the customer with a specific name surname and first name is not a correct choice, any other field (or composition of fields) that I see in the table definition is not a good choice neither.
You'd need to think further about a good solution. There are several options I could tell you about. But the appropriate solution depends on your assignment/context.
By the way, the last select clause may not deliver the result you expect. You are producing a cartesian product (every row of the first table with every row of the second table). What you probably want is a JOIN where you link the first table with the second table accordingly (e.g. using the primary key and the foreign key).

How do I create a IF statement creating a table in Postgres?

I'm creating a table and I need a check constraint to validate the posibles values given a string value. I'm creating this table:
CREATE TABLE cat_accident (
acc_type VARCHAR(30) NOT NULL CHECK(acc_type = 'Home accident' OR acc_type = 'Work accident'),
acc_descrip VARCHAR(30) NOT NULL
);
So basically I want to validate if acc_type is equal to Home accident, then acc_descrip can be or 'Intoxication' OR 'burns' OR 'Kitchen wound', OR if acc_type is equal to Work Accident, then acc_descrip can be OR 'freezing' OR 'electrocution'.
How do I write that constraint?
Use a CHECK constraint with a CASE expression:
CREATE TABLE cat_accident (
acc_type VARCHAR(30) NOT NULL,
acc_descrip VARCHAR(30) NOT NULL
CHECK(
CASE acc_type
WHEN 'Home accident' THEN acc_descrip IN ('Intoxication', 'burns', 'Kitchen wound')
WHEN 'Work accident' THEN acc_descrip IN ('freezing', 'electrocution')
END
)
);
See the demo.
I'd suggest implementing this with a lookup table:
CREATE TABLE l_accident_description(
description_id VARCHAR(5) PRIMARY KEY,
description_full VARCHAR(30) NOT NULL UNIQUE,
location VARCHAR(30)
);
INSERT INTO l_accident_description
(description_id,description_full,location)
VALUES
('INTOX','Intoxication','Home Accident'),
('BURNS','Burns','Home Accident'),
('K_WND','Kitchen wound','Home Accident'),
('FREEZ','Freezing','Work Accident'),
('ELECT','Electrocution','Work Accident');
That way you can encode the relationship you want to encode into cat_accident, but if the details ever change, it's only a matter of inserting/deleting/updating rows in your lookup table. This implementation has the added benefit that you're not storing as much data repetitively in your table (just a VARCHAR(5) code rather than a VARCHAR(30) string). The table construction then becomes (with added primary key):
CREATE TABLE cat_accident (
cat_accident_id PRIMARY KEY,
acc_descrip VARCHAR(5) NOT NULL REFERENCES l_accident_description(description_id)
);
Any time you wanted to know whether the accident Home/Work, this could be accomplished with a query joining the lookup table. Joining lookup tables is more in the spirit of good database construction, rather than hard-coding checks to tables that may easily change or grow more complex as the database grows.
In fact, the ideal solution might be to create two lookup tables here, with l_accident_description in turn referencing a location lookup, but for simplicity's sake I've shown how it might be accomplished with one.

Creating table when each object may have a list of values

First I've created a table with information on stores and transactions with the following query:
CREATE TABLE main.store_transactions
(
store_id varchar(100) NOT NULL,
store_name varchar(100),
store_transaction_id varchar(100),
transaction_name varchar(100),
transaction_date timestamp,
transaction_info varchar(200),
primary_key(store_id)
)
But then I realized that the same store may have various transactions related to it, not just one. How should I implement table creation in this case?
One thing that comes to mind is to create a separate table with transactions, each transaction having store_id as a foreign key. And then just join when needed.
How is it possible to implement it in a single table?
Well, the most elegant way would be indeed to create a satelite table for your stores and reference it to the store_transactions table, e.g:
CREATE TABLE stores
(
store_id varchar(100) NOT NULL PRIMARY KEY,
store_name varchar(100)
);
CREATE TABLE store_transactions
(
store_id varchar(100) NOT NULL REFERENCES stores(store_id),
store_transaction_id varchar(100),
transaction_name varchar(100),
transaction_date timestamp,
transaction_info varchar(200)
);
With this structure you will have many transactions to a single store.
There are other less appealing options, such as customizing a data type for stores and creating an array of it in the table store_transactions. But regarding the costly maintainability of such approach, I would definitely discourage it.

Creating a view between two tables in SQL

I'm having trouble creating a view between two tables, as I'm quite new to SQL. I need to create a view which will show which employees have carried out work as consultants within the past 14 days. The result of the view should also display this kind of layout:
14 day consultancy report
-----------------------------------------------
Employee Helvin Paul worked for 6 hours for factory ltd chargeable £351
The two tables I assume you will need to join together are the Employee table and also the Consultancy table. I will show both below as I have them in a text file from when I was creating these tables:
create table Funtom_employee
(
emp_ID Number(3) primary key,
Emp_firstname varchar2(50) not null,
Emp_surname varchar2(50),
Emp_department Number(2) constraint FK_funtom_dept references
funtom_department,
emp_street varchar2(50),
emp_town varchar2(50),
emp_district varchar2(50),
Emp_grade Number(3) default 4 constraint chk_emp_grd check (Emp_grade between 1 and 9),
Emp_site varchar2(30) default 'LONDON',
constraint FK_funtom_grade funtom_grade references funtom_department
);
create table Funtom_consultancy
(
consultancy_ID Number(3) primary key,
Consultancy_emp Number(3) constraint cns_emp references funtom_employee,
Consultancy_hours Number(4,2) constraint consultancy_check check (Consultancy_hours > 1),
Consultancy_client Number(3) references funtom_customer,
Consultancy_date DATE,
Consultancy_activity Number(3) references funtom_activity
);
Thanks to anyone that can help with this create view and for your time
A view can be created using the CREATE VIEW statement. An example based on your data is listed below.
CREATE VIEW consultancy_report as
select
Funtom_employee.Emp_firstname,
Funtom_consultancy.Consultancy_date,
from
Funtom_employee
join Funtom_consultancy
on Funtom_employee.emp_id = Funtom_consultancy.Consultancy_emp
You can add whatever other fields you need from either table in the select clause of the query. I've demonstrated one field from both tables.
If you want output explicitly as listed in your sample, you will need to concatenate several fields together as one string. Since this feels like a homework question, I will leave that as an exercise for you.

Beginner with triggers

Im a beginner in database and i got this difficult auction database project.
Im using SQL Server Management Studio also.
create table user(
name char(10) not null,
lastname char(10) not null
)
create table item(
buyer varchar(10) null,
seller varchar(10) not null,
startprice numeric(5) not null,
description char(22) not null,
start_date datetime not null,
end_date datetime not null,
seller char(10) not null,
item_nummer numeric(9) not null,
constraint fk_user foreign key (buyer) references user (name)
)
Basically what the rule im trying to make here is:
Column buyer has NULL unless the time (start_date and end_date) is over and startprice didnt go up or increased. Then column buyer will get the name from table user who bidded on the item.
The rule is a bid too difficult for me to make, i was thinking to make a trigger, but im not sure..
Your model is incorrect. First you need a table to store the bids. Then when the auction is over, you update the highest one as the winning bid. Proably the best way is to have a job that runs once a minute and finds the winners of any newly closed auctions.
A trigger will not work on the two tables you have because triggers only fire on insert/update or delete. It would not fire because the time is past. Further triggers are an advanced technique and a db beginner should avoid them as you can do horrendous damage with a badly written trigger.
You could have a trigger that works on insert to the bids table, that updates the bid to be the winner and takes that status away from the previous winner. Then you simply stop accepting new bids at the time the auction is over. Your application could show the bidder who is marked as the winner as the elader if the auction is till open and teh winner if it is closed.
There are some initial problems with your schema that need addressed before tackling your question. Here are changes I would make to significantly ease the implementation of the answer:
-- Added brackets around User b/c "user" is a reserved keyword
-- Added INT Identity PK to [User]
CREATE TABLE [user]
(
UserId INT NOT NULL
IDENTITY
PRIMARY KEY
, name CHAR(10) NOT NULL
, lastname CHAR(10) NOT NULL
)
/* changed item_nummer (I'm not sure what a nummer is...) to ItemId int not null identity primary key
Removed duplicate Seller columns and buyer column
Replaced buyer/seller columns with FK references to [User].UserId
Add currentBid to capture current bid
Added CurrentHighBidderId
Added WinningBidderId as computed column
*/
CREATE TABLE item
(
ItemId INT NOT NULL
IDENTITY
PRIMARY KEY
, SellerId INT NOT NULL
FOREIGN KEY REFERENCES [User] ( UserId )
, CurrentHighBidderId INT NULL
FOREIGN KEY REFERENCES [User] ( UserId )
, CurrentBid MONEY NOT NULL
, StartPrice NUMERIC(5) NOT NULL
, Description CHAR(22) NOT NULL
, StartDate DATETIME NOT NULL
, EndDate DATETIME NOT NULL
)
go
ALTER TABLE dbo.item ADD
WinningBidderId AS CASE WHEN EndDate < CURRENT_TIMESTAMP
AND currentBid > StartPrice THEN CurrentHighBidderId ELSE NULL END
GO
With the additional columns a computed column can return the correct information. If you must return the winner's name instead of id, then you could keep the schema above the same, add an additional column to store the user's name, populate it with a trigger and keep the computed column to conditionally show/not show the winner..