How to achieve following result with Group By in MySql? - mysql

Consider following table:
+------------+-----------+-------------+---------+------------+--------+-------------+
| client_id | TradeDate | servicetype | SEGMENT | OrdChannel | orders | OrderAmount |
+------------+-----------+-------------+---------+------------+--------+-------------+
| 1 | 20140611 | Type_1 | CASH | TT | 1 | 39275 |
| 2 | 20150119 | Type_1 | CASH | DNT | 2 | 11856.9 |
| 3 | 20150922 | Type_1 | FNO | OTHER | 1 | 854750 |
| 4 | 20151223 | Type_1 | CASH | TT | 5 | 71075 |
| 5 | 20140529 | Type_1 | Offline | FNO | 1 | 0 |
| 6 | 20160310 | Type_2 | CASH | WEB | 2 | 8009.6 |
| 7 | 20150318 | Type_1 | Offline | FNO | 2 | 432900 |
| 8 | 20150914 | Type_2 | CASH | WEB | 2 | 15612 |
| 9 | 20160317 | Type_2 | FNO | MINI | 1 | 9000 |
| 10 | 20140421 | Type_1 | CASH | TT | 8 | 17112.5 |
+------------+-----------+-------------+---------+------------+--------+-------------+
I am trying to group this data by client_id and TradeDate. Thus final dataset would contain each row for every <client-id, TradeDate> pair.
I want to compute following features from this data:
For each type of SEGMENT in every pair, I want to compute sum of orders and OrderAmount
Similarly, for each type of OrdChannel in every pair, I want to compute sum of orders and OrderAmount
Finally, a count of each servicetype i.e. Type_1 and Type_2.
Thus final dataset would contain columns similar to shown below:
+------------+-----------+-------------+---------+------------+--------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| client_id | TradeDate | SEGMENT_CASH_orders_sum | SEGMENT_CASH_OrderAmount_sum.... | OrdChannel_TT_orders_sum | OrdChannel_TT_OrderAmount_sum.... | servicetype_Type_1_count | servicetype_Type_2_count |
+------------+-----------+-------------+---------+------------+--------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
So far, I have tried:
select clientsrno, TradeDate, SEGMENT, COUNT(orders) from orders group by clientsrno, TradeDate, SEGMENT;
but it's not giving separate columns for SEGMENT_CASH-orders_sum, etc.
Instead the output I am getting is:
+------------+-----------+---------+---------------+
| clientsrno | TradeDate | SEGMENT | COUNT(orders) |
+------------+-----------+---------+---------------+
| 44 | 20141209 | CASH | 23 |
| 44 | 20141211 | FNO | 10 |
+------------+-----------+---------+---------------+

You can do with a lot of sum( CASE .... END)
this is a suggestionfor the firts column
select client_di, TradeDate
sum (case SEGMENT
when 'CASH' then orders ELSE 0 END) as SEGMENT_CASH_orders_sum,
sum (case SEGMENT
when 'CASH' then OrderAmount ELSE 0 END) as SEGMENT_CASH_ordersAmount_sum,
sum (case SEGMENT
when 'FNO' then orders ELSE 0 END) as SEGMENT_FNO_orders,
sum (case SEGMENT
when 'FNO' then OrderAmount ELSE 0 END) as SEGMENT_FNO_ordersAmount_sum
from my_table
group by client_id, TradeDate

You can do for example:
SELECT clientsrno, TradeDate, SEGMENT, COUNT(orders), sumOrders.total FROM tabletest
INNER JOIN (
SELECT tabletest.tradeDate, SUM(orders) as total FROM tabletest
GROUP BY clientsrno, TradeDate, SEGMENT
) sumOrders ON tableTest.tradeDate = sumOrders.tradeDate
GROUP BY clientsrno, TradeDate, SEGMENT
And repeat the process for every sum you need.

Related

Group data by foreign key and date with total by date

