add a column in MySQL rank by deal by day - mysql

I am just learning MySQL. I need to find out rank of deals by day. Here I am adding the corresponding MYSQL query for my requirement that currently ranks all sales highest to lowest by day. Please help me to add a column that gives the rank to the deal highest to lowest and resetting the next day.
Here is my current working query,..
single day with title, price
SELECT
DATE(order_items.created_at) AS the_day,
order_items.deal_id,
SUM(order_items.item_total) AS daily_total,
SUM(order_items.qty) AS units_sold,
deals.price,
deals.title
FROM
order_items JOIN deals ON order_items.deal_id = deals.id
WHERE
order_items.created_at >= '2016-01-01 00:00:00' AND order_items.created_at < '2016-01-30 00:00:00'
AND
order_items.status=1
AND
order_items.paid=1
GROUP BY
order_items.deal_id
ORDER BY
the_day,
daily_total DESC;

The easiest way to do is that:
Use your existing SQL - I guess you need to update your SQL, make sure any non-aggregated columns in select should be in group by as well
Use PHP to loop (1-5), it works for multiple days
If you are happy to get top 5 for a single day, you can add limit 5 at end of your SQL
If you need top 5 results for each day in multiple days in one SQL, you need to update SQL to be more complicated. And here is a hint to use row id see example:
select increment counter in mysql
OK - Since you updated your question to return top 1 result per day, this is easier:
Step 1: get each day, each deal, report:
SELECT deal_id, date(created_at) ymd, sum(item_total) daily_total, sum(qty) units_sold
FROM order_items
WHERE substr(created_at,1,7) = '2016-01'
AND status = 1
AND paid = 1
GROUP BY 1,2
Step 2: Find the best deal of each day from step 1:
SELECT aa.ymd, max(aa.daily_total) max_total
FROM (
SELECT deal_id, date(created_at) ymd, sum(item_total) daily_total, sum(qty) units_sold
FROM order_items
WHERE substr(created_at,1,7) = '2016-01'
AND status = 1
AND paid = 1
GROUP BY 1,2
) as aa
GROUP BY 1;
Please note that max(item_total) not necessary same row as max(unit_sold), so you need to choose one, and cannot run togather
Step 3: Join step 2 with step 1 and deals to find out the rest of information:
SELECT aa.*, deals.price, deal.title
FROM (
SELECT aa.ymd, max(aa.daily_total) max_total
FROM (
SELECT deal_id, date(created_at) ymd, sum(item_total) daily_total, sum(qty) units_sold
FROM order_items
WHERE substr(created_at,1,7) = '2016-01'
AND status = 1
AND paid = 1
GROUP BY 1,2
) as aa
GROUP BY 1
) as bb
JOIN (
SELECT deal_id, date(created_at) ymd, sum(item_total) daily_total, sum(qty) units_sold
FROM order_items
WHERE substr(created_at,1,7) = '2016-01'
AND status = 1
AND paid = 1
GROUP BY 1,2
) as aa ON bb.ymd = aa.ymd and bb.max_total = aa.daily_total
JOIN deals ON aa.deal_id = deals.id
ORDER BY aa.ymd, aa.max_total

Related

Difficult order / group by / count

I've got 3 simple tables, but my query is difficult
Sellers table :
seller_id | name
1 john
2 paul
5 fred
6 robert
etc ...
Transactions table (only 3 values for the moment) :
trans_id | name
1 BUY
2 SELL
3 EXCHANGE
Operations table :
seller_id | trans_id | datetime
2 1 ....
2 2 ....
6 1 ....
2 3 ....
6 1 ....
This tables records all the sellers' transactions and their moment.
I would like to obtain, in the last day, or in a time interval
seller name, number of buy-transaction order by number of buy-transaction in the interval
seller name, number of buy-or-sell-transaction order by number buy-or-sell-transaction in the interval
I've tried many things, strange things taht mysql does'nt like, but I can't succeed ... thanks !
Here is a solution for your first query, ie "seller name, number of buy-transaction order by number of buy-transaction in the interval" :
SELECT
S.name,
COUNT(1) AS total
FROM operations O
JOIN sellers S on O.seller_id = S.seller_id
JOIN transactions T on O.trans_id = T.trans_id
WHERE O.datetime >= CURDATE() AND T.name = 'BUY'
GROUP BY S.name
ORDER BY total
Obviously, the second query is nearly the same, the where clause just changes a little, see the following :
SELECT
S.name,
COUNT(1) AS total
FROM operations O
JOIN sellers S on O.seller_id = S.seller_id
JOIN transactions T on O.trans_id = T.trans_id
WHERE O.datetime >= CURDATE()-1 AND T.name IN ('BUY','SELL')
GROUP BY S.name
ORDER BY total
To be honest you could even remove the join with transactions table and use O.trans_id in your where clause.
SEE DEMO HERE
Here solution for your first query
Select a.name, a.count from
(select seller.name name, Count(Transaction.Tran_id) count
from seller, Transaction, Operation
where seller.Seller_id = Operation.Seller_Id
and Transaction.Tran_id = Operation.Tran_id
and Transaction.Tran_id=1
and Operation.datetime between (datetime 1 & datetime2)
group by seller.name) a
order by a.count
Second solution is :-
Select a.name, a.count from
(select seller.name name, Count(Transaction.Tran_id) count
from seller, Transaction, Operation
where seller.Seller_id = Operation.Seller_Id
and Transaction.Tran_id = Operation.Tran_id
and Transaction.Tran_id in (1, 2)
and Operation.datetime between (datetime 1 & datetime2)
group by seller.name) a
order by a.count

