calculating accounts balance from debit and credit table - mysql

I have a accounts table like this
+-----------+--------------+
| fld_id| name |
+-----------+--------------+
| 1 | Bank1|
| 2 | Bank2|
| 4 | Bank3|
+-----------+--------------+
Revenue Income Table Like this
+-----------+--------------+---------------+-------------+
| fld_id | fld_type | fld_account id| fld_amount |
+-----------+--------------+---------------+-------------+
| 1 | Salry| 1 | 400 |
| 2 | Rent | 2 | 500 |
| 4 | Others | 1 | 1000 |
+-----------+--------------+---------------+-------------+
Payment Table Like This
+-----------+--------------+---------------+-------------+
| fld_id | fld_type | fld_account id| fld_amount |
+-----------+--------------+---------------+-------------+
| 1 | Food | 2 | 200 |
| 2 | Entertain | 2 | 300 |
| 4 | Transport | 1 | 400 |
+-----------+--------------+---------------+-------------+
I want a final balance table for accounts with sum of income, expence and balance like This Table --
+-----------+--------------+---------------+-------------+
| account | Income | Expence | Balance |
+-----------+--------------+---------------+-------------+
| Bank1 | 1400 | 400 | 1000 |
| Bank2 | 500 | 500 | 0 |
| Bank3 | 0 | 0 | 0 |
+-----------+--------------+---------------+-------------+
So far I write this query and getting income and expense but did't find any way to calculate balance, my query and result is --query
SELECT fld_account as account, Income, Expense
from tbl_accounts
LEFT JOIN (SELECT fld_account_id, SUM(fld_amount) as Income FROM tbl_revenue tr GROUP BY tr.fld_account_id) tc on fld_id=tc.fld_account_id
left JOIN (SELECT fld_account_id, SUM(fld_amount) as Expense FROM tbl_payment tp GROUP BY tp.fld_account_id) td on fld_id=td.fld_account_id
and the result is like below --
+-----------+--------------+---------------+
| account | Income | Expense |
+-----------+--------------+---------------+
| Bank1 | 1400 | 400 |
| Bank2 | 500 | 500 |
| Bank3 | Null | Null |
+-----------+--------------+---------------+
How can I calculate balance form payment and revenue table and join it with my account table? Any help is very appreciated.

Just use coalesce():
SELECT fld_account as account, COALESCE(Income, 0) as Income,
COALESCE(Expense, 0) as Expense,
( COALESCE(Income, 0) - COALESCE(Expense, 0) ) as balance
FROM tbl_accounts LEFT JOIN
(SELECT fld_account_id, SUM(fld_amount) as Income
FROM tbl_revenue tr
GROUP BY tr.fld_account_id
) tc
ON fld_id = tc.fld_account_id LEFT JOIN
(SELECT fld_account_id, SUM(fld_amount) as Expense
FROM tbl_payment tp
GROUP BY tp.fld_account_id
) td
ON fld_id = td.fld_account_id;
COALESCE() is the ANSI-standard function that returns the first non-NULL argument.

Related

MySQL Left Join with Specific Condition

I have following tables that manage revenue
revenue Table
+------------+--------+--------+
| revenue_id | amount | status |
+------------+--------+--------+
| 1 | 45000 | 1 |
| 2 | 25000 | 1 |
| 3 | 67000 | 1 |
| 4 | 22000 | 1 |
| 5 | 32000 | 0 |
+------------+--------+--------+
bank Table
+---------+--------+-------------+-------------+
| bank_id | ref_no | bank_amount | bank_status |
+---------+--------+-------------+-------------+
| 1 | 2 | 23000 | Pending |
| 2 | 3 | 67000 | Confirmed |
| 3 | 4 | 22000 | Confirmed |
+---------+--------+-------------+-------------+
02) If a revenue as mentioned in the revenue table has banked, it is recorded in the bank table. After that, the amounts in two tables are equal, the bank status may be into "Confirmed".
03) So, I need to get Confirmed records only as following by joining above two tables
Desired Output
+------------+--------+-------------+-------------+
| revenue_id | amount | bank_amount | bank_status |
+------------+--------+-------------+-------------+
| 3 | 67000 | 67000 | Confirmed |
| 4 | 22000 | 22000 | Confirmed |
+------------+--------+-------------+-------------+
Desired Output-02
+------------+--------+-------------+-------------+
| revenue_id | amount | bank_amount | bank_status |
+------------+--------+-------------+-------------+
| 1 | 45000 | | |
| 2 | 25000 | 23000 | Pending |
| 3 | 67000 | 67000 | Confirmed |
| 4 | 22000 | 22000 | Confirmed |
+------------+--------+-------------+-------------+
Desired Output-03
+------------+--------+-------------+-------------+
| revenue_id | amount | bank_amount | bank_status |
+------------+--------+-------------+-------------+
| 1 | 45000 | | |
| 2 | 25000 | 23000 | Pending |
+------------+--------+-------------+-------------+
04) To get the desired output I used the following query
select revenue.revenue_id, revenue.amount, bank.bank_amount, bank.bank_status
from revenue
left join bank on bank.ref_no = revenue.revenue_id
where revenue.status = 1 and bank.bank_status = "Confirmed"
05) But did't get the expected result. It generated only the empty result. I can not understand what I am going wrong. Can any one help me ?
You have to use Inner Join instead of Left JOIN for your expected output.
SELECT revenue.revenue_id,
revenue.amount,
bank.bank_amount,
bank.bank_status
FROM revenue
INNER JOIN bank ON bank.ref_no = revenue.revenue_id
WHERE revenue.status = 1
AND bank.bank_status = "Confirmed"
DEMO
select revenue.revenue_id, revenue.amount, bank.bank_amount, bank.bank_status
from revenue
Inner join (select *
From bank
Where bank_status = "Confirmed") bank
on bank.ref_no = revenue.revenue_id
You have to use the first bank table and then revenue table for left join .
Because in left join all rows will be returned even without matches.
So, use query like this.
select revenue.revenue_id, revenue.amount, bank.bank_amount, bank.bank_status
from bank
left join revenue on bank.ref_no = revenue.revenue_id
where revenue.status = 1 and bank.bank_status = "Confirmed"