I need help to select daily payments made and group by the organization and date.
Group by date, then the total number of payments and the sum total amount of payments for each day
Tables are as follows,
organizations
-----------------------------
| id | name |
+-------------+-------------+
| 1 | org_1 |
+-------------+-------------+
| 2 | org_2 |
+-------------+-------------+
| 3 | org_2 |
-----------------------------
payments
------------------------------------------------------------
| id | org_id | amount | date_created |
+-----------+------------+-------------+-------------------+
| 1 | 2 | 20 | 2020-11-06 |
+-----------+------------+-------------+-------------------+
| 2 | 2 | 10 | 2020-11-06 |
+-----------+------------+-------------+-------------------+
| 3 | 1 | 50 | 2020-11-05 |
+-----------+------------+-------------+-------------------+
| 4 | 2 | 10 | 2020-11-05 |
------------------------------------------------------------
Expected Result
----------------------------------------------------------------------------------------------
| date_created | total_amount | num_payments | org_1 | org_2 | org_3 |
+----------------+----------------+-------------------+-----------+-------------+------------+
| 2020-11-06 | 30.00 | 2 | 0 | 2 | 0 |
+----------------+----------------+-------------------+-----------+-------------+------------+
| 2020-11-05 | 60.00 | 2 | 1 | 1 | 0 |
+----------------+----------------+-------------------+-----------+-------------+------------+
Use conditional aggregation:
select p.date_created,
sum(p.amount) as total_amount,
count(*) as num_payments,
sum(case when o.name = 'org_1' then p.amount else 0 end) as org_1,
sum(case when o.name = 'org_2' then p.amount else 0 end) as org_2,
sum(case when o.name = 'org_3' then p.amount else 0 end) as org_3
from payments p
inner join organizations o on o.id = p.org_id
group by p.date_created

How to select only first matching value from another table in MySQL?

Here is my database schema:
Payment table:
+------------+--------+--------+---------------------+
| payment_id | tab_id | amount | created |
+------------+--------+--------+---------------------+
| 1 | 1 | 5 | 2017-05-22 12:14:27 |
| 2 | 2 | 10 | 2017-05-22 12:15:21 |
| 3 | 2 | 1 | 2017-05-22 13:11:14 |
+------------+--------+--------+---------------------+
Tab table:
+------------+----------------+
| tab_id | service_charge |
+------------+----------------+
| 1 | 1 |
| 2 | 3 |
+------------+----------------+
I need to calculate total amounts (amount + service_charge) per payment, but service_charge should be included only in first payment matching tab_id.
My current query:
SELECT
payment.payment_id,
(payment.amount + tab.service_charge) as total_amount,
payment.created
FROM payment
INNER JOIN tab
ON payment.tab_id = tab.tab_id;
Actual result:
As you can see below service_charge from tab_id = 2 included twice (payment_id = 2 and payment_id = 3).
+------------+-----------------+---------------------+
| payment_id | total_amount | created |
+------------+-----------------+---------------------+
| 1 | 6 | 2017-05-22 12:14:27 |
| 2 | 13 | 2017-05-22 12:15:21 |
| 3 | 4 | 2017-05-22 13:11:14 |
+------------+-----------------+---------------------+
Expected result:
total_amount should not include service_charge in payment_id = 3 as shown below.
+------------+-----------------+---------------------+
| payment_id | total_amount | created |
+------------+-----------------+---------------------+
| 1 | 6 | 2017-05-22 12:14:27 |
| 2 | 13 | 2017-05-22 12:15:21 |
| 3 | 1 | 2017-05-22 13:11:14 |
+------------+-----------------+---------------------+
You should determine which is the first payment matching the tab_id and then based on that info, decide if you want to use the service_charge or not:
SELECT
payment.payment_id,
payment.amount + if (payment.created=m.mintime, tab.service_charge, 0) as total_amount,
payment.created
FROM payment
INNER JOIN tab
ON payment.tab_id = tab.tab_id
JOIN (
SELECT tab_id, min(created) as 'mintime'
FROM payment
GROUP BY tab_id
) AS m on m.tab_id = payment.tab_id;

Mysql query not giving the two rows with max numbers

