I need to calculate difference not sum, is there any way to do this. Here is desired example if sub aggreagate function exists.
SELECT p.*,SUB(p.orders) AS diff FROM products AS p GROUP BY p.id HAVING p.orders<0;
This is just example, not real table, just for example. The idea is to compare if first value is bigger than next values. Real example is if query returns two rows compare two values (orders count) of this tow rows in one query.
I would be grateful for any help.
What you want is only applicable when there are always 2 rows with the same p.id and different orders. If you have more than 2 rows which you would subtract from which?
So in the special case that you always have 2 rows per p.id then what you need is not a group function but join table products with itself like:
Select p1.id, (p1.orders - p2.orders) as diff
from products p1 inner join products p2 on p1.id = p2.id
where p1.orderid <> p2.orderid
This will only work if you always have 2 different orders per product.
Related
I'm trying to join 2 tables and count the number of entries for unique variables in one of the columns. In this case I'm trying to join 2 tables - patients and trials (patients has a FK to trials) and count the number of patients that show up in each trial. This is the code i have so far:
SELECT patients.trial_id, trials.title
FROM trials
JOIN(SELECT patients, COUNT(id) AS Num_Enrolled
FROM patients
GROUP BY trials) AS Trial_Name;
The Outcome I'm trying to acheive is:
Trial_Name Num_Patients
Bushtucker 5
Tribulations 7
I'm completely new to sql and have been struggling with the syntax compared to scripting languages.
It's not 100% clear from your question of the names of your columns however you are after a basic aggregation. Adjust the names of the columns if necessary:
select t.title Trial_Name, Count(*) Num_Patients
from Trials t
join Patients p on p.Trial_Id = t.Id
group by t.title;
Based on Stu-'s answer, I want to say that your column naming is wrong.But you can write query based on logic like this.
SELECT trial.title AS Trial_Name, COUNT(p.id) AS Num_Patients
FROM trial
INNER JOIN patients AS p
ON trial.patient_fk_id = p.id
GROUP BY trial.title,p.id;
Considering the following query:
SELECT COUNT(table1.someField), COUNT(table2.someField)
FROM table1
INNER JOIN table2 ON table2.id = table1.id
GROUP BY table1.id
I am trying to understand what the difference is (if any) between groupping by table1.id and groupping by table2.id. In short, when inner joining two tables on X=Y, what the difference is when groupping by X and when groupping by Y. That's it.
The real world example - pretty straightforward: a table transaction holds transactions information (paid amount, dates etc), and a table transaction_product holds information regarding which products were included in which transaction.
So for example, transaction number 1 could have included products number 1, 2 and 3, and so forth (so the table relation is obviously one-to-many).
The problem: I need to know for each transaction, how much was paid for how many products. This is the query, including both GROUP BY alternatives:
SELECT
`transaction`.id,
SUM(`transaction`.transaction_amount) AS total_amount,
COUNT(`transaction_product`.product_id) AS number_of_products
FROM `transaction`
INNER JOIN `transaction_product` ON `transaction_product`.transaction_id = `transaction`.id
GROUP BY [`transaction`.id [OR] `transaction_product`.transaction_id]
I need to know if there is a difference between the two GROUP BY alternatives. I couldn't find relevant information regarding the GROUP BY behavior in this case in the documentation, therefore any help on clarifying the matter would be much appreciated.
The result of the inner join will be a set of rows with matching transaction IDs, so the set of values that column can have will be the same on both transaction and transaction_product tables.
The group by will return a single row for each available value of the grouped column(s), and all the rows that share the same value will be aggregated with the aggregation function you use. The result
Result: there won't be any difference between the two options you have, because the same rows will be grouped with the exact same criteria, being the set of values the same on both sides.
TL/DR
There is no difference at all.
There is no difference whatsovever which id you choose to include in your GROUP BY clause. The total number of rows for each transaction id will be the number of products for that transaction. This query should get what you need:
SELECT
`transaction`.id,
SUM(`transaction`.transaction_amount) AS total_amount,
COUNT(1) AS number_of_products
FROM `transaction`
INNER JOIN `transaction_product` ON `transaction_product`.transaction_id =
`transaction`.id
GROUP BY `transaction`.id
let me sketch the situation a bit:
i have 2 tables: producten and reviews,
in producten i have multiple products stored, and in reviews i have stored all the reviews now while attemption to get the average of the ratings in the reviews table mysql only returns 1 row while i expect 2 rows back since i have 2 products.
the query im trying to use is:
SELECT p.*, CAST(AVG(r.rating) AS DECIMAL(2,1)) as waardering FROM `producten` as p INNER JOIN `reviews` as r ON p.id=r.product_id
i have also tried:
SELECT p.*, CAST(AVG(r.rating) AS DECIMAL(2,1)) as waardering FROM `producten` as p INNER JOIN `reviews` as r ON r.product_id=p.id
but this diddnt returned more then 1 row either.
could anyone please tell me why the query is only returning 1 row and not all the rows it finds inside the producten table?
also please feel free to tell me how i could increase this question if needed.
You want to GROUP BY p.id at the end of your query so that you get the average per product, instead of the values in the "first" product's field with the average for all products.
It's because you are using AVG. It is going to group all the rows together as one row. You probably want to group by avg rating instead.
So if I had a table with two columns.. product name / rating... I would do like so:
select productname, avg(rating) from ratings group by productname
Thank you for taking a look at my question! I've been trying to figure out a single query to do the following but have been unsuccessful. I would truly appreciate any help. Thank you in advance :-)
I am making an admin page for my e-commerce store that shows products that haven't sold in the last X days. There are three tables that need to be used...
Table: products
Column: product_id (int)
This table/column contains all the products in the store
Table: orders
Columns: order_id (int), date_ordered (datetime)
This table contains all the orders which are identified by order_id and the date for which they were ordered (date_ordered).
Table: order_products
Column: order_id (int), product_id (int)
This table contains a complete listing of all products ordered (product_id) and the corresponding order (order_id).
So, the query I'm trying to figure out would use use the order_id in tables orders and order_products to determine which products have sold in the last X days... Then return any products_id from the products table which have not sold in the last X days.
Any suggestions? Any help would be very appreciated! Thank you :-)
Okay so while I agree in part that you should do some poking around and learn more about left joins, there is also some trickiness to answering this question correctly that might be lost on a beginner. I'm gonna go ahead and help you answer it, but I would recommend learning more about joins.
My exact query would depend on the available indices, but it very likely resemble something like this:
SELECT a.*
FROM products AS a
LEFT JOIN (
SELECT product_id FROM order_products as b
INNER JOIN orders AS c
ON b.order_id = c.order_id
WHERE c.date_ordered >= date_sub(c.date_ordered, INTERVAL 7 day)
GROUP BY product_id
) AS d
ON a.product_id = d.product_id
WHERE d.product_id IS NULL
What I'm doing is I'm writing a subquery that joins orders and orders products together, where date_ordered falls within a certain date range (I would recommend learning about the date_sub function here: http://www.w3schools.com/sql/func_date_sub.asp and also do a few quick SELECT date_sub(date_ordered, INTERVAL X DAY) FROM orders queries to make sure you understand how this calculation works, in practice.
Now, I get my list of orders for the last X days (7 in the query above) and I join it with the orders product table to get the products that were ordered. Here, I want to dedup my products, basically. Product_id = 300 may have been ordered 70 times. Product_id = 200 may have been ordered 50 times. Whatever the case may be, I don't want to join 70 records and 50 records to my product table for product ids 300 and 200, so I dedup them. That last GROUP BY statement does that. It's functionally the same thing as writing DISTINCT (although there can be minor differences in how these are computed in certain circumstances, none of those circumstances seem to apply here... use DISTINCT if that's clearer for you)
Once I have my list of unique product ids that were ordered in the past X days, I join that with my product table. Here, I use a left join. Like the comments noted above, you'll want to look into the notion of joins pretty carefully. Do that, if you haven't already.
Last, I apply a WHERE filter that says "WHERE d.product_id IS NULL." What this is doing is saying, "okay, if product_id = Y was ordered in the past X days, then it will join to my products table successfully with a.product_id = d.product_id. If it wasn't ordered, then a.product_id will exist in my result set, but d.product_id won't. That is, d.product_id will be null."
That last twist may be the part that's not apparent / standing out.
Hope this helps.
I have three tables which we'll pretend are called products, coupons, and discounts. I have a query that attempts to pull a list of products, and runs a subquery to find ANY coupons which have a valid discount.
For example, this shows what I'm attempting:
SELECT products.id, products.name,
(
SELECT MAX(discounts.amount) FROM discounts
WHERE discounts.coupon_id = coupons.id
LIMIT 1
) as discount
FROM products
LEFT JOIN coupons ON products.id = coupons.product_id
GROUP BY products.id
My problem is that my GROUP BY is necessary for lots of other reasons. But if there are multiple coupons for each product, the "discount" gets combined in weird ways when the grouping occurs.
Let's say for a single product there are three coupons - two without any discount and one with a discount of 33%. When the group by occurs, I want to choose the highest value but by default, MySQL returns the value as 0.
Using MAX is the subquery obviously only returns the maximim value of discounts for each individual coupon. I just need to tell GROUP BY to use the max value.
I could easily use GROUP_CONCAT to return a string of all of them, but I also need to use that value in a calculation in some HAVING conditions.
Any suggestions?
I'm don't think you want or need the subquery. What does this return for you?
SELECT products.id, products.name, MAX(discounts.amount) AS discount
FROM products
LEFT JOIN coupons ON products.id = coupons.product_id
LEFT JOIN discounts ON coupons.id = discounts.coupon_id
GROUP BY products.id
You group by productid only, while the subselect actually return three values (one for each coupon of the product). I would actually expect this query to return an error. You should either move the discount one level up, or move the coupons to the subselect. An example of the first (subqueries are typically slower in MySQL):
select
p.productid,
max(d.discount) as discount
from
product p
left join coupon c on c.productid = p.productid
left join discount d on d.couponid = c.couponid
group by
p.productid