how to connect two different table having similar foreign key? - mysql

I am creating an accounting module with laravel and mysql. For that, I've master table called 'bills' which has some columns regarding invoice informations and id as primary key. Now I've two different tables called 'payments' having bill_id as foreign key and 'debitnotes' also having bill_id as foreign key.
Now I want to show payment history of particular bill which is paid. In order to that, I've to retrieve information from both payments table and debitotes table based on bill id at once! Now, my question is: How can I achieve this without writing multiple queries?
bills table has columns:
id
bill_number
vendor_id
amount
amount_payable
date
payments table has columns:
id
bill_id
transaction_number
amount
date
vendor_id
debitnotes table has columns:
id
bill_id
debit_note_number
amount
vendor_id
date
I want to show both payments and debitnotes of particular bills in single page. How can i achieve this?

Use a union:
select
'bill' source,
id,
bill_number number,
vendor_id,
amount,
amount_payable,
date
from bills
union all
'payment',
id,
transaction_number,
vendor_id,
-amount amount, -- assuming payments cause the balance to lower
null,
date
from payments
union all
'debitnote',
id,
debit_note_number,
vendor_id,
amount,
null,
date
from debitnotes
You should delete the vendor_id column from payments and debitnotes because it is redundant (or denormalized); it can be found by joining to the bill table.

You should use join clause, and for payments and debitnotes, you can prepend the table name.
Here is an example from documentation:
$users = DB::table('users')
->join('contacts', 'users.id', '=', 'contacts.user_id')
->join('orders', 'users.id', '=', 'orders.user_id')
->select('users.*', 'contacts.phone', 'orders.price')
->get();

Related

Create views from tables with different number of columns mysql

I'm new to views in MySQL server.
I'm trying to create two VIEWS with "invoice_head" and "invoice_body", but in order to do that i need to get different keys from different tables (this tables have diferent number of columns).
This is the code that i'm trying to use:
CREATE VIEW invoice_head AS
SELECT
date_order AS 'DATE OF ISSUE'
FROM orders
UNION ALL
SELECT
customer_name AS 'Client Name',
customer_address AS 'Street adress',
customer_district AS 'District',
customer_country AS 'Portugal',
customer_zipcode AS 'ZIP Code'
FROM customer;
but this code is giving me the error: The used SELECT statements have different number of columns.
And the tables i'm using are something like this (for example)
Customer Table (8 columns)
customer_id
customer_name
customer_address
customer_district
(...)
1
maria xxx
street xxx
lisbon
(...)
Orders Table (9 columns)
order_id
customer_id
product_id
date_order
(...)
10
1
20
2020-12-15
(...)
The invoice_head is supposed to have information about the customer, the invoice_id, and the date of the order (invoice_date aka date_order).
Can someone tell me in what way is this possible to be made?
Is it impossible to do or I need to do something I'm not seeing?
Someone in the comments helped me. I just needed to use the "Join" instead of "Select":
DROP VIEW IF EXISTS `invoice_head`;
CREATE VIEW `invoice_head` AS
SELECT date_order as `Date of issue`,
customer_name AS `Client Name`,
customer_address AS `Street adress`,
customer_district AS `District`,
customer_country AS `Country`,
customer_zipcode AS `ZIP Code`
FROM orders
join customer
on orders.customer_id = customer.customer_id;

SQL - Select one record randomly per person

I currently have one table containing details of 100 people's first transactions with each product in the transaction as a separate record. Some people only bought 1 product in their first transaction while others may have bought up to 4 different products in their first transaction.
I'd like to create a table containing 1 distinct record per person where if they had purchased multiple different products in their first transaction, I'm randomly selecting one of those products. How would I go about doing this in mySQL?
Suppose your table is like this:
CREATE TABLE MyTable (
person_id INT,
product_id INT,
transaction_date DATE
);
It might have other columns too, but I'm not going to guess at them.
I would do this by "shuffling" the rows for each person. Sort the table by person first, then randomize the rows for the given person. You can do this by using ORDER BY person_id, RAND().
Then pick the first row for each person. This is a way to do this, using MySQL session variables to track the row number and start the row numbering from 1 with each distinct person_id:
SELECT person_id, product_id, transaction_date
FROM (
SELECT IF(#p=person_id, #r:=#r+1, 1) AS row_num
#p:=person_id AS person_id, product_id, transaction_date
FROM (SELECT #p:=0, #r:=0) AS _init
CROSS JOIN MyTable
ORDER BY person_id, RAND()
) AS T
WHERE row_num = 1;
When MySQL 8.0 comes out (probably in 2018), it should implement windowing functions, which will make this a little more standard:
SELECT person_id, product_id, transaction_date
FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY person_id ORDER BY RAND()) AS row_num,
person_id, product_id, transaction_date
FROM MyTable
) AS T
WHERE row_num = 1;
P.S.: By the way, when you ask questions about SQL, you should run SHOW CREATE TABLE MyTable and include the result in your question. It helps people not have to guess about your table, columns, indexes, data types, etc. They may be able to write an example that is closer to what you need.

How to select count of records from order and order line tables group by date?