I have query :-
select
CustomerName,
Scenario,
StepNo,
InTransit,
IsAlef,
RunNo,
count(1) as Total
from RequestInfo
group by CustomerName,
Scenario,StepNo,InTransit,
IsAlef,RunNo
order by Total DESC LIMIT 1;
which gives me output :-
+--------------+-------------+--------+-----------+--------+-------+-------+
| CustomerName | Scenario | StepNo | InTransit | IsAlef | RunNo | Total |
+--------------+-------------+--------+-----------+--------+-------+-------+
| MMT | HotelBrowse | 1 | No | No | 2 | 226 |
+--------------+-------------+--------+-----------+--------+-------+-------+
the actual table is :-
+--------------+-------------+--------+-----------+--------+-------+----------+
| CustomerName | Scenario | StepNo | InTransit | IsAlef | RunNo | count(1) |
+--------------+-------------+--------+-----------+--------+-------+----------+
| MMT | HotelBrowse | 1 | No | No | 1 | 206 |
| MMT | HotelBrowse | 1 | No | No | 2 | 226 |
| MMT | HotelBrowse | 1 | No | No | 3 | 206 |
| YATRA | HotelBrowse | 1 | No | No | 1 | 298 |
| YATRA | HotelBrowse | 1 | No | No | 2 | 206 |
| YATRA | HotelBrowse | 1 | No | No | 3 | 147 |
+--------------+-------------+--------+-----------+--------+-------+----------+
but i want output like below:-
+--------------+-------------+--------+-----------+--------+-------+----------+
| CustomerName | Scenario | StepNo | InTransit | IsAlef | RunNo | count(1) |
+--------------+-------------+--------+-----------+--------+-------+----------+
| MMT | HotelBrowse | 1 | No | No | 2 | 226 |
| YATRA | HotelBrowse | 1 | No | No | 1 | 298 |
+--------------+-------------+--------+-----------+--------+-------+----------+
The idea is to get the rows with max count numbers of the last column "Total".
Check This.
select R1.* from RequestInfo R1
inner join
(
select CustomerName,MAX( `count(1)`) `count(1)`
from RequestInfo
group by CustomerName
)R2 on R1.CustomerName=R2.CustomerName and R1.`count(1)`=R2.`count(1)`
Demo : sqlfiddle here
Please try below query
select a.* from RequestInfo a,
(select CustomerName,max(Total) as total from RequestInfo group by CustomerName ) b
where a.customername=b.customername
and a.total=b.total;
Just set your 'TOTAL DESC LIMIT' as '2'
SELECT CustomerName, Scenario,StepNo,InTransit,IsAlef,RunNo, count(1) AS
Total FROM RequestInfo GROUP BY
CustomerName, Scenario,StepNo,InTransit,IsAlef,RunNo ORDER BY Total DESC LIMIT 2;
error because count is reserved keyword in mysql so you can write between count(1) not only count without acute
your query like this
select CustomerName,Scenario,StepNo,InTransit,IsAlef,RunNo,`count(1)` as Total from customer group by CustomerName;
check here

Get available stocks to sell

