Mysql sum column according to another column - mysql

This is my table data from my Mysql Table
t_Id t_Type t_Date t_acd_Id t_acc_Id t_Amount t_Desc t_u_Id c_Id
------ ------ ---------- -------- -------- -------- ------ ------ --------
1 0 2016-01-26 266 29 400.00 1 1
2 0 2016-01-27 266 29 160.00 1 1
3 1 2016-01-28 29 266 83.30 1 1
4 2 2016-01-27 29 272 400.00 1 1
5 0 2016-01-27 266 272 300.00 1 1
6 1 2016-01-28 272 22 20.00 1 1
I Want my result like
accout_Id rec_Amount pay_Amount
------ ---------- ----------
29 483.30 560.00
where rec_Amount is sum of t_acd_Id and pay_Amount is sum of t_acc_Id
How to get this result?
My current query
SELECT
(SELECT SUM(t_Amount) FROM tbl_transactions WHEREt_acd_Id= 29) AS rec_Amount,
(SELECT SUM(t_Amount) FROM tbl_transactions WHEREt_acc_Id= 29) AS pay_Amount
FROM tbl_transactions
which gives multiple rows

This query only serves the above requirement (for single account). If you want to get result for all the accounts then you need to group the records by account.
Try this(It's based on your requirement):
SELECT CASE
WHEN t_acc_id = 29 THEN t_acc_id
WHEN t_acd_id = 29 THEN t_acd_id
END account_id,
Sum(CASE
WHEN t_acd_id = 29 THEN t_amount
ELSE 0
END) rec_Amount,
Sum(CASE
WHEN t_acc_id = 29 THEN t_amount
ELSE 0
END) pay_Amount
FROM tbl_transactions
WHERE t_acc_id = 29
OR t_acd_id = 29

can you try with this query? as i have checked it manually.
SELECT t4.t_acd_Id as accout_Id ,sum(t4.t_Amount) as rec_Amount, (SELECT SUM(t_Amount) from table4 WHERE t_acc_Id =t4.t_acd_Id) as pay_Amount FROM `table4` as t4 WHERE t4.t_acd_Id IN (29,266) GROUP BY t4.t_acd_Id
Thanks

The following query takes into account the possibility that a given idea might appear only in t_acd_Id or t_acc_Id, but not both. In this case, we would like to do a full outer join, but MySQL does not directly support this. Instead, the first subquery in my answer obtains all unique ID values. This is then LEFT JOINed to two other subqueries for each of the totals you want.
SELECT t1.accout_Id, t2.rec_Amount, t3.pay_Amount
FROM
(
SELECT DISTINCT t_acd_Id AS accout_Id FROM tbl_transactions
UNION
SELECT DISTINCT t_acc_Id AS accout_Id FROM tbl_transactions
) t1
LEFT JOIN
(
SELECT t_acd_Id AS accout_Id, SUM(t_acd_Id) AS rec_Amount
FROM tbl_transactions
GROUP BY t_acd_Id
) t2
ON t1.accout_Id = t2.accout_Id
LEFT JOIN
(
SELECT t_acc_Id AS accout_Id, SUM(t_acc_Id) AS pay_Amount
FROM tbl_transactions
GROUP BY t_acc_Id
) t3
ON t1.accout_Id = t3.accout_Id
Click the link below for a running demo:
SQLFiddle

Related

Select difference based on record having minimum and maximum date in MySql

Below is my table let's call account
**ID accountID score tracking_date
1 1 3 2014-09-25 00:01:05
2 2 4 2014-09-26 01:05:18
3 1 6 2014-09-27 09:23:05
4 2 9 2014-09-28 20:01:05
5 1 1 2014-09-28 23:21:34
6 3 7 2014-09-21 00:01:00
7 2 1 2014-09-22 01:45:24
8 2 9 2014-09-27 14:01:43
9 3 1 2014-09-24 22:01:27
I want to select record with max date and also the difference of score with the records having tracking_date as minimum for that accountId. So I want output like below
ID accountID score_with_maxdate diff_score_with_mindate max_tracking_date
1 1 1 -2 2014-09-28 23:21:34
2 2 9 8 2014-09-28 20:01:05
3 3 1 -6 2014-09-24 22:01:27
Any help?
Here is one option. We can self-join a subquery which finds both the min and max tracking dates, for each account, twice to your original table. This will bring in all metadata for those max tracking date records, including the scores.
SELECT
t1.accountID,
t2.score AS score_with_maxdate,
t2.score - t3.score AS diff_score_with_mindate,
t1.max_tracking_date
FROM
(
SELECT
accountID,
MAX(tracking_date) AS max_tracking_date,
MIN(tracking_date) AS min_tracking_date
FROM yourTable
GROUP BY accountID
) t1
INNER JOIN yourTable t2
ON t1.accountId = t2.accountID AND t2.tracking_date = t1.max_tracking_date
INNER JOIN yourTable t3
ON t1.accountId = t3.accountID AND t3.tracking_date = t1.min_tracking_date
ORDER BY
t1.accountID;
Demo
This is a somewhat tricky question. I think conditional aggregation is a convenient way to solve the problem:
select min(t.id) as id, t.accountId,
max(case when t.tracking_date = t2.max_td then t.score end) as score_with_maxdate,
max(case when t.tracking_date = t2.max_td then t.score
when t.tracking_date = t2.min_td then - t.score
end) as diff_score_with_mindate,
max(t.tracking_date) as max_tracking_date
from t join
(select t2.accountId, min(t2.tracking_date) as min_td, max(t2.tracking_date) as max_td
from t t2
group by t2.accountId
) t2
on t.accountId = t2.accountId
group by t.accountId;
Another hackish way of getting same results by using aggregate and string fucntion
select t.accountID,
t.score_with_maxdate,
t.score_with_maxdate - t.score_with_mindate score_with_maxdate,
t.max_tracking_date
from(
select accountID,
substring_index(group_concat(score order by tracking_date desc),',', 1) + 0 score_with_maxdate,
substring_index(group_concat(score order by tracking_date asc),',', 1) + 0 score_with_mindate,
max(tracking_date) max_tracking_date
from demo
group by accountID
) t
Demo
But i would suggest you to go with other solutions mentioned by Tim & Gordon

get last completed (some condition) id while counting

I'm trying to get the last completed task id of the child table while counting all the child records and completed child records:
set #tmp := 0;
select
count(*) total,
count(if(completed=1, 1, null)) completed,
#tmp:=if(completed=1, task_id, #tmp) last_completed_task_id
from child_table where parent_id = 6
order by sequence
Here is some sample data:
id parent_id completed task_id sequence
526 6 1 1 1
1653 6 0 5 2
2749 6 0 20 3
3840 6 0 21 4
4913 6 1 22 5
5983 6 0 23 6
7063 6 0 25 7
7183 6 0 26 8
8241 6 1 27 9
9317 6 0 28 10
10380 6 0 29 11
So final result should be like that:
total: 11
completed: 3
last_completed_task_id: 27
I know how to get it with separate queries, but I wish to get it with one query if possible.
You could use a cros join between the count and the max task_id eg:
select
count(*) total,
count(if(completed=1, 1, null)) completed,
t.last_completed_task_id
from child_table
cross join (
select max(task_id) last_completed_task_id
from child_table
where parent_id = 6
and completed=1 ) t
where parent_id = 6
You can easily get the last completed id using conditional aggregation:
select count(*),
sum(is_completed = 1),
max(case when is_completed = 1 then id end) as last_completed_id
from child_table ct
where parent_id = 6;
If task_id is increasing -- as in your sample data -- you can just use task_id rather than id in the max().
Otherwise, just join the table back in:
select cnt, cnt_completed, ct2.task_id
from (select count(*) as cnt,
sum(is_completed = 1) as cnt_completed,
max(case when is_completed = 1 then id end) as last_completed_id
from child_table ct
where parent_id = 6
) x join
child_table ct2
on x.last_completed_id = ct2.id
You could try this :
select count(*) total,
count(if(completed=1, 1, null)) completed,
(select task_id from child_table where parent_id = 6 and completed = 1 order by sequence desc limit 1) as last_completed_task_id
from child_table
where parent_id = 6

Create Mysql view from two table not working

I have two table
ORDER
prod_id qty gst gst_rate
1 25 yes 18
1 25 no 0
2 10 yes 12
3 5 no 0
RETURN
prod_id add less gst_rate
1 5 0 0
1 10 0 18
3 0 2 0
About the table ORDER
Product 1 have order 25 with gst 18% and order 25 without gst. Product
2 have order 10 with gst 12%. Product 3 have order 5 without gst.
About the table Return
Product 1 without gst have extra qty 5. Product 1 with gst have extra
qty 10. Product 3 (no gst) have less qty 2. Product 2 have no extra or
less qty.
So I have to create a VIEW for each entry in ORDER table
Result should look like this
prod_id qty gst_rate add less
1 25 18 10 0
1 25 0 5 0
2 10 12 0 0
3 5 0 0 2
What I tried is:
SELECT ord.prod_id, ord.qty, ord.gst_rate, ret.add, ret.less FROM order ord LEFT JOIN (SELECT case when ord.gst='no' then (select sum(add) from return,order where order.prod_id=return.prod_id and return.gst_rate=0) else (select sum(add) from return,order where order.prod_id=return.prod_id and return.gst_rate!=0) end as add FROM return) as ret ON ret.prod_id=ord.prod_id
But it is not working..
you query could be refactored avoiding subquery ..
SELECT ord.prod_id, ord.qty, ord.gst_rate,
case when rd.gst='no' then t1.sum_add else t2.sum_add end as add
FROM order ord
LEFT JOIN (
select prod_id, sum(add) as sum_add
from return
INNER JOIN order ON order.prod_id=return.prod_id and return.gst_rate=0
GROUP BY prod_id
) t1 on t1.prod_id = ord.prod_id
LEFT JOIN (
select prod_id, sum(add) as sum_add
from return
INNER JOIN order ON order.prod_id=return.prod_id and return.gst_rate!=0
GROUP BY prod_id
) t2 on t2.prod_id = ord.prod_id
(the less was not in you code so i have omitted by select )

Conditional SQL Query on Multiple Rows

I am trying to find out which customers have defaulted on their loans. I would like to query the dataset to find the User_id of customers who have not paid in the last 60 days, but and not sure how to implement this in SQL.
User_id Due_Date Loan_Amount Paid_Amount
1 2012-04-04 16:14:12 500 40
1 2012-05-04 16:14:12 500 40
1 2012-06-04 16:14:12 500 0
1 2012-07-04 16:14:12 500 0
1 2012-08-04 16:14:12 500 0
2 2012-02-15 03:30:55 2030 100
2 2012-03-15 03:30:55 2030 100
2 2012-04-15 03:30:55 2030 100
3 2012-01-03 12:24:42 777 10
3 2012-02-03 12:24:42 777 0
3 2012-03-03 12:24:42 777 0
3 2012-04-03 12:24:42 777 0
In pseudocode (shown in bold) would look something like this, but I can't seem to implement it in MySQL:
SELECT User_id from TABLE_NAME WHERE Loan_Amount > 0 AND [the value Paid_Amount has been null for over 60 days]
Desired Output:
Users 1 and 3 in the above query would be returned because they have not paid for three consecutive periods.
NOTE: Due_Date is a time stamp
Any ideas would be very much appreciated!
Looks like you can use the DATEDIFF(date1, date1) function to obtain a list of delinquent borrowers.
SELECT DISTINCT
user_id
FROM table_name n
JOIN (SELECT user_id, max(due_date) maxDate FROM table_name GROUP BY user_id) t
ON n.user_id = t.user_id
AND n.due_date = t.maxDate
WHERE
loan_amount > 0
AND paid_amount IS NULL
AMD DATEDIFF(due_date, getdate()) > 60
My previous query was wrong, try this
select distinct t1.User_id
from TABLE_NAME t1
inner join (
select ts1.User_id, sum(ts1.Paid_Amount) as Paid_Amount_Total
from TABLE_NAME ts1
group by ts1.User_id
) t2
on t1.User_id=t2.User_id and t1.Loan_Amount>t2.Paid_Amount_Total
)
where
t1.Loan_Amount > 0
and t1.User_id not in (
select ts2.User_id
from TABLE_NAME ts2
where ts2.Due_Date>=DATE_SUB(NOW(), INTERVAL 60 DAY) and ts2.Paid_Amount>0
)
t1, ts1, ts2 - are aliases for TABLE_NAME