Trouble in join and alias table

I'm trying to solve a question where each worker from a specific department sells a product and makes 1000 in profit. I want to find out the profit or loss of the company for each month. Assuming that the only profit comes from the sales and costs are the salaries off all workers.
Table dept_worker
+-----------+---------+------------+------------+
| worker_id | dept_n | from_date | to_date |
+-----------+---------+------------+------------+
| 10002 | 25 | 1996-08-03 | 9999-01-01 |
| 10016 | 25 | 1998-02-11 | 9999-01-01 |
| 10034 | 25 | 1995-04-12 | 1999-10-31 |
+-----------+---------+------------+------------+
Table salaries
+----------+--------+------------+------------+
| worker_id| salary | from_date | to_date |
+----------+--------+------------+------------+
| 10001 | 617 | 1986-04-26 | 1987-06-26 |
| 10002 | 600 | 1996-08-03 | 9999-01-01 |
| 10016 | 602 | 1998-02-11 | 9999-01-01 |
| 10034 | 674 | 1995-04-12 | 1999-10-31 |
| 10100 | 900 | 2000-07-25 | 2002-06-25 |
+----------+--------+------------+------------+
I tried two different approaches. I tried using WHERE dept_n = '25' but the result wasn't the expected because I was filtering everything.
SELECT MONTH(from_date) AS 'Months', COUNT(worker_id)*1000 AS 'Profit',
SUM (salary) AS 'Costs', (COUNT(worker_id)*1000-SUM(salary)) AS 'Diff'
FROM dept_worker JOIN salaries using(from_date,worker_id)
GROUP BY Month
ORDER BY Diff DESC;
The second one (this query doesn't give me any result):
SELECT MONTH(from_date) AS 'Months',
(SELECT COUNT(worker_id)*1000 FROM dept_worker WHERE dept_n = '25') AS 'Profits', SUM(salary)
FROM dept_worker JOIN salaries using(from_date)
GROUP BY Months;
Expected result:
+----------+--------+------------+-------------------+
| Months | Profits| Costs | Profits - Costs |
+----------+--------+------------+-------------------+
| 1 | 4456 |14478 |-10022 |
| 2 | 4105 |14824 |-10719 |
| 3 | 4379 |16130 |-11751 |
| 4 | 4329 |15562 |-11233 |
| (...) | (...) |(...) |(...) |
+----------+--------+------------+-------------------+
Try Starting with this:
SELECT MONTH(from_date) AS 'Months', COUNT(worker_id) over(partition by dept_n order by dept_n) * 1000 AS 'Profit',
SUM (salary) over(partition by dept_n order by dept_n) AS 'Costs'
FROM dept_worker JOIN salaries using(from_date,worker_id)
GROUP BY MONTH(from_date)

Converting currency in MySQL using a join

I have two tables:
A currency table (based on USD) which is updated constantly:
+----+----------+-----------+
| id | currency | value_usd |
+----+----------+-----------+
| 1 | USD | 1 |
| 2 | AUD | 1.077315 |
| 3 | GBP | 0.620868 |
| 4 | EUR | 0.775338 |
+----+----------+-----------+
And I have an order table where new orders are added:
+----+-------------+----------+
| id | sales_total | currency |
+----+-------------+----------+
| 1 | 100 | USD |
| 2 | 50 | GBP |
| 3 | 75 | EUR |
| 4 | 60 | GBP |
+----+-------------+----------+
I have an input of currency, which dictates the type of currency that I need to output the totals in, even though all orders are stored in various currencies.
For example, if $currency = 'EUR'; all totals must be in EUR when querying the order table based on the rates in the currency table. Like so:
+----+-------------+----------+-----------------+
| id | sales_total | currency | converted_total |
+----+-------------+----------+-----------------+
| 1 | 100 | USD | 77.53 |
| 2 | 50 | GBP | 62.44 |
| 3 | 75 | EUR | 75.00 |
| 4 | 60 | GBP | 74.92 |
+----+-------------+----------+-----------------+
How can I do this? I imagine that I'd need some sort of a CASE statement?
This oughta do it:
SELECT o.*, sales_total * (c2.value_usd / c1.value_usd) as converted_total,
c2.currency as converted_currency
FROM `order` o
JOIN `currency` c1 ON o.currency = c1.currency
JOIN `currency` c2 ON c2.currency = 'EUR'
Hard to test without a sample DB though - the calculation might be off but the principle is clear.
The factor for output currency you can get with a Sub-SELECT and the rest you do by joining the Tables on currency:
SELECT
t2.id AS id,
t2.sales_total AS sales_total,
t2.currency AS currency,
(t2.sales_total / value_usd * (SELECT value_usd FROM t1 WHERE currency = 'EUR')) AS converted_total
FROM t2 JOIN t1
ON t1.currency = t2.currency

Mysql, 3 tables 2 group by

I have 3 tables, student, family and fee. Some families have more than one kid. Fees are recorded in fee table. Families makes many payments through the year.
I want to group the number of kids by family and get the total amount paid by each family.
My Qyery:
SELECT student.Family_ID, family.Family_Name, count(*) as kids_numb, sum (Amount) as Paid_Amount
FROM student, family, fee
WHERE student.Family_ID = family.Family_ID
AND fee.Family_ID = family.Family_ID
AND student.Status ='1'
GROUP BY student.Family_ID;
I need to sort Something like:
Family Name | # of kids | Fees | Paid | Balance
----------------------------------------------------
Lebon | 1 | 425 | 200 | 225
Lavoix | 2 | 700 | 150 | 550
Napper | 1 | 425 | 0 | 425
Major | 3 | 900 | 300 | 600
UPDATED based on your comments.
Try it this way
SELECT m.family_id, m.family_name, s.kids_numb, COALESCE(f.paid_amount, 0) paid_amount
FROM family m LEFT JOIN
(
SELECT family_id, COUNT(*) kids_numb
FROM student
WHERE status = 1
GROUP BY family_id
) s
ON m.family_id = s.family_id LEFT JOIN
(
SELECT family_id, SUM(amount) paid_amount
FROM fee
GROUP BY family_id
) f
ON m.family_id = f.family_id
WHERE s.family_id IS NOT NULL
Sample output:
| FAMILY_ID | FAMILY_NAME | KIDS_NUMB | PAID_AMOUNT |
|-----------|-------------|-----------|-------------|
| 1 | Lebon | 1 | 200 |
| 2 | Lavoix | 2 | 150 |
| 3 | Napper | 1 | 0 |
| 4 | Major | 3 | 300 |
Here is SQLFiddle demo
UPDATE2: to add a grand total
SELECT family_id, family_name, SUM(kids_numb) kids_numb, SUM(paid_amount) paid_amount
FROM
(
SELECT m.family_id, m.family_name, s.kids_numb, COALESCE(f.paid_amount, 0) paid_amount
FROM family m LEFT JOIN
(
SELECT family_id, COUNT(*) kids_numb
FROM student
WHERE status = 1
GROUP BY family_id
) s
ON m.family_id = s.family_id LEFT JOIN
(
SELECT family_id, SUM(amount) paid_amount
FROM fee
GROUP BY family_id
) f
ON m.family_id = f.family_id
WHERE s.family_id IS NOT NULL
) q
GROUP BY family_id, family_name WITH ROLLUP
HAVING (family_id IS NOT NULL AND
family_name IS NOT NULL)
OR (family_id IS NULL AND
family_name IS NULL)
Sample output:
| FAMILY_ID | FAMILY_NAME | KIDS_NUMB | PAID_AMOUNT |
|-----------|-------------|-----------|-------------|
| 1 | Lebon | 1 | 200 |
| 2 | Lavoix | 2 | 150 |
| 3 | Napper | 1 | 0 |
| 4 | Major | 3 | 300 |
| (null) | (null) | 7 | 650 |
MySQL GROUP BY non-standard extension will allow you to change this whole part
GROUP BY family_id, family_name WITH ROLLUP
HAVING (family_id IS NOT NULL AND
family_name IS NOT NULL)
OR (family_id IS NULL AND
family_name IS NULL)
with just
GROUP BY family_id WITH ROLLUP
but then instead of NULL in family_name column for a total row you'll have a value of last family name.
Sample output:
| FAMILY_ID | FAMILY_NAME | KIDS_NUMB | PAID_AMOUNT |
|-----------|-------------|-----------|-------------|
| 1 | Lebon | 1 | 200 |
| 2 | Lavoix | 2 | 150 |
| 3 | Napper | 1 | 0 |
| 4 | Major | 3 | 300 |
| (null) | Major | 7 | 650 |
Here is SQLFiddle demo

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