MySQL question: The right way to calculate some data from different tables - php

We have a table A in which we store data about user investments; example columns user_id, project_id, amount.
We also have a table B in which we store data about projects and the total amount of investments; columns project_id and total_amount.
With PHP we can count the amount from A and write total_amount to B.
The question: Is it possible at the MYSQL level to automatically calculate data in order to avoid unnecessary operations in PHP?
If Yes, could you show me an example?

UPDATE tableB
LEFT JOIN (
SELECT project_id, SUM(amount) total_amount
FROM tableA
GROUP BY project_id
) amounts
ON amounts.project_id = tableB.project_id
SET tableB.code_counter=amounts.total_amount
This should work.

You can use following query to calculate total amount:
"SELECT SUM(amount) as total_amount from table_a group by project_id"

Related

How to show data from two table order by average of second table

I have two tables in MYSQL database with the following attributes.
services(id,name,details).
rating(id,sid,points).
In the rating table sid is foreign key of service table.
I want to show data in the following format
output(service id, name, details,average points) order by average points.
I have used the following query for this purpose
SELECT s.*, ROUND(COALESCE(AVG(r.points),0)) AS rating
FROM services s, rating r
WHERE s.id=r.sid
ORDER BY rating DESC
Above query shows the result only when record exists in the rating table. I want to show the both records who's record exists or not in the rating table. if there is no record in the rating table than its average will be counted as zero.
Please help me.
Change the implicit join to a left outer join (which will return null) and wrap the avg in an ifnull
SELECT s.*, ifnull(ROUND(COALESCE(AVG(r.points),0)),0) AS rating
FROM services s
left outer join rating r on s.id=r.sid
ORDER BY rating DESC

Mysql query with count on another table

I have two tables, one that has transaction information such as id, status, price and date. I have another table that stores the number of items in that order as individual rows. So, say transaction 2 has 10 items, there will be 10 rows in the second table of different items. What im trying to do is run a query that lists transactions and the number of items sold in that transaction. I imagine this would require a count on the second table, but im not entirely sure of how to do it. This is the basic layout of the database
transaction id, date, price, discount, status
items: id, transaction_id, item_name, email, date_ordered, hash
Thanks in advance for all the help.
Group by the columns in the transaction table you want to select. Then add a count of the items
select t.id, count(i.id) as item_count
from transaction t
left join items i on i.transaction_id = t.id
group by t.id
You can do a left join on both tables like below
select t.*, tab.total_order
from transaction t
left join
(
select transaction_id, count(*) as total_order
from items
group by transaction_id
) tab on t.id = tab.transaction_id

Using multiple inner joins

I have four tables:
users, orders, orders_product and products.
They are connected to each other by foreign key
user tables contains: id, name, email and username.
product table contains: id, product_name, product_description and product_price
orders table contains: id, u_id(foreign key).
orders_product table contains: id, product_id(foreign key), order_id(foreign key).
Now I was trying to fetch the name of a user with the total price of a particular order that he has placed.
The maximum I could went for was something like this:
SELECT prod.order_id,
SUM(product_price) AS Total
FROM products
INNER JOIN
(SELECT orders.id AS order_id,
orders_product.product_id
FROM orders
INNER JOIN orders_product ON orders.id = orders_product.order_id
WHERE order_id=1) AS prod ON products.id = prod.product_id;
It showed me total price of a particular order. Now I have two questions:
Is that query correct. It looks like a very long query. Can the same result be achieved with a smaller one?
How to fetch the name of a user with the total price of a particular order that he has placed.
Hi some addition to #Gordon Linoff
your query seems ok.
if you store your price data in order_products it will be good and some benefit, one of these benefit is aggregation will be simple. Second benefit if product price change it will not affect to order.
Your query is correct for one order, but it can be improved:
Don't use a subquery unless necessary. In MySQL this introduces additional overhead.
You are only looking at one order, which seems on the light site. You should remove the where clause.
You should be using a group by because you want aggregation.
You need to join in the user table to get the name.
I also added table aliases (abbreviations for table names). This makes the query a bit more readable:
SELECT u.name, SUM(p.product_price) as Total
FROM orders_product op INNER JOIN
orders o
ON o.id = op.order_id INNER JOIN
products p
ON p.id = op.product_id INNER JOIN
users u
on o.userid = u.id
WHERE op.order_id = 1
GROUP BY u.name;
Your SQL is wrong. Because You want to calculate specific to user. But your SQL is specific to Order. Your SQL will give result for One Order. Please make it User Specific by giving user name or what ever is unique.

Retrieve values from multiple tables relationed