What I have until now: http://sqlfiddle.com/#!2/bbfec/6
I want to get the quanity of shares for a given stock, that a given company has available to sell - grouped by price. For example, for company number 9 and stock number 1, I want the data like this:
| id | name | price | date | quantity | total |
------------------------------------------------------------------
| 3 | ALTR | 2.240 | 2015-05-12 04:29:29 | 50 | 112.00 |
| 7 | ALTR | 2.449 | 2014-06-10 18:21:02 | 50 | 122.45 |
Because company 9 bought 200 stocks on 2015-05-12 04:29:29, sold 100 on 2014-06-10 15:50:17, more 50 on 2014-06-10 17:06:18 and bought 50 on 2014-06-10 18:21:02.
I don't want the total of all shares, because they have different prices when a company acquires them. The price and the date are the purchasing price and date but the quantity is what is left from a certain purchasing.
Thanks in advance.
Strawberry, the desired result:
| id | price | date | quantity |
-----------------------------------------------
| 3 | 2.240 | 12-05-2015 | 50 |
| 7 | 2.449 | 10-06-2014 | 50 |
Start with:
select id_acao, id_empresa, ifnull(bought,0) - ifnull(sold,0) as stock
from
(
select id_acao, id_empresa,
(select sum(quantidade) from acao_trans where tipo='C' and id_acao=a.id_acao and id_empresa=a.id_empresa) as bought,
(select sum(quantidade) from acao_trans where tipo='V' and id_acao=a.id_acao and id_empresa=a.id_empresa) as sold
from acao_trans a group by id_acao,id_empresa
) x
;
+---------+------------+-------+
| id_acao | id_empresa | stock |
+---------+------------+-------+
| 1 | 4 | 1500 |
| 1 | 9 | 100 |
| 8 | 9 | 3500 |
| 13 | 9 | 5000 |
+---------+------------+-------+
And join this query to your base acao and empresa tables.
Remark: For statistics etc. it would be easier to use negative quantities for selling transactions instead of a transaction type 'C' and 'V'.
For ease of (my) comprehension, I translated and adjusted your stock table slightly...
SELECT a.stock_id
, a.company_id
, a.transaction_date
, a.price
, COALESCE(a.quantity - SUM(b.quantity),a.quantity) quantity
, COALESCE(a.quantity - SUM(b.quantity),a.quantity) * a.price subtotal
FROM stock_company a
LEFT
JOIN
( SELECT x.stock_id
, x.company_id
, MAX(x.transaction_date) min_transaction_date
, y.quantity
FROM stock_company x
JOIN stock_company y
ON y.stock_id = x.stock_id
AND y.company_id = x.company_id
AND y.transaction_date <= x.transaction_date
AND y.transaction_type <> x.transaction_type
WHERE y.transaction_type = 'SELL'
GROUP
BY x.stock_id
, x.company_id
, y.quantity
) b
ON b.stock_id = a.stock_id
AND b.company_id = a.company_id
AND b.min_transaction_date = a.transaction_date
WHERE a.stock_id = 1
AND a.company_id = 9
AND a.transaction_type = 'BUY'
GROUP
BY stock_id
, company_id
, transaction_date;
+----------+------------+---------------------+-------+----------+----------+
| stock_id | company_id | transaction_date | price | quantity | subtotal |
+----------+------------+---------------------+-------+----------+----------+
| 1 | 9 | 2014-06-10 18:21:02 | 2.449 | 50 | 122.450 |
| 1 | 9 | 2015-05-12 04:29:29 | 2.240 | 50 | 112.000 |
+----------+------------+---------------------+-------+----------+----------+
http://www.sqlfiddle.com/#!2/cfa4d/1
Note that this hasn't been tested extensively so there may be a flaw (or perhaps several flaws!) in my logic, but it seems to work well enough on the data set provided.
EDIT: I made a slight adjustment - still not sure if it's enough. Let me know.
Maybe now I've understood it. How about this:
select c.id,c.id_empresa,c.id_acao,c.data as c_data,c.quantidade as c_quantidade,v.preco,v.id as v_id,v.data as v_data,ifnull(v.quantidade,0) as v_quantidade, c.preco*v.quantidade as bought, v.preco*v.quantidade as sold
from acao_trans c
left join acao_trans v
on c.id=v.parent
order by id_empresa, id_acao,c_data,v_data
which results in
+----+------------+---------+---------------------+--------------+-------+------+---------------------+--------------+----------+----------+
| id | id_empresa | id_acao | c_data | c_quantidade | preco | v_id | v_data | v_quantidade | bought | sold |
+----+------------+---------+---------------------+--------------+-------+------+---------------------+--------------+----------+----------+
| 4 | 4 | 1 | 2014-06-10 08:59:09 | 2000 | 2.385 | 8 | 2014-06-11 10:39:48 | 500 | 1184.000 | 1192.500 |
| 8 | 4 | 1 | 2014-06-11 10:39:48 | 500 | NULL | NULL | NULL | 0 | NULL | NULL |
| 5 | 9 | 1 | 2014-06-10 15:50:17 | 100 | NULL | NULL | NULL | 0 | NULL | NULL |
| 6 | 9 | 1 | 2014-06-10 17:06:18 | 50 | NULL | NULL | NULL | 0 | NULL | NULL |
| 7 | 9 | 1 | 2014-06-10 18:21:02 | 50 | NULL | NULL | NULL | 0 | NULL | NULL |
| 3 | 9 | 1 | 2015-05-12 04:29:29 | 200 | 2.430 | 5 | 2014-06-10 15:50:17 | 100 | 224.000 | 243.000 |
| 3 | 9 | 1 | 2015-05-12 04:29:29 | 200 | 2.449 | 6 | 2014-06-10 17:06:18 | 50 | 112.000 | 122.450 |
| 2 | 9 | 8 | 2015-05-12 04:27:56 | 3500 | NULL | NULL | NULL | 0 | NULL | NULL |
| 1 | 9 | 13 | 2015-05-12 04:25:52 | 5000 | NULL | NULL | NULL | 0 | NULL | NULL |
+----+------------+---------+---------------------+--------------+-------+------+---------------------+--------------+----------+----------+
Can you go on from there?
Ok, now I think I got it.
Here's the query resulting what I wanted:
SELECT p.id
, a.nome
, p.preco
, date_format(p.`data`,'%m/%d/%Y') AS `data`
, COALESCE(p.quantidade-SUM(f.quantidade), p.quantidade) AS quantidade
, p.preco*COALESCE(p.quantidade-SUM(f.quantidade), p.quantidade) AS total
FROM acao_trans p
LEFT JOIN acao_trans f
ON p.id=f.parent
INNER JOIN acao a
ON p.id_acao=a.id
WHERE p.parent IS NULL
AND p.id_acao=1
AND p.id_empresa=9
GROUP BY p.id
Fiddle: http://sqlfiddle.com/#!2/bbfec/64.
What I did: I joined the table that matters (acao_trans "p") with itself ("f") and I used Sum function to aggregate all the quantities of second argument, giving me the total of all sold shares. If there are records on "f" I want to subtract that total of the quantity of purchasing shares ("p"). If there is not a correspondence it will show null fields and I show purchased quantity. After it's done it's kind of simple. Quantity was what really mattered here, with that I was able to reach other things easily.