Need help on MySQL query, i need to get the starting balance and the end balance by date group by stock_id

I need to get the starting balance from the earliest date and the ending balance from month end and group by stock_id.
My table:
id stock_id balance transact_at
1 1 100 2018-06-15
2 1 70 2018-06-16
3 1 30 2018-06-31
4 2 50 2018-06-01
5 2 10 2018-03-31
I want output:
stock_id start_balance ending_balance
1 100 30
2 50 10
Try this one. In this one two inner queries are fetching starting balance and closing balance by getting minimum and maximum transact_at corresponding to a stock_id and then the parent query is combing the two queries to get starting and closing balance in an single row. I have also shared fiddle link below to try.
select
tabledata1.stock_id,
startBalance,
closingBalance
from (
select
table1.stock_id,
balance as startBalance
from table1 join
(
select stock_id,
min(transact_at) as transact_at
from Table1 group by stock_id
) startTransaction
on Table1.stock_id = startTransaction.stock_id and
Table1.transact_at = startTransaction.transact_at
) tabledata1
join (
select
table1.stock_id,
balance as closingBalance
from table1 join
(
select stock_id,
max(transact_at) as transact_at
from Table1 group by stock_id
) endTransaction
on Table1.stock_id = endTransaction.stock_id
and Table1.transact_at = endTransaction.transact_at
) tabledata2
on tabledata1.stock_id = tabledata2.stock_id;
Demo
One approach in MySQL would be to aggregate by stock_id once and find the opening and closing dates. Then, self-join twice to pull in the actual balances which occurred on those opening and closing dates.
SELECT
t1.stock_id,
t2.balance AS start_balance,
t3.balance AS ending_balance
FROM
(
SELECT
stock_id,
MIN(transact_at) AS min_transact_at,
MAX(transact_at) AS max_transact_at
FROM my_table
GROUP BY stock_id
) t1
INNER JOIN my_table t2
ON t1.stock_id = t2.stock_id AND t2.transact_at = t1.min_transact_at
INNER JOIN my_table t3
ON t1.stock_id = t3.stock_id AND t3.transact_at = t1.max_transact_at;
Demo
Note: For posterity's sake, when MySQL 8+ becomes the norm, we could make use of things like ROW_NUMBER here, which might make it easier to get the result we want.
Try This One.
SELECT stock_id,MAX(balance) as start_balance, MIN(balance) as ending_balance FROM tbl_balance GROUP BY stock_id

How to stop this repetition and group by date

