How do I structure a Database with a Sales Table MySql - mysql

I have a sales table that I want to record all the sales done by the employee.
The problem i'm having is that I can only store one ProductId that comes from a Products table. What is wrong is that a sale has multiples products and with my current structure I can only store one ProductId. I know my approach is wrong but I just don't know how to properly fix it. The question I have is how do I store multiples products in the Sales Table.
This is my Sales Table columns.
CREATE TABLE `Sales` (
`SaleId` int(11) unsigned NOT NULL AUTO_INCREMENT,
`EmployeeId` int(11) unsigned NOT NULL,
`ProductId` int(11) unsigned NOT NULL,
PRIMARY KEY (`SaleId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Your table and approach is ok.
You just have to insert one row in your sales table per product-id.
The unique key for the sales is the SaleId,
the foreign keys for Employee and Product are also there.
The only thing that's missing in your table is the sale quantity and amount.
It's the typical n:m-issue which is solved by the V-structure.

You need a second table, a Sales-Product table:
CREATE TABLE `SaleProduct` (
`SaleId` int(11) unsigned NOT NULL,
`ProductId` int(11) unsigned NOT NULL,
`Quantity` int(11) unsigned NOT NULL,
PRIMARY KEY (`SaleId`, `ProductId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
and change your Sales Table:
CREATE TABLE `Sales` (
`SaleId` int(11) unsigned NOT NULL AUTO_INCREMENT,
`EmployeeId` int(11) unsigned NOT NULL,
PRIMARY KEY (`SaleId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

The second way I suggest is more "standard" but since I have no idea how do you query the table and the size of it, the first method might(?) be useful
concatenate all prod_id into a single string, get them using regexp
example: prod_id = 13_07_255_23_11
SELECT * FROM Sales WHERE ProductId REGEXP '(^|)23(|$)';
split a single sale into multiple entries, have sales_id and product_id be your combined unique/primary key

Related

I'm trying to display total no. of orders by each vendor every year?

I'm trying to display total no. of orders by each vendor every year?
Table: Sales
Table: Products
Table: Vendors & Vendor_Info
select year(orderdate) as date_year,count(orderid) as count, OrderID
from products
NATURAL JOIN sales
NATURAL JOIN vendor_info
WHERE products.Vendor_Id=vendor_info.Vendor_Id
group by year(orderdate);
on doing this query i'm getting
query result
Where am i going wrong ? and what would the most efficient way to do this?
-- Table structure for table `products`
--
CREATE TABLE IF NOT EXISTS `products` (
`Product_id` varchar(255) NOT NULL,
`OrderId` int(11) NOT NULL,
`Manufacture_Date` date DEFAULT NULL,
`Raw_Material` varchar(255) DEFAULT NULL,
`Vendor_Id` int(11) DEFAULT NULL,
PRIMARY KEY (`Product_id`),
KEY `OrderId` (`OrderId`)
);
-- Table structure for table `sales`
--
CREATE TABLE IF NOT EXISTS `sales` (
`OrderID` int(11) NOT NULL AUTO_INCREMENT,
`OrderDate` date DEFAULT NULL,
`OrderPrice` int(11) DEFAULT NULL,
`OrderQuantity` int(11) DEFAULT NULL,
`CustomerName` varchar(255) DEFAULT NULL,
PRIMARY KEY (`OrderID`)
) AUTO_INCREMENT=10 ;
-- Table structure for table `Vendors`
--
CREATE TABLE IF NOT EXISTS `Vendors` (
`Raw_material` varchar(255) DEFAULT NULL,
`Vendors` varchar(255) DEFAULT NULL,
`Vendor_id` int(11) DEFAULT NULL,
KEY `Vendor_id` (`Vendor_id`)
)
-- Table structure for table `Vendor_info`
--
CREATE TABLE IF NOT EXISTS `Vendor_info` (
`Vendor_id` int(11) DEFAULT NULL,
`Vendor_name` varchar(255) DEFAULT NULL,
KEY `Vendor_id` (`Vendor_id`)
)
Some guesswork here, because you have not explained your requirement.
I guess you want to summarize numbers of orders by year. You can do that with a simpler query than your example, because all the data you need is in your sales table.
select year(orderdate) as date_year, count(orderid) as count
from sales
group by year(orderdate);
If this does not meet your need, please edit your question to give us more details.
If you want to get the number or orders by vendor and year yoy can use a query like this one:
select vendor_info.vendor_name,year(sales.orderdate),count(distinct products.orderId)
from vendor_info
join products on vendor_info.vendor_id=productos.vendor_id
join sales on products.orderid=sales.orderid
group by vendor_info.vendor_name,year(sales.orderdate)
Where you make a join from vendors to products and sales. Here you will get only the vendors who have sales.

Correct database's structure for table's relations (MySQL)

I have a table payouts with column reciever_id which by idea must links to primary keys of another Two tables: workers or doctors, which is determined by payouts.reciever_type.
As I understood this structure is a bit wrong.
Would be better to make payouts like this ?
....
`reciever_worker` INT(10) UNSIGNED DEFAULT NULL,
`reciever_doctor` INT(10) UNSIGNED DEFAULT NULL
....
Or merge tables workers and doctors to one table.
Table's structure:
TABLE `payouts`
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`date_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`reciever_type` VARCHAR(25) NOT NULL,
`reciever_id` INT(10) UNSIGNED NOT NULL,
`sum` DOUBLE NOT NULL,
`description` TEXT NOT NULL,
PRIMARY KEY (`id`)
TABLE `workers`
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(40) NOT NULL
PRIMARY KEY (`id`)
TABLE `doctors`
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(40) NOT NULL,
`doctor_fields_1` TEXT ...,
`doctor_fields_2` ...
PRIMARY KEY (`id`)
How to realize it correctly and standardly?
Note: this is valid only if 'receiver_id` is always either a doctor or a worker.
If you rename those doctor fields in the doctors table to something more generic, then it would make perfect sense to have just 1 table for both workers and doctors, with an additional type column that would flag them as one or another.
Then, from the payouts table you'd use a single column with a FK pointing to this one table with workers and doctors. Also, receiver_type would be redundant in payouts table.
Having two separate columns in payouts table would induce permanent checking if one is empty (NULL) or not, or check the type and use either one or another table, and so on. In short, it'd pretty much complicate your life without any benefit.

How do i store repetition of item in table?

I have three tables
user table
CREATE TABLE IF NOT EXISTS `user` (
`user_id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(25) NOT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8_unicode_ci;
item table
CREATE TABLE IF NOT EXISTS `item` (
`item_id` int(11) NOT NULL AUTO_INCREMENT,
`item` varchar(20) NOT NULL,
`price` int(3) DEFAULT NULL,
`likes` int(4) DEFAULT NULL,
PRIMARY KEY (`item_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8_unicode_ci;
order table
CREATE TABLE IF NOT EXISTS `order` (
`user_id` int(11) DEFAULT NULL,
`order_no` varchar(50) DEFAULT NULL,
`item1` varchar(5) DEFAULT NULL,
`item2` varchar(5) DEFAULT NULL,
`item3` varchar(5) DEFAULT NULL,
`item4` varchar(5) DEFAULT NULL,
`item5` varchar(5) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8_unicode_ci;
I store item_id in item1 or item2 so on column in order table. i give only 5 items can be select by user but they can increase quantity of any item like any user order two quantity of item1 how do i store this on database .
and any suggestion for improvement in tables .
The best way to allow an unlimited number of items per order is to use another table:
CREATE TABLE IF NOT EXISTS `orderitem` (
`order_no` varchar(50),
`itemid` INT,
`qty` INT NOT NULL DEFAULT 1,
`price` NUMERIC(9,2) NOT NULL,
PRIMARY KEY (order_no, itemid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8_unicode_ci;
Remove the five item columns from your order table.
As the user adds items, INSERT to the table above. You therefore have no limit to the number of items for each order.
This design is necessary whenever you have a many-to-many relationship. It's not a good idea to use five columns, that creates a limitation that is inconvenient (as you know).
If you want to allow the user to increase the quantity of a given line item, add a qty column to this table. When they choose to add more quantity of the same item they had chosen before, increase the qty.
You will also need a price column in this table. You need to record the price paid for the item during the current order, because the price could change tomorrow.
Re your comment:
INSERT INTO orderitem (order_no, itemid, qty, price)
VALUES (1234, 42, 3, 19.95)
ON DUPLICATE KEY UPDATE qty = qty + VALUES(qty), price = VALUES(price);
Read the documentation about http://dev.mysql.com/doc/refman/5.7/en/insert-on-duplicate.html to understand what this does.
One suggestion would be not to define your own id field, unless you have a very specific reason for it. Most databases can keep track of that for you. If you want to define your own you should probably add a unique constraint, and/or auto increment it.
I might not understand the question but it sounds like you want to be able to change the values in your items? I'm not quite sure what you're using but here's sql documentation

How to create one-to-zero-or-one relationship programmatically - MySQL?

I'm busy with a project and one of the stumbling blocks I've come across has been the following:
I have a bookings table, which may or may not result in an invoice being issued (because of some irrelevant stuff such as cancellations). How would I enforce a one (on the bookings side) to zero-or-one (on the invoice side) relationship? Here's what I have thus far:
CREATE TABLE IF NOT EXISTS `booking` (
`booking_id` int(11) NOT NULL AUTO_INCREMENT,
`voucher_id` int(11) NOT NULL,
`pickup_date_time` datetime NOT NULL, ...
PRIMARY KEY (`booking_id`,`voucher_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
And then, later on:
CREATE TABLE IF NOT EXISTS `invoice` (
`booking_id` int(11) NOT NULL,
`voucher_id` int(11) NOT NULL,
`invoice_number` int(11) NOT NULL,
`paid` tinyint(1) NOT NULL,
PRIMARY KEY (`booking_id`,`voucher_id`),
UNIQUE KEY `invoice_number` (`invoice_number`),
KEY `voucher_id` (`voucher_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
voucher_id is just something else I use in the system. The invoice_number is also generated in the PHP, so this is irrelevant.
Any help would be greatly appreciated!
This is more-less just a systematization of what #thaJeztah already suggested in his comments, but here you go anyway...
CREATE TABLE voucher (
voucher_id int(11) PRIMARY KEY
-- Etc...
);
CREATE TABLE booking (
booking_id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
voucher_id int(11) REFERENCES voucher (voucher_id),
pickup_date_time datetime NOT NULL
-- Etc...
);
CREATE TABLE invoice (
invoice_number int(11) NOT NULL PRIMARY KEY,
booking_id int(11) NOT NULL UNIQUE REFERENCES booking (booking_id),
paid tinyint(1) NOT NULL
-- Etc...
);
Minimal cardinality: There can be a booking without an invoice. There cannot, however, be an invoice without the booking (due to the FK on the non-NULL field invoice.booking_id).
Maximal cardinality: A booking cannot be connected to multiple invoices due to the UNIQUE constraint on invoice.booking_id. An invoice cannot be connected to multiple bookings, simply because one field (in one row) cannot contain multiple values.
So, the resulting relationship between booking and invoice is "one to zero or one".
Alternatively, put everything in just one table with NULL-able fields that get progressively filled as the booking advances.

SQL 'merging' columns from result sets into one result set

I've been pulling my hair about how to write a particular view within the constraints of MySQL.
The following tables and columns are of importance:
CREATE TABLE `invoices` (
`id` int(10) unsigned NOT NULL AUTO INCREMENT,
PRIMARY KEY (`id`)
)
-- Joins payments to invoices. The sum of all `invoice_currency_value`s is the balance paid towards an invoice.
CREATE TABLE `financial_transactions_invoices` (
`id` int(10) unsigned NOT NULL AUTO INCREMENT,
`invoice` int(10) unsigned NOT NULL,
`invoice_currency_value` decimal(8,2) unsigned NOT NULL,
PRIMARY KEY (`id`)
)
-- Lists items (services) available to purchase.
CREATE TABLE `items` (
`id` int(10) unsigned NOT NULL AUTO INCREMENT,
`value` decimal(8,2) unsigned NOT NULL
PRIMARY KEY (`id`)
)
-- Each instance represents that the `item` has been purchased.
CREATE TABLE `item_instances` (
`id` int(10) unsigned NOT NULL AUTO INCREMENT,
`invoice` int(10) unsigned NOT NULL,
`item` int(10) unsigned NOT NULL,
`invoice_currency_rate` decimal(11,5) unsigned NOT NULL,
PRIMARY KEY (`id`)
)
-- Any number of tax instances can exist for an item instance and indicate this tax has been applied to the associated item instance.
CREATE TABLE `tax_instances` (
`id` int(10) unsigned NOT NULL AUTO INCREMENT,
`item_instance` int(10) unsigned NOT NULL,
`value` decimal(8,2) unsigned NOT NULL,
PRIMARY KEY (`id`)
)
Now, I need a view that lists for each row,
the invoice number
the total value of the invoice
the total tax on the invoice
and the total value of payments made towards the invoice
However, I can't figure out how to get these three separate queries into the same result set of one row per invoice, e.g.
inv_no total_value total_tax payments
1 150 5 120
2 120 10 20
3 10 0 10
4 1000 150 1150
I have written the following query which produces the desired result, but due to the 'no subquery' rule in MySQL views, it is not acceptable.
SELECT `invoice_id`, SUM(`total_value`) AS `total_value`, SUM(`total_tax`) AS `total_tax`,
SUM(`paid_balance`) AS `paid_balance`
FROM
(SELECT `invoices`.`id` AS `invoice_id`, SUM(`items`.`value` * `item_instances`.`invoice_currency_rate`) AS `total_value`,
NULL AS `total_tax`, NULL AS `paid_balance`
FROM `items`
JOIN `item_instances` ON `items`.`id` = `item_instances`.`item`
JOIN `invoices` ON `item_instances`.`invoice` = `invoices`.`id`
GROUP BY `invoices`.`id`
UNION
SELECT `invoices`.`id`, NULL, SUM(`tax_instances`.`value`), NULL
FROM `tax_instances`
JOIN `item_instances` ON `tax_instances`.`item_instance` = `item_instances`.`id`
JOIN `invoices` ON `item_instances`.`invoice` = `invoices`.`id`
GROUP BY `invoices`.`id`
UNION
SELECT `invoices`.`id`, NULL, NULL, SUM(`financial_transactions_invoices`.`invoice_currency_value`)
FROM `financial_transactions_invoices`
JOIN `invoices` ON `financial_transactions_invoices`.`invoice` = `invoices`.`id`
GROUP BY `invoices`.`id`) AS `components`
GROUP by `invoice_id`;
Without tackling the problem in the way I have, I can't think of any other way I can do it within MySQL.
Any ideas? Appreciate any help.
You could create two views. One with the UNION Subquery, and one with the outer query.