Order by conditioned to a field - mysql

I would like to change the order by clause in function of a field, but I don't know whether it's possible or not.
Here is an example:
**TABLE DISCOUNTS**
category offer
A 0
B 0
C 1
D 1
F 0
product_id category price
1 A 100
2 B 300
3 C 250
4 C 150
5 D 200
6 B 200
7 F 250
I'm willing to select all the products but already ordered, firstly if they are an offer or not (I want to show offers first), and after that I want to group them by category and sorted by price.
The problem is with the offers, here is not important to group by category because won't be too many offers and makes more sense to directly show them sorted by price.
So here is the ouput I'm getting:
product_id category price offer
4 C 150 1
3 C 250 1
5 D 200 1
1 A 100 0
6 B 200 0
7 F 250 0
2 B 300 0
While I would like to get a different order (sorting offers only by price):
product_id category price offer
4 C 150 1
5 D 200 1
3 C 250 1
1 A 100 0
6 B 200 0
2 B 300 0
7 F 250 0
The query I'm using is:
select * from Products p
left join Discounts d on p.category = d.category
order by offer desc, p.category, price
and here is the fiddle
What would be the best option here?
Thanks.

I think you just need to remove category from the order by:
select *
from Products p left join
Discounts d
on p.category = d.category
order by offer desc,
(case when offer = 0 then category end),
price ;

As I understand it you want offers ordered by price only and non offers order by category then price. In that case you can use an IF to conditionally order:
select * from Products p
left join Discounts d on p.category = d.category
order by offer desc,IF(offer,price,p.category), p.category, price

Related

MySQL sums from multiple tables

I have multiple tables and I need to aggregate the data from all of them, but it seems that I always get the wrong results for the sums. What am I doing wrong?
customers
ID Name
1 c1
2 c2
3 c3
budget
ID Cust_ID Value
1 1 100
2 1 300
3 2 600
4 3 450
forecast
ID Cust_ID Value
1 1 200
2 1 500
3 2 100
4 2 700
5 3 550
orders
ID Cust_ID Net_Sales
1 1 100
2 1 200
3 1 300
4 2 400
5 3 500
Here is the expected result:
ID Name sum(budget.Value) sum(forecast.Value) sum(orders.Net_Sales) count(orders.ID)
1 c1 400 700 600 3
2 c2 600 800 400 1
3 c3 450 550 500 1
And here's what I've tried so far:
SELECT customers.ID, customers.Name, sum(budget.Value), sum(forecast.Value), sum(orders.Net_Sales), count(orders.ID)
FROM customers
INNER JOIN budget ON budget.Cust_ID = customers.ID
INNER JOIN forecast ON forecast.Cust_ID = customers.ID
INNER JOIN orders ON orders.Cust_ID = customers.ID
GROUP BY customers.ID
ORDER BY customers.ID ASC
You are joining along multiple dimensions, which multiplies the results.
A simple solution is correlated subqueries:
SELECT c.ID, c.Name,
(SELECT SUM(b.Value)
FROM budget b
WHERE b.Cust_ID = c.ID
) as budget,
(SELECT SUM(f.Value)
FROM forecast f
WHERE f.Cust_ID = c.ID
) as forecast,
(SELECT SUM(o.Net_Sales)
FROM orders o
WHERE o.Cust_ID = c.ID
) as net_sales
FROM customers c
ORDER BY c.ID ASC;
With the right indexes in the second tables (budget(cust_id, value), and so on), this may actually be faster than a JOIN approach.

MySQL find MIN() from duplicate rows

I have 3 tables like below:
Product Table
PID CODE
1 a
2 b
Price Table
PrID PID(ID from Product) UMID(ID from UOM) Price
1 1 1 10
2 1 2 5
3 2 1 10
UOM Table
UMID UM_NAME UM_RATE
1 BOX 5
2 PC 10
I want to get product with price and that uom which has min UM_RATE. For example, product CODE a has two prices but the prices are different for different uom. What I want to achieve is,
PID CODE PrID Price UM_NAME UM_RATE
1 a 1 10 BOX 5
2 b 3 10 BOX 5
Because box has min UM_RATE. I have tried the following query,
SELECT product.*, price.*, uom.um_name, MIN(uom.um_rate)
FROM product
LEFT JOIN price ON price.pid = product.pid
LEFT JOIN uom ON price.umid = uom.umid
GROUP BY product.pid
This query gives me the following result,
PID CODE PrID Price UM_NAME UM_RATE
1 a 1 10 PC 5
2 b 3 10 BOX 5
which is wrong. because UM_RATE 5 is belong to UM_NAME box.
How can I get the expected result?
use join and corelated subquery
select * from (select distinct p.*,u.UMID as uid,
u.UM_NAME,u.UM_RATE,pr.code from
price p join uom u on p.UMID=u.UMID
join product pr on pr.PID=p.PID
) a
where a.UM_RATE =(select min(UM_RATE) from
(select p.*,u.UMID as uid,
u.UM_NAME,u.UM_RATE,pr.code from
price p join uom u on p.UMID=u.UMID
join product pr on pr.PID=p.PID) t where t.code=a.code
)
prid PID UMID price uid UM_NAME UM_RATE code
1 1 1 10 1 Box 5 a
3 2 1 10 1 Box 5 b