After multiple attempts I'm unable to get my required result from this query.
SELECT
cc.date as credi_date,
cd.date as debit_date,
cd.month AS month,
ROUND(IFNULL(cc.credit_amount,0),2) AS credit,
ROUND(IFNULL(cd.debit_amount,0),2) AS debit
FROM
(SELECT
DATE(cc.credit_date) as date,
MONTHNAME(cc.credit_date) as month,
IFNULL(SUM(cc.credit_amount),0) AS credit_amount
FROM
cust_credit cc
WHERE YEAR(cc.credit_date) = YEAR(NOW())
GROUP BY DATE(cc.credit_date)) cc
INNER JOIN
(SELECT
DATE(cd.debit_date) as date,
MONTHNAME(cd.debit_date) as month,
IFNULL(SUM(cd.debit_amount),0) AS debit_amount
FROM
cust_debit cd
WHERE YEAR(cd.debit_date) = YEAR(NOW())
GROUP BY DATE(cd.debit_date)) cd ON cc.month=cd.month
The problem is that this query repeats the rows multiple times. I don't know what thing cause this repetition and how can fix this. The image of result is given below.
My required result is
My credit table is give below
My debit table is give below
Yon should use a UNION in the subquery and then GROUP BY in the SELECT:
SELECT my_date,
my_month,
SUM(credit),
SUM(debit)
FROM (
SELECT cc.credit_date as my_date,
MONTHNAME(cc.credit_date) as my_month,
ROUND(SUM(IFNULL(cc.credit_amount,0)),2) AS credit,
0 AS debit
FROM cust_credit cc
WHERE YEAR(cc.credit_date) = YEAR(NOW())
GROUP BY cc.credit_date,
MONTHNAME(cc.credit_date)
UNION
SELECT
cd.debit_date ,
MONTHNAME(cd.debit_date) ,
0 ,
ROUND(SUM(IFNULL(cd.debit_amount,0)),2)
FROM cust_debit cd
WHERE YEAR(cd.debit_date) = YEAR(NOW())
GROUP BY cd.debit_date,
MONTHNAME(cd.debit_date)
) as TT
GROUP BY my_date,my_month
This is the Fiddle
Basically, your result is cross join between two query and that's the reason your are getting cross product i.e. total number of rows from credit x total number of rows from debit.
Because, month for all rows in debit and credit tables are same (i.e. January). But, you have unique date in both table
So, making below change should give you expected output.
ON cc.month=cd.month
to
ON cc.date = cd.date

Fetch only 2 results, one for each different value of a concrete field

In a MYSQL table with those 5 fields: id, user_id, date, type, uid where type can be 1 or 2, I'm looking for a single query where I can fetch 2 results, one for type=1 and another one for type=2 based on date field.
Right now i have the following query which only gives me the last uid without taking care of the type field.
SELECT t.uid
FROM table AS t
WHERE t.user_id = 666
ORDER BY t.date
DESC LIMIT 1
Does anyone know how should modify this query so i can get the last uid for type=1 and the last one for type=2 based on date field? I would like to keep a a single query
Union all is probably the simplest method:
(select t.*
from t
where t.user_id = 666 and t.type = 1
order by date desc
limit 1
) union all
(select t.*
from t
where t.user_id = 666 and t.type = 2
order by date desc
limit 1
)
Finally i updated the query following this "paradigm":
http://dev.mysql.com/doc/refman/5.7/en/example-maximum-column-group-row.html
http://jan.kneschke.de/projects/mysql/groupwise-max/
This is how the query ended up:
SELECT s1.type, s1.uid
FROM t AS s1
LEFT JOIN t AS s2 ON s1.type = s2.type AND s1.date < s2.date
WHERE s2.date IS NULL;
Here's a visual example: http://hastebin.com/ibinidasuw.vhdl
Credits are for snoyes from #sql on Freenode. :)

Select count of customers that purchased at least one from two specific categories in the same month

I'm trying to write a query to count the customers that purchased at least one from order_type=0 and one order_type=1 during the same month in 2014
I have two tables.
The order table that have:
order_id
customer_id
aquisition_date
orders_category table:
order_id
order_type (the type of the orders it may have 0, 1, 2, 3, 5, 8 ...etc )
I tried with this query but it didn't work, I know it's not complete and I missed the month condition!
Select count(user_id) From order
join orders_category
on order.order_id = orders_category.order_id
Where (order_type=0 or order_type=1)
and extract (year from order.aquisition_date)=2014
group by user_id
having count (case when type_id=0 then null else null end) > 0
and count (case when type_id=1 then null else null end) > 0;
I don't know how to find users with at least 1 order from order_type=0 & 1 order of order_type=1, in the same month.
You could use this query, based on what you already had. However, I suggest you change the name of the table order to orders as order is a reserved word:
select count(distinct user_id)
from (
select user_id, month(aquisition_date)
from orders
inner join order_category
on orders.order_id = order_category.order_id
where order_type in (0, 1)
and year(aquisition_date) = 2014
group by user_id, month(aquisition_date)
having count(distinct order_type) = 2
) as base
SQL fiddle
I selected the month also in the sub-select, as it will be interesting to look at the output of that query on its own during your analysis.