Mysql query with count on another table - php

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

Related

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

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"

How to sum values across a set of categories, in SQL?

I want to get a list of category items and display the total amount linked to those categories. I have the "amount" field in the "transaction" table and I want to link it to category table.
This is how my tables are:
Category Master
Subcategory Master
Item Master
Transaction
So to get my "Amount" field to category, I would have to pass a certain common column between them. I have CategoryID in SubCategory master, subcatid in item master and similarly itemid in transaction.
Earlier when I grouped the amount using transaction date, the process went smoothly:
SELECT TransactionDate, SUM(Amount) FROM transaction GROUP BY MONTH(TransactionDate)
Now the problem I'm facing with grouping it using categoryname is that all of the amount seems to be =50 whereas it is still different in the database. I know that this is something really silly, but I am comparatively new to programming and not sure how to use logic appropriately.
SELECT categorymaster.CategoryName, transaction.Amount
FROM categorymaster
INNER JOIN subcategorymaster
INNER JOIN itemmaster
INNER JOIN transaction
GROUP BY categorymaster.CategoryName
This answer assumes your primary key in each table is named "ID". You didn't provide that info.
SELECT categorymaster.CategoryName, sum(transaction.Amount)
FROM categorymaster
INNER JOIN subcategorymaster
ON subcagetorymaster.CategoryId = categorymaster.ID
INNER JOIN itemmaster
ON itemmaster.SubCatId = subcategorymaster.ID
INNER JOIN transaction
ON transaction.ItemId = itemmaster.ID
GROUP BY categorymaster.CategoryName

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.

How to list two joined tables info by name (some with name, some possible empty)

I have two tables like these
Invoice (invoice_no, invoice_date, customer_id, ...),
Customers (customer_id, customer_name, ...)
Now what I want to do is list invoices ordered by customer name.
SELECT b.customer_name, a.*
FROM Invoice a, Customers b
WHERE a.customer_id=b.customer_id
ORDER BY b.customer_name
but problem with this sql is that if there are invoices without customer_id,
how can I list those invoices first and invoices with customer_id by customer_name asc.
use LEFT JOIN instead.
"kinda" weird. How come there are some invoices that without customer? To whom are you issuing it? Anyway, here's the query.
SELECT a.*, b.* // SELECT only the columns you want
FROM Invoice a
LEFT JOIN Customers b
ON a.customer_ID = b.customer_ID
To fully gain knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins
SELECT
a.*,
b.customer_name
FROM Invoice a
LEFT JOIN Customers b ON a.customer_ID = b.customerID
Use joins instead of FROM tablea, tableb.
Because this will fetch cartisian product from both tables unless you restrict them with WHERE
Use this
SELECT * FROM Invoice,customer where Invoice.customer_id=customer.customer_id ORDER BY IF(Invoice.customer_id is NULL , Invoice.customer_id, ~Invoice.customer_id) ASC

SQL Select multiple matching rows

I have a SQL database of products from different suppliers, so the same product could appear multiple times with different prices.
Is it possible to select all of the products that have more than 4 prices, so bascially all of the rows which have more than 4 rows with the same ID?
You could add COUNT(*) AS number_of_products to SELECT, GROUP BY product_id, then use HAVING number_of_products > 4.
Note that HAVING is applied on the results (it basically goes through all the results, one by one, and applies the conditions), so it will be slower than WHERE. If you have hundreds of thousands of rows and you need performance, consider pre-counting the products, storing the indexed count value somewhere, then using a simple WHERE instead.
Yes, GROUP on the identificator for your item, and specify the number of prices to count in a HAVING clause, something like this :
SELECT ItemID, COUNT(Price) FROM itemTBL GROUP BY ItemID HAVING COUNT(Price) >= 4
You can then use this to later filter and get more information:
SELECT Item.*, Category.Name, Filter.NumPrices from itemTBL AS Item
INNER JOIN categoryTBL as Category ON Item.CategoryID = Category.CategoryID
INNER JOIN (SELECT ItemID, COUNT(Price) AS NumPrices FROM itemTBL GROUP BY ItemID HAVING COUNT(Price) >= 4) AS Filter on Item.ItemID = Filter.ItemID
This is the perfect thing for a group by:
SELECT ProductID, COUNT(*) AS PriceCount
FROM Product GROUP BY
Product,Price HAVING COUNT(Product) > 4

Categories