I have two table amount_to_pay and paid_amount in amount_to_pay table data inserted as per center_id and university_id for which center for which university how much amount he has to pay and in paid_amount data inserted as which center for which university how much amount he paid, I want net amount pending from center for particular university as shown in third table below.
This is first table amount_to_pay
+---------+--------------+-------------+
|center_id|university_id |amount_topay |
+---------+--------------+-------------+
| 1 | 6 |29000 |
+---------+--------------+-------------+
| 1 | 7 |19700 |
+---------+--------------+-------------+
| 2 | 6 |9000 |
+---------+--------------+-------------+
This is my second table paid_amount
+---------+--------------+------------+
|center_id|university_id |amount_paid |
+---------+--------------+------------+
| 1 | 6 |9000 |
+---------+--------------+------------+
| 2 | 6 |5000 |
+---------+--------------+------------+
And want output as Below table
+---------+--------------+-------+
|center_id|university_id |amount |
+---------+--------------+-------+
| 1 | 6 |20000 |
+---------+--------------+-------+
| 1 | 7 |19700 |
+---------+--------------+-------+
| 2 | 6 |4000 |
+---------+--------------+-------+
Above amount_topay column is sum of amount_topay and group by center_id and university_id
In second table also amount_paid is sum of amount_paid column and group by center_id and university_id.
You could join the tables and subtract the amounts. Note that you should use a left join so you don't miss entries where no payments have been made yet:
SELECT a.center_id,
a.university_id,
a.amount_to_pay - COALESCE(p.amount_paid, 0) AS amount
FROM amount_to_pay a
LEFT JOIN paid_amount p ON a.center_id = p.center_id AND
a.university_id = p.university_id
You could use a join and agroup by
select
a.center_id
, a.university_id
, sum(a.amount_topay) - sum(ifnull(b.amount_paid,0) as amount
from amount_to_pay as a
left join paid_amount as b
on a.center_id = b.center_id
and a.university_id = b.university_id
group by a.center_id, a.university_id
try this
SELECT p1.center_id,p1.university_id,p1.amount_topay,p2.amount_paid,
CASE WHEN p1.center_id = p2.center_id AND p1.university_id = p2.university_id then amount_topay - amount_paid
WHEN p1.center_id <> p2.center_id and p1.university_id <> p2.university_id then amount_topay
END as total
FROM amount_to_pay p1
LEFT JOIN paid_amount p2
ON amount_topay > amount_paid
GROUP BY total HAVING total is not null
ORDER BY total desc;
see demo
Try this simple one & Make sure you have applied unique key for center_id and university_id combination
SELECT
a.center_id
, a.university_id
, SUM(a.amount_topay)- SUM(inull(b.amount_paid,0) AS amount
FROM amount_to_pay AS a
LEFT OUTER JOIN paid_amount AS b
ON(a.center_id = b.center_id
AND a.university_id = b.university_id)
GROUP BY a.center_id, a.university_id
Related
I am having below Tables
1. Material Unit:
id | material_unit
1 | Nos.
2 | lts
2. Material Table:
id | Material_name
1 | bricks
2 | Cement
3. Grn Table:
id | material_id | qty | unit
1 | 1 | 100 | 1
2 | 2 | 500 | 1
3 | 2 | 100 | 1
4 | 1 | 200 | 1
4. Consumption table:
id | material_id | qty | unit
1 | 1 | 50 | 1
2 | 1 | 50 | 1
3 | 2 | 100 | 1
4 | 2 | 200 | 1
Results expected is as below:
Material Name | Unit | Total Qty | Total Consumed Qty | Stock
Bricks | Nos. | 300 | 100 | 200
Cement | Nos. | 600 | 300 | 300
So on above results Total Qty is to be fetched from Grn Table and Total Consumed Qty from Consumption Table and Stock is difference of both and should be Group By Material_id.
Below query returns SUM of the values from GRN and Consumption table but it multiples the SUM with the No. of entries in the consumption table.
What mistake i am doing, can someone please help to figure out my mistake.
SELECT sm.material_name as 'Material Name', mu.material_unit as 'Material Unit', sum(g.qty) as 'GRN Qty', sum(c.qty) as 'Consumed Qty', SUM(g.qty) - SUM(c.qty) as 'Stock' from grn g
JOIN material_table sm ON g.material_id = sm.id
JOIN material_unit_table mu ON g.unit_id = mu.id
JOIN consumption c ON c.material_id = g.material_id
group by g.material_id
You consumption doubles the number of rows, so by summing the quantidy before joining corrects the numbers.
SELECT
MAX(sm.material_name) as 'Material Name'
, MAX(mu.material_unit) as 'Material Unit'
, sum(g.qty) as 'GRN Qty'
, sum(c.qty) as 'Consumed Qty'
, SUM(g.qty) - SUM(c.qty) as 'Stock'
from grn g
inner JOIN material_table sm ON g.material_id = sm.id
inner JOIN material_unit_table mu ON g.unit = mu.id
INNER JOIN (SELECT `material_id`, SUM(`qty`) qty, `unit` FROM consumption GROUP BY `material_id`,`unit`) c ON c.material_id = g.material_id
GROUP BY g.material_id
example https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=1a19b0f5a7ba08c5e9dbb0cbf85d2a27
I think your problem is due to grn table is your origin table, so the select gets a line for each row in the table. Make material_table your first table and join the rest of them to this, using its ID to make the join with the rest of tables.
Pls, try this version and let me know if it works properly (consider it may contain an error, i've written it into a notepad)
SELECT sm.material_name as 'Material Name', mu.material_unit as 'Material Unit', sum(g.qty) as 'GRN Qty', sum(c.qty) as 'Consumed Qty', SUM(g.qty) - SUM(c.qty) as 'Stock'
FROM material_table sm
JOIN grn g ON g.material_id = sm.id
JOIN material_unit_table mu ON g.unit_id = mu.id
JOIN consumption c ON c.material_id = sm.material_id
GROUP BY by sm.material_id
Hope it helps!
WITH Grn AS (
SELECT
material_id,
unit,
SUM(qty) AS 'Total Qty'
FROM grn
GROUP BY
material_id,
unit
),
Consumption AS (
SELECT
material_id,
SUM(qty) AS 'Consumed Qty'
FROM consumption
GROUP BY
material_id
)
SELECT
m.Material_name AS 'Material Name',
u.Material_unit AS Unit,
g.[Total Qty],
c.[Consumed Qty],
g.[Total Qty] - c.[Consumed Qty] AS Stock
FROM Grn g
INNER JOIN Consumption c ON g.material_id = c.material_id
INNER JOIN material_unit_table u ON g.unit_id = u.Id
INNER JOIN material_table m ON g.material_id = m.Id
This query will give desired result.
Bottom line is to remove material_id duplicates in grn and consumption tables. This way joining table consumption and grn by material_id won't give duplicates.
Note: In order for this to work, in grn table every material needs to have only one unit.
A more generic title for this post would be
MySql Sum different columns in same table based on value of another row, group by yet another row
I have a table of employee expenses:
id | employee_id | expense_cat_id | expense_amount |
1 | 11 | 1 | 100 |
2 | 11 | 1 | 200 |
3 | 12 | 1 | 120 |
4 | 12 | 1 | 140 |
5 | 11 | 2 | 5 |
6 | 12 | 2 | 8 |`
and I want to produce a report like this:
Employee Id | Expense Cat 1 Total Amount | Expense Cat 2 Total Amount
11 | 300 | 5
12 | 260 | 8
So initially I thought I could use 2 table aliases for the same table like this:
SELECT
employee_id,
sum(expense_cat_1.expense_amount) as expense_1_total,
sum(expense_cat_2.expense_amount) as expense_2_total
FROM
expenses as expense_cat_1 where expense_cat_1.expense_cat_id=1 ,
expenses as expense_cat_2 where expense_cat_2.expense_cat_id=2
group by employee_id
but this was not correct Sql Syntax, which makes sense to me.
So I thought I could do two joins on between employee table and the expenses table:
SELECT
employees.id as employee_id,
sum(expenses_cat_1.expense_amount) as expense_1_total,
sum(expenses_cat_2.expense_amount) as expense_2_total
FROM employees
join expenses as expenses_cat_1 on employees.id = expenses_cat_1.employee_id and expenses_cat_1.expense_cat_id=1
join expenses as expenses_cat_2 on employees.id = expenses_cat_2.employee_id and expenses_cat_2.expense_cat_id=2
group by employees.id
Which comes close, but is wrong:
employee_id | expense_1_total | expense_2_total
11 | 300 | 10
12 | 260 | 16
as the expense 2 total is doubled! I think this is because the join on shows up two rows for each of the two expenses with category 1, and sums them.
I also tried a sub-query approach:
SELECT (SELECT sum(expense_amount)
FROM expenses
WHERE expense_cat_id = 1) AS sum1 ,
(SELECT sum(expense_amount)
FROM expenses
WHERE expense_cat_id = 2) AS sum2,
employee_id
FROM expenses group by employee_id
but this has the same problem as the join approach - totals for cat 2 are doubled.
How do I make the second join only include the expense_2_total once ???
I have a personal dislike of sql case statements as they seem more of a procedural language construct (and sql is declarative), but am happy to consider their use in this case - but I put the challenge out there for sql experts to solve this elegantly.
You are looking for conditional aggregation:
SELECT employee_id,
sum(case when expense_cat_id = 1 then expense_amount else 0 end) as expense_1_total,
sum(case when expense_cat_id = 2 then expense_amount else 0 end) as expense_2_total
FROM expenses e
GROUP BY employee_id;
I have two tables.
Invoices
ID | Amount
-----------
1 | 123.54
2 | 553.46
3 | 431.34
4 | 321.31
5 | 983.12
Credit Memos
ID | invoice_ID | Amount
------------------------
1 | 3 | 25.50
2 | 95 | 65.69
3 | 51 | 42.50
I want to get a result set like this out of those two tables
ID | Amount | Cr_memo
---------------------
1 | 123.54 |
2 | 553.46 |
3 | 431.34 | 25.50
4 | 321.31 |
5 | 983.12 |
I've been messing with joins and whatnot all morning with no real luck.
Here is the last query I tried, which pulled everything from the Credit Memo table...
SELECT A.ID, A.Amount FROM Invoices AS A
LEFT JOIN Credit_Memos AS B ON A.ID = B.invoice_ID
Any help or pointers are appreciated.
Your query would work fine. Just add Credit_memo.Amount with an alias:
SELECT Inv.ID,Inv.Amount,IFNULL(C.Amount,'') AS Cr_memo
FROM Invoices Inv LEFT JOIN
Credit_Memos C ON Inv.ID=C.invoice_ID
Result:
ID AMOUNT CR_MEMO
1 124
2 553
3 431 25.50
4 321
5 983
See result in SQL FIDDLE.
You almost got the answer Left Outer Join is what you need but you missed to select Cr_memo from Credit_Memos table. Since you don't want to show Null values when there is no Invoices_ID in Credit Memos table use IFNULL to make NULL's as Empty string
SELECT A.ID, A.Amount, IFNULL(B.Cr_memo,'') AS Cr_memo
FROM Invoices AS A
LEFT JOIN Credit_Memos AS B
ON A.ID = B.invoice_ID
The LEFT JOIN keyword returns all rows from the left table (table1), with the matching rows in the right table (table2). The result is NULL in the right side when there is no match.
SELECT A.ID, A.Amount, IFNULL(B.amount,0) AS Cr_memo FROM Invoices AS A
LEFT JOIN Credit_Memos AS B ON A.ID = B.invoice_ID
here is some useful link about left join link and another
i have three tables
customer
id | name
1 | john
orders
id | customer_id | date
1 | 1 | 2013-01-01
2 | 1 | 2013-02-01
3 | 2 | 2013-03-01
order_details
id | order_id | qty | cost
1 | 1 | 2 | 10
2 | 1 | 5 | 10
3 | 2 | 2 | 10
4 | 2 | 2 | 15
5 | 3 | 3 | 15
6 | 3 | 3 | 15
i need to select data so i can get the output for each order_id the summary of the order
sample output. I will query the database with a specific customer id
output
date | amount | qty | order_id
2013-01-01 | 70 | 7 | 1
2013-02-01 | 50 | 4 | 2
this is what i tried
SELECT
orders.id, orders.date,
SUM(order_details.qty * order_details.cost) AS amount,
SUM(order_details.qty) AS qty
FROM orders
LEFT OUTER JOIN order_details ON order_details.order_id=orders.id AND orders.customer_id = 1
GROUP BY orders.date
but this returns the same rows for all customers, only that the qty and cost dont hav values
Maybe
SELECT
orders.id, orders.date,
SUM(order_details.qty * order_details.cost) AS amount,
SUM(order_details.qty) AS qty
FROM orders
LEFT JOIN order_details ON order_details.order_id=orders.id
AND orders.customer_id = 1
GROUP BY orders.date
HAVING amount is not null AND qty is not null
SQL Fiddle
NOTE: In the following query, it is assumed that the dates are stored in the database as a string in the format specified in the OP. If they are actually stored as some type of date with time then you'll want to modify this query such that the time is truncated from the date so the date represents the whole day. You can use the date or date_format functions. But then you'll need to make sure that you modify the query appropriately so the group by and select clauses still work. I added this modification as comments inside the query.
select
o.date -- or date(o.date) as date
, sum(odtc.total_cost) as amount
, sum(odtc.qty) as qty
, o.order_id
from
orders o
inner join (
select
od.id
, od.order_id
, od.qty
, od.qty * od.cost as total_cost
from
order_details od
inner join orders _o on _o.id = od.order_id
where
_o.customer_id = :customer_id
group by
od.id
, od.order_id
, od.qty
, od.cost
) odtc on odtc.order_id = o.id
where
o.customer_id = :customer_id
group by
o.date -- or date(o.date)
, o.order_id
;
I don't think you want an outer join just a simple inner join on all 3 tables:
FROM orders, order_details, customer
WHERE orders.customer_id=customer.id
AND order_details.order_id=orders.id
Given the following (simplified) tables:
People p
id name registered
-----------------------------------
1 Geoff 2011-03-29 12:09:08
2 Phil 2011-04-29 09:03:54
3 Tony 2011-05-29 21:22:23
4 Gary 2011-06-21 22:56:08
...
Items i
date p1id p2id
----------------------------------------
2011-06-29 20:09:44 1 2
2011-06-26 10:45:00 1 3
2011-06-23 12:22:43 2 3
2011-06-22 13:07:12 2 4
...
I'd like:
The earliest single i.date that each p.id appears in either column p1id or p2id; or p.registered if they feature in neither.
So far, I've tried:
CREATE TEMPORARY TABLE temp (id INT);
INSERT INTO temp (id)
SELECT DISTINCT u FROM (
SELECT p1id AS u FROM Items UNION ALL
SELECT p2id AS u FROM Items
)tt;
SELECT registered,id FROM People
WHERE id NOT IN (SELECT id FROM temp);
Which gets me as far as the second part, albeit in a fairly clumsy way; and I'm stuck on the first part beyond some sort of external, scripted iteration through all the values of p.id (ugh).
Can anyone help?
I'm on MySQL 5.1 and there's ~20k people and ~100k items.
One more solution:
SELECT id, name, IF(min_date1 IS NULL AND min_date2 IS NULL, registered, LEAST(COALESCE(min_date1, min_date2), COALESCE(min_date2, min_date1))) date FROM (
SELECT p.id, p.name, p.registered, MIN(i1.date) min_date1, MIN(i2.date) min_date2 FROM people p
LEFT JOIN items i1
ON p.id = i1.p1id
LEFT JOIN items i2
ON p.id = i2.p2id
GROUP BY id
) t;
OR this:
SELECT p.id, p.name, COALESCE(MIN(i.date), p.registered) FROM people p
LEFT JOIN (
SELECT p1id id, date FROM items
UNION ALL
SELECT p2id id, date FROM items
) i
ON p.id = i.id
GROUP BY id;
Result:
+------+-------+---------------------+
| id | name | date |
+------+-------+---------------------+
| 1 | Geoff | 2011-06-26 10:45:00 |
| 2 | Phil | 2011-06-22 13:07:12 |
| 3 | Tony | 2011-06-23 12:22:43 |
| 4 | Gary | 2011-06-22 13:07:12 |
+------+-------+---------------------+
This is tested in Postgres, but I think it ought to work in MySQL with few or no changes:
SELECT p.id,COALESCE(MIN(x.date),p.registered) AS date
FROM p
JOIN (
SELECT p.id,MIN(i.date) AS date
FROM p
JOIN i ON (p.id=i.p1id)
GROUP BY p.id
UNION
SELECT p.id,MIN(i.date) AS date
FROM p
JOIN i ON (p.id=i.p2id)
GROUP BY p.id
) AS x ON x.id = p.id
GROUP BY p.id,p.registered;
Output (given your sample data):
id | date
----+---------------------
3 | 2011-06-23 12:22:43
1 | 2011-06-26 10:45:00
2 | 2011-06-22 13:07:12
4 | 2011-06-22 13:07:12
(4 rows)