Please help me to fix mysql query and get correct results...
Please see dataset for tables as following...
students
| id | name | batch | discount | open_bal | inactive |
+----+-------+-------+----------+----------+----------+
| 1 | Ash | 19 | 0 | -5000 | 0 |
+----+-------+-------+----------+----------+----------+
| 2 | Tuh | 15 | 0 | 0 | 0 |
+----+-------+-------+----------+----------+----------+
invoices
| id | invoice_num | student_id | reg_fee | tut_fee | other_fee | discount |
+------+-------------+------------+---------+---------+-----------+----------+
| 1 | 2011/1 | 1 | 5000 | 0 | 0 | 0 |
+------+-------------+------------+---------+---------+-----------+----------+
| 137 | 2011/137 | 1 | 15000 | 0 | 0 | 0 |
+------+-------------+------------+---------+---------+-----------+----------+
| 169 | 2011/169 | 2 | 15000 | 0 | 0 | 0 |
+------+-------------+------------+---------+---------+-----------+----------+
recipts
| id | recipt_num | student_id | reg_fee | tut_fee | other_fee | status |
+------+-------------+------------+---------+---------+-----------+------------+
| 264 | 2011/264 | 1 | 0 | 15000 | 0 | confirmed |
+------+-------------+------------+---------+---------+-----------+------------+
| 18 | 2011/18 | 2 | 0 | 5250 | 0 | confirmed |
+------+-------------+------------+---------+---------+-----------+------------+
| 251 | 2011/251 | 2 | 4650 | 0 | 0 | pending |
+------+-------------+------------+---------+---------+-----------+------------+
batches
| id | name |
+-----+----------+
| 19 | S.T-11 |
+-----+----------+
| 15 | Mc/11-13 |
+-----+----------+
I want to achieve report according to batches....
Batch id - batch id from batches table
Batch Name - batch name from batches table
Total Students - count(s.id) from students table group by batch
Opening Bal - sum(s.openbal) from students table
Gross Fee - sum(reg_fee+tut_fee+other_fee) from invoices table
Discount - sum(i.discount) from invoices table
Net Payable - (openbal + grossfee) - discount
Net Received - sum(reg_fee+tut_fee+other_fee) from recipts table where r.status = 'confirmed'
Due Balance - Net Payable - Net Received
expected report
| batch_id | batch_name | total_students | opening_bal | gross_fee | discount | net_payable | net_recieved | due_balance |
+----------+------------+----------------+-------------+-----------+----------+-------------+--------------+-------------+
| 15 | 2011/264 | 1 | 0 | 15000 | 0 | 15000 | 5250 | 9750 |
+----------+------------+----------------+-------------+-----------+----------+-------------+--------------+-------------+
| 19 | S.T-11 | 1 | -5000 | 20000 | 0 | 15000 | 15000 | 0 |
+----------+------------+----------------+-------------+-----------+----------+-------------+--------------+-------------+
I have tried using following query but its giving wrong results.
SELECT b.name AS batch_name,
b.id AS batch_id,
COUNT( s.id ) AS total_students,
COALESCE( s.open_bal, 0 ) AS open_balance,
COALESCE( sum( i.reg_fee + i.tut_fee + i.other_fee ) , 0 ) AS gross_fee,
COALESCE( s.discount, 0 ) ,
COALESCE( sum( i.reg_fee + i.tut_fee + i.other_fee ) , 0 ) -
COALESCE( s.discount, 0 ) AS net_payable,
COALESCE( sum( r.reg_fee + r.tut_fee + r.other_fee ) , 0 ) AS net_recieved,
COALESCE( s.discount, 0 ) ,
COALESCE( sum( i.reg_fee + i.tut_fee + i.other_fee ) , 0 ) -
COALESCE( s.discount, 0 ) -
COALESCE( sum( r.reg_fee + r.tut_fee + r.other_fee ) , 0 )
AS due_balance
FROM batches b
LEFT JOIN students s ON s.batch = b.id
LEFT JOIN invoices i ON i.student_id = s.id
LEFT JOIN recipts r ON r.student_id = s.id
WHERE s.inactive =0 and r.status = 'confirmed'
GROUP BY b.name;
please help me to rewrite this query...
Talking about SQL this line is quite certainly wrong:
GROUP BY b.name;
The GROUP BY should contain every element of the select which is not an aggregate expression.
Try the query using:
GROUP BY b.name,b.id,COALESCE(s.open_bal,0), COALESCE(s.discount,0);
When you do not make the right GROUP BY expression MySQL makes his own improved and simplified group by, which avoids a query rejection but produce higly unexpectable results, especially if your query is complex.
If you do not need a distinct result row for each s.open_bal and s.discount, then maybe you do not need theses (duplicates) data in the select.
Then I did not took the time to analyze the complete query. But your needs seems quite complex. I would say Divide and conquer, KISS (Keep It Stupid Simple), make several queries you fully understand instead of one huge query. Especially if requirements from some of the results differs (some working on details, some working on aggregates, and some working on different aggregates, etc), as you would maybe need some window functions ("partition by" keyword) that you do not have on MySQL.
maybe you should try to fix your sum like this example:
COALESCE( sum( i.reg_fee + i.tut_fee + i.other_fee ) , 0 ) //bad
sum( COALESCE(i.reg_fee,0) + COALESCE(i.tut_fee,0) + COALESCE(i.other_fee,0) ) //good
Related
I'm trying to count all the rows which has a status of checked out,
but I can only do is to populate it by rows then count it dynamically.
How can I make my rows as header then count the status after?
I need to make the dorm name rows as column header
then checked out as rows.
Query :
SELECT Room_Number as 'Room Number',Dorm_Name as 'Dorm Name',
COUNT(IF(action = 'Checked Out' , 1, NULL)) 'Checked Out' FROM billeting_history group by dorm_name;
+-----------+-------------+-------------+
| Dorm Name | Room_number | Checked Out |
+-----------+-------------+-------------+
| Arquitola | 205 | 1 |
| Hangar | 201 | 0 |
| Noble | 200 | 0 |
+-----------+-------------+-------------+
Desired output :
+-------------+-----------+--------+-------+
| Room Number | Arquitola | Hangar | Noble |
+-------------+-----------+--------+-------+
| 205 | 1 | 0 | 0 |
| 201 | 0 | 0 | 0 |
| 200 | 0 | 0 | 0 |
+-------------+-----------+--------+-------+
If you know the specific columns you want, you can use conditional aggregation:
SELECT Room_Number,
SUM( CASE WHEN Dorm_Name = 'Arquitola' THEN checked_out ELSE 0 END ) as Arquitola,
SUM( CASE WHEN Dorm_Name = 'Hangar' THEN checked_out ELSE 0 END ) as Hangar,
SUM( CASE WHEN Dorm_Name = 'Noble' THEN checked_out ELSE 0 END ) as Noble
FROM billeting_history
GROUP BY Room_Number;
If you don't know the full list of names, then you need to use dynamic SQL.
I need to show the data from DB into a table of report file.
my_table looks like:
+----+-------+------+------+-------------------+-----------+-------+----+-------------------+
| id |entryID|userID|active| dateCreated |affiliateId|premium|free| endDate |
| 1 | 69856 | 1 | N |2014-03-22 13:54:49| 1 | N | N |2014-03-22 13:54:49|
| 2 | 63254 | 2 | Y |2014-03-21 13:35:15| 2 | Y | N | |
| 3 | 56324 | 3 | N |2014-03-21 11:11:22| 2 | Y | N |2014-02-22 16:44:46|
| 4 | 41256 | 4 | Y |2014-03-21 08:10:46| 1 | N | Y | |
| .. | ... | ... | ... | ... | ... | ... | .. | ... |
+----+-------+------+------+-------------------+-----------+-------+----+-------------------+
I need to create the table with data from my_table
| Date | № of Entries (in that date) | Total № of Entries | Premium | Free | Afiiliate |
The final table in file should looks like:
Report 17-07-2013:
+----------+--------------+-------+---------+------+-----------+
| Date | № of Entries | Total | Premium | Free | Afilliate |
|2013-07-17| 2 | 99845 | 2 | 0 | 0 |
|2013-07-18| 1 | 99843 | 0 | 1 | 0 |
|2013-07-22| 1 | 99842 | 1 | 0 | 1 |
|2013-07-23| 3 | 99841 | 2 | 1 | 2 |
|2013-07-24| 298 | 99838 | 32 | 273 | 25 |
|2013-07-25| 5526 | 99540 | 474 | 5058 | 126 |
|2013-07-26| 1686 | 94014 | 157 | 1532 | 56 |
|2013-07-27| 1673 | 92328 | 156 | 1517 | 97 |
|2013-07-28| 1461 | 90655 | 155 | 1310 | 83 |
| ... | ... | ... | ... | ... | ... |
+----------+--------------+-------+---------+------+-----------+
Should I for each column do a SELECT or I should do only 1 select?
If it possible to do 1 select how to do it?
It should be by analogy with this report:
report
Some fields differ (like 'Number of Entries in that date').
Total number of Entries means: all entries from beginning to the that specific date.
Number of Entries in that date means: all entries in that date.
In a final table the date from column Date will not repeat, that's why Column 'Number of Entries (in that date)' will calculate all entries for that date.
Your result is not so clear for the total is a count or sum and affiliate is sum or count also
but assuming total will be count and affiliate will be sum
here a query you might use to give you a result ( using ms-sql )
select DateCreated,count(EntryId) as Total,
sum(case when Premium='Y' then 1 else 0 end) as Premium,
sum(case when Premium='N' then 1 else 0 end) as Free,
sum(AffiliateId) as Affiliate
from sample
group by DateCreated
here a working demo
if I didn't understood you correctly, kindly advise
hope it will help you
SQLFiddle Demo: http://sqlfiddle.com/#!9/20cc0/5
The added column entryID does not matter for us.
I don't really understand what you want for Total, or the criteria for affiliateID. This query should get you started.
SELECT
DATE(dateCreated) as "Date",
count(dateCreated) as "No of Entries",
99845 as Total,
sum( case when premium='Y' then 1 else 0 end ) as Premium,
sum( case when premium='N' then 1 else 0 end ) as Free,
sum( case when affiliateID IS NOT NULL then 1 else 0 end) as Affiliate
FROM MyTable
GROUP BY DATE(dateCreated)
ORDER BY Date ASC
The final table in file should looks like:
... This new table can be in a file or in the web page. But it is not a new table in DB. –
It sounds like you may be new to this area so I just wanted to inform you that spitting out a report into a file for a website is highly unusual and typically only done when your data is completely separate from the website. Putting data from a database onto a website (like the query we made here) is very common and it's very likely you don't need to mess with any files.
select date(DateCreated),count(entryId) as Total,
sum(case when Premium='Y' then 1 else 0 end) as Premium,
sum(case when Premium='N' then 1 else 0 end) as Free,
sum( case when affiliateID IS NOT NULL then 1 else 0 end) as Affiliate
INTO OUTFILE '/tmp/myfile.csv'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
from my_table
group by date(DateCreated) order by date(DateCreated);
This query runs on an invoices table to help me decide who I need to pay
Here's the base table:
The users table
+---------+--------+
| user_id | name |
+---------+--------+
| 1 | Peter |
| 2 | Lois |
| 3 | Stewie |
+---------+--------+
The invoices table:
+------------+---------+----------+--------+---------------+---------+
| invoice_id | user_id | currency | amount | description | is_paid |
+------------+---------+----------+--------+---------------+---------+
| 1 | 1 | usd | 140 | Cow hoof | 0 |
| 2 | 1 | usd | 45 | Cow tail | 0 |
| 3 | 1 | gbp | 1 | Cow nostril | 0 |
| 4 | 2 | gbp | 1500 | Cow nose hair | 0 |
| 5 | 2 | cad | 1 | eyelash | 1 |
+------------+---------+----------+--------+---------------+---------+
I want a resulting table that looks like this:
+---------+-------+----------+-------------+
| user_id | name | currency | SUM(amount) |
+---------+-------+----------+-------------+
| 1 | Peter | usd | 185 |
| 2 | Lois | gbp | 1500 |
+---------+-------+----------+-------------+
The conditions are:
Only consider invoices that have not been paid, so where is_paid = 0
Group them by user_id, by currency
If the SUM(amount) < $100 for the user_id, currency pair then don't bother showing the result, since we don't pay invoices that are less than $100 (or equivalent, based on a fixed exchange rate).
Here's what I've got so far (not working -- which I guess is because I'm filtering by a GROUP'ed parameter):
SELECT
users.user_id, users.name,
invoices.currency, SUM(invoices.amount)
FROM
mydb.users,
mydb.invoices
WHERE
users.user_id = invoices.user_id AND
invoices.is_paid != true AND
SUM(invoices.amount) >=
CASE
WHEN invoices.currency = 'usd' THEN 100
WHEN invoices.currency = 'gbp' THEN 155
WHEN invoices.currency = 'cad' THEN 117
END
GROUP BY
invoices.currency, users.user_id
ORDER BY
users.name, invoices.currency;
Help?
You can't use SUM in a WHERE. Use HAVING instead.
Use HAVING clause instead of SUM in WHERE condition
Try this:
SELECT u.user_id, u.name, i.currency, SUM(i.amount) invoiceAmount
FROM mydb.users u
INNER JOIN mydb.invoices i ON u.user_id = i.user_id
WHERE i.is_paid = 0
GROUP BY u.user_id, i.currency
HAVING SUM(i.amount) >= (CASE i.currency WHEN 'usd' THEN 100 WHEN 'gbp' THEN 155 WHEN 'cad' THEN 117 END)
ORDER BY u.name, i.currency;
Try something like this:
SELECT
user_id, name, currency, sum(amount) due
FROM
invoice i
JOIN users u ON i.user_id=u.user_id
WHERE
is_paid = 0 AND
GROUP BY user_id, currency
having due >= 100
do you store exchange rates? Multiply rates with amount to get actual amount with respect to base currency.
sum(amount*ex_rate) due
I have a simple query where I select available x Rooms with x Adults + x Children per hotel that matches a date range, but I'm having a hard time trying to figure out how to query a list of rooms per hotel like this:
1 Room with 2 Adults / 0 Children
1 Room with 4 Adults / 2 Children
1 Room with 2 Adults / 1 Children
Here is my query:
SELECT COUNT(pl.day) AS Days,
p.property_ID AS Hotel_ID,
p.name AS Hotel_Name,
r.room_name AS Room_Name,
r.room_type_ID AS Room_ID
FROM property p
INNER JOIN room_type r ON p.property_ID=r.property_ID
AND (r.max_adults >= 3
AND r.max_children >= 0)
INNER JOIN plan pl ON pl.room_type_ID=r.room_type_ID
AND (pl.day >= "2014-07-07"
AND pl.day <= "2014-07-11")
GROUP BY Room_ID,
Hotel_ID HAVING Days = 4
EDIT
How do I add 'No_of_Room' in SELECT that differentiates the room_types by the room number, example result of a single room:
Array
(
[Room_Price] => 160.00
[Days] => 4
[Hotel_ID] => 1
[Hotel_Name] => Hotel Alfa
[Room_Name] => Room type C
[Room_ID] => 3
[Max_Adults] => 3
[Max_Children] => 1
[No_of_Room] => 1 // What number of room does this room_type belongs to
)
Then I can show the results like:
EDIT
Rooms table
Rooms(
ID,
hotel_id
room_name,
max_Adults,
max_Children
);
-- Populate
INSERT INTO Rooms VALUES (1,1,"Room A",2,1),(2,1,"Room B",2,5),(3,1,"Room C",3,0);
INSERT INTO Rooms VALUES (1,2,"Room A",2,1),(2,2,"Room B",2,5),(3,3,"Room C",3,4);
EXAMPLES OF USING VIEWS TO MAKE THINGS NICER.
For this project authors may have aliases, for example one book may have "S. Lang" as the author, another might have "Serge Lang", the primary author is the main form (Serge Lang) and the secondaries are things like "S. Lang".
It is important to relate these, ideally I'd like a table with "AuthorId" and "PrimaryAuthorId" as columns, that way I could just select PrimaryAuthorId from it on AuthorId being equal to something.
To do this the view is defined as:
select
`BookSystem_AuthorList`.`AuthorId` AS `AuthorId`,
if((`BookSystem_AuthorList`.`duplicateOf` = 0),
`BookSystem_AuthorList`.`AuthorId`,
`BookSystem_AuthorList`.`duplicateOf`
) AS `PrimaryAuthorId`
from `BookSystem_AuthorList`;
Then
SELECT PrimaryAuthorId FROM BookSystem_PrimaryAuthorId WHERE AuthorId=10;
gives:
7
Which is much nicer for joining!
I then use this view to define another view (EditionAuthorsWithPrimaryId) - this gets the authors of an edition - and the primary author (I can then join to get names as needed)
select
`BookSystem_EditionAuthors`.`BindingId` AS `BindingId`,
`BookSystem_EditionAuthors`.`EditionId` AS `EditionId`,
`BookSystem_EditionAuthors`.`AuthorId` AS `AuthorId`,
`BookSystem_EditionAuthors`.`Position` AS `Position`,
(select
`BookSystem_PrimaryAuthorId`.`PrimaryAuthorId`
from `BookSystem_PrimaryAuthorId`
where (`BookSystem_PrimaryAuthorId`.`AuthorId` = `BookSystem_EditionAuthors`.`AuthorId`)
) AS `PrimaryAuthorId`
from `BookSystem_EditionAuthors`;
Now I can do:
SELECT * FROM BookSystem_EditionAuthorsWithPrimary WHERE EditionId=10;
BindingId, EditionId, AuthorId, Position, PrimaryAuthorId
10, 10, 10, 0, 7
Much nicer!
this next query is a great example
select
`BookSystem_BookList`.`BookId` AS `Id`,
`BookSystem_BookList`.`Title` AS `Name`,
`BookSystem_BookList`.`UserId` AS `UserId`,
`BookSystem_BookList`.`BookType` AS `Subtype`,
1 AS `IsBook`,0 AS `IsSeries`,
0 AS `IsAuthor`
from `BookSystem_BookList`
union
select
`BookSystem_SeriesList`.`SeriesId` AS `Id`,
`BookSystem_SeriesList`.`SeriesName` AS `Name`,
`BookSystem_SeriesList`.`UserId` AS `UserId`,
'' AS `Subtype`,
0 AS `IsBook`,
1 AS `IsSeries`,
0 AS `IsAuthor`
from `BookSystem_SeriesList`
union
select
`BookSystem_AuthorList`.`AuthorId` AS `Id`,
concat(
`BookSystem_AuthorList`.`AuthorSurname`,', ',`BookSystem_AuthorList`.`AuthorForename`,
ifnull(
(select concat(
' (AKA: ',
group_concat(
concat(
`BookSystem_AuthorList`.`AuthorSurname`,
', ',
`BookSystem_AuthorList`.`AuthorForename`
) separator '; '
),')'
) AS `AKA` from `BookSystem_AuthorList`
where
(`BookSystem_AuthorList`.`duplicateOf` = `Id`)
group by (`BookSystem_AuthorList`.`duplicateOf` = `Id`)
),'')) AS `Name`,
`BookSystem_AuthorList`.`UserId` AS `UserId`,
'' AS `SubType`,
0 AS `IsBook`,
0 AS `IsSeries`,
1 AS `IsAuthor`
from `BookSystem_AuthorList`
where (`BookSystem_AuthorList`.`duplicateOf` = 0) order by `Name`;
IS HUGE!
But now I can get all the things for UserId=1 easily:
mysql> SELECT * FROM BookSystem_Index WHERE UserId = 1;
+----+----------------------------------------+--------+-------------+--------+----------+----------+
| Id | Name | UserId | Subtype | IsBook | IsSeries | IsAuthor |
+----+----------------------------------------+--------+-------------+--------+----------+----------+
| 4 | A First Course in Calculus | 1 | Normal | 1 | 0 | 0 |
| 2 | A First Course in Real Analysis | 1 | Normal | 1 | 0 | 0 |
| 2 | Algebra | 1 | | 0 | 1 | 0 |
| 13 | Analysis II assignments | 1 | Assignments | 1 | 0 | 0 |
| 14 | Author Test | 1 | Normal | 1 | 0 | 0 |
| 8 | b, g | 1 | | 0 | 0 | 1 |
| 7 | b, g (AKA: t, lll; Teal, lll) | 1 | | 0 | 0 | 1 |
| 1 | Calculus of Several Variables | 1 | Normal | 1 | 0 | 0 |
| 4 | DuBois, Paul | 1 | | 0 | 0 | 1 |
| 1 | Lang, Serge (AKA: Lang, S. E. R. G. E) | 1 | | 0 | 0 | 1 |
| 5 | Linear Algebra | 1 | Normal | 1 | 0 | 0 |
| 3 | Morrey, C. B. | 1 | | 0 | 0 | 1 |
| 6 | MySQL | 1 | Normal | 1 | 0 | 0 |
| 7 | Principles of Mathematical Analysis | 1 | Normal | 1 | 0 | 0 |
| 2 | Protter, M. H. | 1 | | 0 | 0 | 1 |
| 5 | Rudin, Walter | 1 | | 0 | 0 | 1 |
| 10 | t | 1 | Normal | 1 | 0 | 0 |
| 3 | Test | 1 | | 0 | 1 | 0 |
| 12 | Test 1 | 1 | Normal | 1 | 0 | 0 |
| 11 | Test 4.4.2014 | 1 | Normal | 1 | 0 | 0 |
| 8 | Topology and Analysis | 1 | Normal | 1 | 0 | 0 |
| 3 | Undergraduate Algebra | 1 | Normal | 1 | 0 | 0 |
| 1 | Undergraduate Texts in Mathematics | 1 | | 0 | 1 | 0 |
| 9 | w | 1 | Normal | 1 | 0 | 0 |
+----+----------------------------------------+--------+-------------+--------+----------+----------+
24 rows in set (0.00 sec)
The optimiser sees the view properly, it wont generate the full view, it effectively substitutes the required selects.
(Taken from a testing DB, not production, hence weird names like "TESTING")
First, the room type selection needs to be framed correctly. The following join would probably work.
EDIT:
The query has been edited to return only properties with all three room types. It has also been joined with the plan table.
SELECT
COUNT(pl.day) AS Days,
p.property_ID AS Hotel_ID,
p.name AS Hotel_Name,
r.room_name AS Room_Name,
r.room_type_ID AS Room_ID,
r.max_adults as Max_Adults,
r.max_children as Max_Children
FROM property p
INNER JOIN room_type r
ON p.property_ID=r.property_ID
INNER JOIN plan pl
ON pl.room_type_ID=r.room_type_ID
AND (pl.day >= '2014-07-07' AND pl.day <= '2014-07-11')
WHERE EXISTS
(SELECT 1
FROM room_type r1
WHERE p.property_ID=r1.property_ID
AND r1.max_adults = 2 AND r1.max_children = 0)
AND EXISTS
(SELECT 1
FROM room_type r2
WHERE p2.property_ID=r2.property_ID
AND r2.max_adults = 4 AND r2.max_children = 2)
AND EXISTS
(SELECT 1
FROM room_type r3
WHERE P.PROPERTY_ID=R3.PROPERTY_ID
AND r3.max_adults = 2 AND r3.max_children = 1)
GROUP BY
p.property_ID,
p.name,
r.room_name,
r.room_type_ID,
r.max_adults,
r.max_children
HAVING
COUNT(pl.day) = 4;
I am trying to build complex mysql query but its returning wrong results...
SELECT
b.name AS batch_name,
b.id AS batch_id,
COUNT(DISTINCT s.id)
AS total_students,
COALESCE( SUM(s.open_bal), 0 )
AS open_balance,
SUM( COALESCE(i.reg_fee, 0)
+ COALESCE(i.tut_fee, 0)
+ COALESCE(i.other_fee, 0)
) AS gross_fee,
SUM( COALESCE(i.discount, 0) )
AS discount,
COALESCE( SUM(s.open_bal), 0 )
+ SUM( COALESCE(i.reg_fee, 0)
+ COALESCE(i.tut_fee, 0)
+ COALESCE(i.other_fee, 0)
)
- SUM( COALESCE(i.discount, 0) )
AS net_payable,
SUM( COALESCE(r.reg_fee, 0)
+ COALESCE(r.tut_fee, 0)
+ COALESCE(r.other_fee, 0)
) AS net_recieved,
( COALESCE( SUM(s.open_bal), 0 )
+ SUM( COALESCE(i.reg_fee, 0)
+ COALESCE(i.tut_fee, 0)
+ COALESCE(i.other_fee, 0)
)
- SUM( COALESCE(i.discount, 0) )
)
- ( SUM( COALESCE(r.reg_fee, 0)
+ COALESCE(r.tut_fee, 0)
+ COALESCE(r.other_fee, 0)
)
)
AS balance_due
FROM batches b
LEFT JOIN students s ON s.batch = b.id
LEFT JOIN invoices i ON i.student_id = s.id
LEFT JOIN recipts r ON r.student_id = s.id
WHERE s.inactive = 0
GROUP BY b.name, b.id;
Returns following results...
| batch_name | total_students | open_bal | gross_fee | discount | net_payable | net_recieved | due_balance |
+------------+-----------------+----------+-----------+----------+-------------+--------------+-------------+
| MS | 6 | 10000 | 0 | 0 | 10000 | 101000 | -91000 |
+------------+-----------------+----------+-----------+----------+-------------+--------------+-------------+
batches table
| id | name |
+-----+------+
| 9 | Ms |
+-----+------+
Students table
| id | open_bal | batch | inactive |
+-----+----------+-------+----------+
| 44 | -16000 | 9 | 0 |
+-----+----------+-------+----------+
| 182 | 9000 | 9 | 0 |
+-----+----------+-------+----------+
| 184 | -36000 | 9 | 0 |
+-----+----------+-------+----------+
| 185 | 19000 | 9 | 0 |
+-----+----------+-------+----------+
| 186 | 9000 | 9 | 0 |
+-----+----------+-------+----------+
| 187 | 4000 | 9 | 0 |
+-----+----------+-------+----------+
Invoices Table
| id | student_id | reg_fee | tut_fee | other_fee | net_payable | discount |
+------+------------+---------+---------+-----------+-------------+----------+
| | | | | | | |
+------+------------+---------+---------+-----------+-------------+----------+
No invoices are available for above students id.
Recipts table
| id | student_id | reg_fee | tut_fee | other_fee | status |
+------+------------+---------+---------+-----------+------------+
| 8 | 44 | 0 | 0 | 1500 | confirmed |
+------+------------+---------+---------+-----------+------------+
| 277 | 44 | 0 | 50000 | 0 | confirmed |
+------+------------+---------+---------+-----------+------------+
| 26 | 182 | 0 | 0 | 1500 | confirmed |
+------+------------+---------+---------+-----------+------------+
| 424 | 182 | 0 | 15000 | 0 | confirmed |
+------+------------+---------+---------+-----------+------------+
| 468 | 182 | 0 | 15000 | 0 | confirmed |
+------+------------+---------+---------+-----------+------------+
| 36 | 185 | 0 | 0 | 1500 | confirmed |
+------+------------+---------+---------+-----------+------------+
| 697 | 185 | 0 | 15000 | 0 | confirmed |
+------+------------+---------+---------+-----------+------------+
| 66 | 187 | 0 | 0 | 1500 | confirmed |
+------+------------+---------+---------+-----------+------------+
Expected results using above sql query and tables...
| batch_name | total_students | open_bal | gross_fee | discount | net_payable | net_recieved | due_balance |
+------------+-----------------+----------+-----------+----------+-------------+--------------+-------------+
| MS | 6 | -11000 | 0 | 0 | 10000 | 101000 | -112000 |
+------------+-----------------+----------+-----------+----------+-------------+--------------+-------------+
You still haven't provided full information - no batches table, even the not existing recipts table.. Anyway, I assume we don't care whats in the batches table, lets say it's just the name and id. Your receipts table have multiple rows for the same student. This should result in multiple rows returned for the other tables as well, due to all the JOINs. Therefore you SUM() multiple times values which must be summed just once, i.e. open_balance. This could be a clue as to where the problem is, I'd say you have to move the info that you need from 'the receipts table into subqueries, but I'm not sure you've shown us the entirety of your DB. Try removing the receipts table from the query and check the results again. If that's it, you should see what to do from there on or at least give more info to us.
EDIT:
The query should be:
SELECT
b.name AS batch_name,
b.id AS batch_id,
COUNT(DISTINCT s.id)
AS total_students,
COALESCE( SUM(s.open_bal), 0 )
AS open_balance,
SUM( COALESCE(i.reg_fee, 0)
+ COALESCE(i.tut_fee, 0)
+ COALESCE(i.other_fee, 0)
) AS gross_fee,
SUM( COALESCE(i.discount, 0) )
AS discount,
COALESCE( SUM(s.open_bal), 0 )
+ SUM( COALESCE(i.reg_fee, 0)
+ COALESCE(i.tut_fee, 0)
+ COALESCE(i.other_fee, 0)
)
- SUM( COALESCE(i.discount, 0) )
AS net_payable,
SUM((SELECT SUM(COALESCE(receipts.reg_fee, 0)
+ COALESCE(receipts.tut_fee, 0)
+ COALESCE(receipts.other_fee, 0)) FROM receipts WHERE receipts.student_id = s.id))
AS net_recieved,
( COALESCE( SUM(s.open_bal), 0 )
+ SUM( COALESCE(i.reg_fee, 0)
+ COALESCE(i.tut_fee, 0)
+ COALESCE(i.other_fee, 0)
)
- SUM( COALESCE(i.discount, 0) )
)
- SUM((SELECT SUM(COALESCE(receipts.reg_fee, 0)
+ COALESCE(receipts.tut_fee, 0)
+ COALESCE(receipts.other_fee, 0)) FROM receipts WHERE receipts.student_id = s.id))
AS balance_due
FROM batches b
LEFT JOIN students s ON s.batch = b.id
LEFT JOIN invoices i ON i.student_id = s.id
WHERE s.inactive = 0
GROUP BY b.name, b.id;
This will sum students data in the receipts table even if it's on more than one row, returning just one row. Removing the join to the receipts table removes duplicate lines from the other tables, so the calculations should now be correct.
One more thing - you've got s.inactive = 0 in the WHERE clause, make sure it's not relevant to this calculations.
P.S. How come you don't know what a sub query is and you end up writing stuff like that?
I have got the solution, i was joining lots of queries together and that's by some results are doubling. thanks.