SQL query - how to construct multiple SUMs (based on different parameters) in one query

Please review my tables below... Is it possible to build a single query capable of
1) calculating the SUM of total_time for all vehicles that have class_id 1 (regardless of feature_id)(result would be 6:35)
2) calculating the SUM of total_time for all vehicles that have class_id 1 AND have feature_id 2(result would be 5:35 based on vehicle_id 22 and 24)
I'm able to get the results in two seperate queries, but I was hoping to retrieve them in one single query.... something like:
SELECT
SUM((CASE WHEN (VEHICLE_TABLE.class_id = 1) then LOG_TABLE.total_time else 0 end)) **AS TOTAL_ALL**,
...here goes statement for 2)... AS TOTAL_DIESEL...
FROM LOG_TABLE, VEHICLE_TABLE .....
WHERE VEHICLE_TABLE.vehicle_id = LOG_TABLE.vehicle_id ......
TABLE 1: LOG_TABLE (vehicle_id is NOT unique)
vehicle_id | total_time
--------------|--------------
22 2:00
22 0:30
23 1:00
24 2:20
24 0:45
TABLE 2: VEHICLE_TABLE (vehicle_id is unique)
vehicle_id | class_id
--------------|--------------
22 1
23 3
24 1
TABLE 3: VEHICLE_FEATURES_TABLE (vehicle_id is NOT unique but feature_id is unique per vehicle_id)
vehicle_id | feature_id
--------------|--------------
22 1
22 2
23 1
23 2
23 6
24 2
24 6
SELECT SUM(lt.total_time) AS TOTAL_ALL,
SUM(CASE WHEN (vft.feature_id IS NOT NULL) then LOG_TABLE.total_time else 0 end) AS FEATURE_TOTAL
FROM VEHICLE_TABLE vt
JOIN LOG_TABLE lt
ON vt.vehicle_id = lt.vehicle_id
LEFT JOIN VEHICLE_FEATURES_TABLE vft
ON vt.vehicle_id = vft.vehicle_id AND vft.feature_id = 2
WHERE vt.class_id = 1
It seems that there is not much point in putting both of them in one query unless you want the results together.
If so, just add a UNION between the 2 queries.
If you want to have both values in the same row try something like this:
SELECT (SELECT Sum(X)
FROM TBL
WHERE CLASS_ID = 1) AS CLS_id1,
(SELECT Sum(X)
FROM TBL
WHERE CLASS_ID = 1
AND FEATURE_ID = 2) AS CLS_id1_FTR_ID2