Select total members and amount paid

I need help generating SQL for MySQL database.
I have three tables:
Organisations
Members
Payments
Organisations table:
+------------+---------+--------+
| id | name |website |
+------------+---------+--------+
| 1 | AAA | a.com |
|-------------------------------+
| 2 | BBB | b.com |
+------------+---------+--------+
Members table:
+------------+-------------------+--------+-----------------+-----------+
| id | organisation_id |name | Payment_confirm | join_date |
+------------+-------------------+--------+-----------------+-----------+
| 1 | 1 | james | 1 | 2013-8-02 |
|-----------------------------------------+-----------------+-----------+
| 2 | 1 | Jimmy | 0 | 2013-6-25 |
+------------+-------------------+--------+-----------------+-----------+
| 3 | 2 | Manny | 1 | 2013-07-02|
|-----------------------------------------+-----------------+-----------+
| 4 | 1 | Kim | 1 | 2013-09-02|
+------------+-------------------+--------+-----------------+-----------+
Payments table:
+------------+-------------------+--------+-----------------+----------------+
| id | member_id |amount | transaction_id | transferred_at |
+------------+-------------------+--------+-----------------+----------------+
| 1 | 1 | 100 | T1001 | 2013-8-03 |
|-----------------------------------------+-----------------+--------------- +
| 2 | 2 | 0 | null | Null |
+------------+-------------------+--------+-----------------+----------------+
| 3 | 3 | 200 | T1002 | Null |
|-----------------------------------------+-----------------+----------------+
| 4 | 4 | 50 | T1005 | 2013-09-05 |
+------------+-------------------+--------+-----------------+----------------+
How can I select the following?
Expecting the following output:
+------------+-------------------+--------+-----------------+---------------+--------------+
| Org name | Revenue |untransferred amount | Total members | last 30 days |
+------------+-------------------+--------------------------+---------------+--------------+
| AAA | 150 | 0 | 3 | 2 |
|-----------------------------------------------------------+---------------+--------------+
| BBB | 200 | 200 | 1 | 0 |
+------------+-------------------+--------------------------+---------------+--------------+
Org name = organisation name
Revenue = Total amount received
untransferred amount = transferred_at is null (payments table)
Total members = total members joined till today
last 30 days = total members joined last 30 days
You need to join your tables, group the results and select the desired logic:
SELECT org.name,
SUM(pmt.amount) AS revenue,
SUM(IF(pmt.transferred_at IS NULL, pmt.amount, 0)) AS untransferred
FROM Organisations org
JOIN Members mem ON mem.organisation_id = org.id
JOIN Payments pmt ON pmt.member_id = mem.id
GROUP BY org.id
See it on sqlfiddle.
select o.name,
sum(amount) as Revenue,
sum(if(transferred_at is null, amount, 0)) as untransfered_ammt,
sum(if(join_date>=curdate() - interval 30 day, 1, 0)) as last_30_d
from organisations o
inner join members m on o.id=m.organisation_id
inner join payments p on p.member_id=m.member_id
group by 1