Get most sold products with a specified one

I have a table order_detail with this informations
id_order id_product
1 2
1 3
2 2
2 4
2 5
2 3
3 2
3 1
4 2
4 3
4 1
4 6
I would like to get most sold products(the first 5 elements) with the current product let's say product id 2
I tried this but it returns one wrong result
SELECT od2.product_id, count(od2.`product_id`) FROM `ps_order_detail` od1
LEFT JOIN ps_order_detail od2 ON od1.id_order = od2.id_order where
od2.product_id != od1.product_id AND od1.product_id=2
The result should be
product_id count(od2.`product_id`)
3 3
4 2
1 1
5 1
6 1
Your query is on the right track. Mostly, you are missing a group by:
select od.product_id, count(od2.id_order) as NumTimesWith2
from ps_order_detail od left join
ps_order_detail od2
on od.id_order = od2.id_order and
od2.product_id = 2
where od.product_id <> 2
group by od.product_id
order by count(od2.id_order) desc;
If you want only one such product, then add a limit 1 to the query.
Also, this assumes that products are not repeated inside orders. If they can be, you can quickly get a better count using count(distinct od.id_order)).

MySQL join next lower value from other table

I've the two tables orders
id article amount
1 1 1
2 2 50
and prices
id article min_amount price
1 1 1 42.99
2 2 1 5.06
3 2 5 4.55
4 2 10 4.3
5 2 25 4.05
6 2 100 2.66
The prices tables contains IDs of articles and a minimum amount you would have to buy to get a bulk discount (which would change the price for the order). I would like to join prices into orders, so that the result looks like:
id article amount price
1 1 1 42.99
2 2 50 4.05
The order id 2 is above the minimum (25) to get the article for 4.05€, but still below 100 at which you would get a bigger discount, so the query would to have pick the next-lower value.
I've tried this query so far
SELECT
orders.id AS id,
orders.article,
orders.amount,
prices.price,
(orders.amount - prices.min_amount) AS discount_diff
FROM orders
LEFT JOIN prices ON (prices.article = orders.article) AND (prices.min_amount <= orders.amount)
which gives this result
id article amount price discount_diff
1 1 1 42.99 0
2 2 50 5.06 49
2 2 50 4.55 45
2 2 50 4.3 40
2 2 50 4.05 25
You can find this example on "js"fiddle: http://sqlfiddle.com/#!9/1b2bf/8
The query you need is this:
SELECT orders.id AS id,
orders.article,
orders.amount,
prices.price
FROM orders
INNER JOIN prices ON ( prices.article = orders.article
and prices.min_amount <= orders.amount)
INNER JOIN ( SELECT orders.article,
orders.amount,
min(prices.price) minprince
FROM orders
INNER JOIN prices ON (prices.article = orders.article
AND prices.min_amount <= orders.amount)
GROUP BY orders.article,
orders.amount) b
ON ( prices.article = b.article
AND orders.amount = b.amount
AND prices.price = b.minprince)
See it here: http://sqlfiddle.com/#!9/1b2bf/27

SQL join and count do net get it together

I'am a beginner in SQL and have some trouble with joining and counting at the same time.
First let me explain my two tables.
I have the following:
Table: AnalysePageview
id title session more
-----------------------------------------------------
1 a 10 0
2 b 20 1
3 c 30 1
4 d 40 1
5 e 50 1
6 f 60 0
Table: AnalyseEvent
id name session more
-----------------------------------------------------
1 a 10 0
2 b 10 1
3 c 10 1
4 d 20 1
and I would like to join this two and add a line like this:
New Table:
id name session counts (out off AnalyseEvent)
-----------------------------------------------------
1 a 10 3
2 b 20 1
3 c 30 0
4 d 40 0
5 e 50 0
6 f 60 0
I just tried this:
SELECT *,
COUNT( AnalyseEvent.session ) AS totalViews
FROM AnalysePageview
LEFT JOIN AnalyseEvent ON AnalysePageview.session = AnalyseEvent.session
thanks for any help in advance. (my be with a small beginner explanation)
You need a group by:
SELECT apv.id, apv.name, apv.session, COUNT( ae.session ) AS totalViews
FROM AnalysePageview apv LEFT JOIN
AnalyseEvent ae
ON apv.session = ae.session
GROUP BY apv.id, apv.name, apv.session;
I also added table aliases to make the query easier to write and to read.
You need to use group by. Something like:
select apw.id, apw.title, apw.session, count(1)
from AnalysePageview apw
left join AnalyseEvent ae
on apw.session = ae.session
group by apw.id, apw.title, apw.session