So, I have a table named clients, another one known as orders and other two, orders_type_a and orders_type_b.
What I'm trying to do is create a query that returns the list of all clients, and for each client it must return the number of orders based on this client's id and the amount of money this customer already spent.
And... I have no idea how to do that. I know the logic behind this, but can't find out how to translate it into a MySQL query.
I have a basic-to-thinkimgoodbutimnot knowledge of MySQL, but to this situation I've got really confused.
Here is a image to illustrate better the process I'm trying to do:
Useful extra information:
Each orders row have only one type (which is A or B)
Each orders row can have multiple orders_type_X (where X is A or B)
orders relate with client through the column client_id
orders_type_X relate with orders through the column order_id
This process is being made today by doing a query to retrieve clients, and then from each entry returned the code do another query (with php) to retrieve the orders and yet another one to retrieve the values. So basically for each row returned from the first query there is two others inside it. Needless to say that this is a horrible approach, the performance sucks and I thats the reason why I want to change it.
UPDATE width tables columns:
clients:
id | name | phone
orders:
id | client_id | date
orders_type_a:
id | order_id | number_of_items | price_of_single_item
orders_type_b:
id | order_id | number_of_shoes_11 | number_of_shoes_12 | number_of_shoes_13 | price_of_single_shoe
For any extra info needed, just ask.
If I understand you correctly, you are looking for something like this?
select c.*, SUM(oa.value) + SUM(ob.value) as total
from clients c
inner join orders o on c.order_id = o.id
inner join orders_type_a oa on oa.id = o.order_type_id AND o.type = 'A'
inner join orders_type_b ob on ob.id = o.order_type_id AND o.type = 'B'
group by c.id
I do not know your actual field names, but this returns the information on each customer plus a single field 'total' that contains the sum of the values of all the orders of both type A and type B. You might have to tweak the various names to get it to work, but does this get you in the right direction?
Erik's answer is on the right track. However, since there could be multiple orders_type_a and orders_type_b records for each order, it is a little more complex:
SELECT c.id, c.name, c.phone, SUM(x.total) as total
FROM clients c
INNER JOIN orders o
ON o.client_id = c.id
INNER JOIN (
SELECT order_id, SUM(number_of_items * price_of_single_item) as total
FROM orders_type_a
UNION ALL
SELECT order_id, SUM((number_of_shoes_11 + number_of_shoes_12 + number_of_shoes_13) * price_of_single_shoe) as total
FROM orders_type_b
) x
ON x.order_id = o.id
GROUP BY c.id
;
I'm making a few assumptions about how to calculate the total based on the columns in the orders_type_x tables.

data show from 4 table mysql

How to show the common data from all table on base of vendorID where vendorID is unique key in my vendor table. and i use this as an foriegn key for all other(cost table, hour table,employee table, temporary table and ) table.
This is my Cost table struructre
This is my Hour table structure
This is my Temporarytable structure
This is my Employee table
This is my Final table vendor there are vendorID is unique Key
And i have use the following query but it is showing the different data.
SELECT * FROM cw_employee_csv as emp
inner join cw_cost_hour as cost on cost.vendorid=emp.vendorid
inner join cw_temp_employee as temp on cost.vendorid=temp.vendorid
inner join cw_hour_company as hour on temp.vendorid=hour.vendorid
inner join cw_vendor as vendor on temp.vendorid=vendor.vendorid
where vendor.companyid=1 ORDER BY hour.timeFrom ASC
If I understand, try this:
In your query in the field list explicit fields you want to show, for example:
SELECT
emp.assignmentid, cost.bill_type
FROM
cw_employee_csv AS emp
INNER JOIN
cw_cost_hour AS cost ON cost.vendorid = emp.vendorid
INNER JOIN
cw_temp_employee AS temp ON cost.vendorid = temp.vendorid
INNER JOIN
cw_hour_company AS hour ON temp.vendorid = hour.vendorid
INNER JOIN
cw_vendor AS vendor ON temp.vendorid = vendor.vendorid
WHERE
vendor.companyid = 1
ORDER BY
hour.timeFrom ASC
If the cardinality of tables is different and you want to show only one row per vendor, you must write a main query with cw_vendor and use some subquery to retrieve additional information by other table. Obviously, about parent table of your vendor table you can use INNER JOIN information without use subqueries.
EDIT AFTER COMMENT:
You start by this query (after chat discussion):
I extract an aggregate by company (I suppose to summarize your cost by vendor, if you want to apply another formula, it's the same algorithm)
select
sum(t.vendor_cost), t.companyid
from
(select
vendor.companyid as companyid, vendor.id as vendorid,
(select SUM(c.cost)
from cw_cost_hoyr c
where c.vendorid = vendor.id) as vendor_cost
from
cw_vendor vendor) as t
group by
t.companyid
Now we add other information but I must understand what do you want exactly with their relations

Categories