My system has Order and OrderLine tables.
We can consider them as follows:
(Please don't consider the syntax part).
Order:
OrderId int(11) not null auto increment
customerId int(11)
orderdate datetime
...
OrderLine:
OrderId int(11)
productId int(11)
orderdate datetime
rate, total, ...
I need a hint / pointer to write a query in MySQL which can give me total number of orders and items (which are part of orderlines) grouped by orderdate. In other words, I need a query which can display information from two different tables (basically, some counts) which are not 1:1 (Eg: in this case, one order can consist of many items). What I need is only the count. The relationship between the tables is OrderId. But, that is not relevant to me as I need to look at OrderDate and group them in both the tables.
Eg:
Date Orders Items
2015-08-10 4747 58729
2015-08-11 4822 47593
2015-08-12 5219 52842
What I have done so far is something like this:
Select count(*) from order group by date(orderdate)
Select count(*) from orderline group by date(orderdate)
I also tried joining using LEFT join. But, I could not get the desired results.
Any help in combining the data (mainly count) of multiple tables in a single select will help me.
Let me know if you need more information.
You need to use subselect for counting orderline - something like this:
select date(orderdate),count(*),
(select count(*) from OrderLine
where date(OrderLine.orderdate)=date(Order.orderdate))
from Order
group by date(orderdate);

MYSQL reference to another table fields

I am trying to get for a specific period of time the quantity of products sold. For this example : the products table has a quantity field which increments whenever a certain product is sold. The orders table has a start date and end date. Is there a way i can hold a reference of the products table (like an object) in my orders table so i can see the quantity sold for each product every start - end date ? A quick example : I am having 2 products:
1 bike 25000 3 and 2 sportbike 30000 5 sold for my date. So an order would be something like : 1 05.07.2015 05.07.2015 and those products.
CREATE TABLE products (
product_no integer PRIMARY KEY,
name varchar(20),
price float,
quantity integer,
);
CREATE TABLE sells (
sell_id integer PRIMARY KEY,
start_date date,
end_date date
);
//New idea :
CREATE TABLE products (
product_no integer PRIMARY KEY,
name varchar(20),
price float
);
CREATE TABLE sells (
sell_id integer PRIMARY KEY,
date date,
quantity integer,
product_id integer FOREIGN KEY
);
Unless an order is always for a single product, I think you will need a third table. To me a minimal *) data model for this situation would look like this:
CREATE TABLE products (
product_no integer PRIMARY KEY,
name varchar(20) not null,
price float,
quantity_on_stock integer not null
);
CREATE TABLE orders (
order_id integer PRIMARY KEY,
order_date date not null
);
CREATE TABLE orderlines (
order_id integer not null REFERENCES orders.order_id,
product_no integer REFERENCES products.product_no,
price integer,
quantity integer not null,
PRIMARY KEY(order_id, product_no)
);
Then, a query to get sales in a certain period could look like this:
select
p.product_no,
p.name,
sum(ol.quantity)
from
products p
inner join orderlines ol on ol.product_no = p.product_no
inner join orderlines o on o.order_id = ol.order_id
where
ol.order_date between :start_date and :end_date
*) I say minimal, but it's actually less than minimal. You'd probably want to store invoices too, or at least some kind of indication that says whether an order is actually payed for and delivered, since sometimes orders are cancelled, or are just waiting open.
You definitely want a sales table showing what was sold and when, rather than a table showing the running inventory.
It is much easier in SQL to aggregate detail to create running totals than it is to reconstruct detail from running totals.
So, if you happen to have a sales table containing, among other things, columns for product_id, quantity, and ts (the timestamp of the sale), then you can get a summary of sales by product_id and sales date like this.
SELECT product_id,
DATE(ts) AS salesdate,
SUM(quantity) AS quantity
FROM sales
WHERE ts >= :start_date
AND ts < :end_date + INTERVAL 1 DAY
GROUP BY DATE(ts), product_id
One of the things that's cool about this is you can add a column for transaction_type to this table. If a customer returns a product you tag it return and use a negative quantity. If your shop receives a shipment of products you tag it restock and use a negative quantity. Then, if you want to show net sales -- sales less returned products -- it's a small change to the query.
SELECT product_id,
DATE(ts) AS salesdate,
SUM(quantity) AS quantity
FROM sales
WHERE ts >= :start_date
AND ts < :end_date + INTERVAL 1 DAY
AND transaction_type IN ('sale', 'return')
GROUP BY DATE(ts), product_id
If you want to know how much stock you had on on hand for each product for a particular end_date, you do this (starting from the beginning of time).
SELECT product_id,
SUM(quantity) AS quantity
FROM sales
GROUP BY product_id
In actual inventory / sale systems, it's common to take inventory once a year, close out the previous year's sales table, and start a new one with a starting value for each product. it's also common to organize sales by sales_order and sales_detail, so you can track the sale of multiple items in each transaction.

MYSQL search multiple records in the same table with the same first part of primary key

I have two tables:
SALE(SALE_CODE,SALE_DATE) and
SALE_ITEM(SALE_CODE,ITEM_CODE,QUANTITY,PRICE)
with SALE_CODE and SALE_CODE,ITEM_CODE as primary keys respectively.
I want to find out the sale with the biggest income.
I can only figure out how to do it if each sale contains only one item
SELECT SALE_CODE,PRICE*QUANTITY
FROM SALE_ITEM
WHERE PRICE*QUANTITY =(SELECT MAX(PRICE*QUANTITY)
FROM SALE_ITEM);
But if there are multiple records on the SALE_ITEM table with the same SALE_CODE but with different ITEM_CODE, I don't know what to do
select sale_code, sum(price * quantity)
from sale_item
group by sale_code
order by sum(price * quantity) desc
limit 1;
SQLFiddle example here.