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.
Related
Below is my mysql query :
SELECT u.id,
CASE WHEN (p.PaymentType = "FreeCredit") THEN SUM(p.CreditedAmount) ELSE 0 END AS freecredit ,
CASE WHEN (p.PaymentType = "Online") THEN SUM(p.CreditedAmount) ELSE 0 END AS onlinepayment,
CASE WHEN (p.PaymentType = "Cash") THEN SUM(p.CreditedAmount) ELSE 0 END AS Cash
FROM users as u
LEFT JOIN payment as p on u.id = p.UserId AND p.PaymentSucc = "Yes"
WHERE
`u`.`UserType` = 'User'
GROUP BY p.UserId
ORDER BY u.id DESC;
Required result : in payment table I have 3 payment type in result I required to show sum for particular payment type for single user like below,
userid= 1974
PaymentType = FreeCredit,CreditedAmount= 120
PaymentType = Online ,CreditedAmount== 140
PaymentType = cash ,CreditedAmount==100
PaymentType = FreeCredit,CreditedAmount== 100
PaymentType = Online ,CreditedAmount== 120
PaymentType = cash ,CreditedAmount==170
in required result it should be as below,
id freecredit onlinepayment Cash
1972 220 260 270
from my query ,I am not able to get above result ,please can any person help me to resolve my this mysql query issue:
I will appreciate best answer.
This is a good question (y)
So,
Here's table user:
mysql> select * from user;
+----+-----------+
| id | user_type |
+----+-----------+
| 1 | krish |
| 2 | bala |
+----+-----------+
Here's table payment:
mysql> select * from payment;
+------+-------------+----------------+
| id | PaymentType | CreditedAmount |
+------+-------------+----------------+
| 1 | FreeCredit | 120 |
| 1 | Online | 140 |
| 1 | cash | 100 |
| 1 | FreeCredit | 100 |
| 1 | Online | 120 |
| 1 | cash | 170 |
| 2 | FreeCredit | 500 |
| 2 | Online | 450 |
| 2 | FreeCredit | 230 |
+------+-------------+----------------+
The goal is to have - for each ID - the sum of 'FreeCredit' / 'Online' / 'cash'
select u.id, sum(case when PaymentType = "FreeCredit" then
CreditedAmount else 0 end) as freeamnt, sum(case when PaymentType =
'Online' then CreditedAmount else 0 end) as Online, sum(case when
PaymentType = 'cash' then Creditedamount else 0 end) as cash from user
as u left join payment as p on u.id=p.id group by p.id order by u.id
desc;
+----+----------+--------+------+
| id | freeamnt | Online | cash |
+----+----------+--------+------+
| 3 | 0 | 0 | 0 |
| 2 | 730 | 450 | 0 |
| 1 | 220 | 260 | 270 |
+----+----------+--------+------+
3 rows in set (0.03 sec)
Note:
I simulated a sample based upon your examples
The query is based on my sample and it won't have all the 'where' conditions you have given
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);
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 have the following schema setup :
table name : thing
Column | type
----------------------------
id | auto increment int
ident | int
cost1 | int
cost2 | int
cost3 | int
table name : thing_usage
column | type
---------------------------------
id | auto increment int
thing | int - FK to thing.id
usage_type | int
data | int
duration | int
with some data :
thing :
id | ident | cost1 | cost2 | cost3
------------------------------------------------
1 | 1234 | 1 | 2 | 3
2 | 5678 | 0 | 0 | 0
thing_usage :
id | thing | usage_type | data | duration
--------------------------------------------------------
1 | 1 | 1 | 5555 | 0
2 | 1 | 1 | 3 | 0
3 | 1 | 2 | 0 | 123
4 | 1 | 3 | 232 | 12
All available here -> SQLFiddle
What I would like to output if a single row for each thing like this :
thing | cost1 | usage1 | cost2 | usage2 | cost3 | usage3
------------------------------------------------------------------------
1 | 1 | 5558 | 2 | 00:02:03 | 3 | 232
2 | 0 | 0 | 0 | 0 | 0 | 0
cost1 uses usage_type of 1, cost2 uses usage_type of 2 and so on ...... and cost1 and cost3 use data for its usage and cost2 converts duration from seconds to hh:mm:ss for usage - usage should be summed
At the moment i have to create 2 queries and so this in code - so i loop all thing rows then get the usage for it and output accordingly
Is there any way that I can get the desired output from a single query - perhaps using a subquery of some kind?
Hopefully this is what you were looking for:
SELECT thing_usage1.id
,thing.id
,thing.cost1
,SUM(thing_usage1.data) AS usage1
,thing.cost2
,TIME_FORMAT(SEC_TO_TIME(thing_usage2.duration),'%H:%i:%s') AS usage2
,thing.cost3
,SUM(thing_usage3.data) AS usage3
FROM thing AS thing
INNER JOIN thing_usage AS thing_usage1 ON thing.id = thing_usage1.thing
AND thing.cost1 = thing_usage1.usage_type
INNER JOIN thing_usage AS thing_usage2 ON thing.id = thing_usage2.thing
AND thing.cost2 = thing_usage2.usage_type
INNER JOIN thing_usage AS thing_usage3 ON thing.id = thing_usage3.thing
AND thing.cost3 = thing_usage3.usage_type
GROUP BY thing_usage1.id
,thing.id
,thing.cost1
,thing.cost2
,thing.cost3
Here is an example of it working: http://sqlfiddle.com/#!2/68f430/51
Updated my logic to account for the SUMming piece, as well as the use of duration.
If you want to do it "manually" here is something to get you started:
SELECT
th.ident,
th.cost1,
SUM(tu.data) as usage1data
FROM
thing th
JOIN thing_usage tu
ON th.id = tu.thing
WHERE tu.usage_type = 1
GROUP BY th.id, tu.usage_type
And this query should get you going on collecting all sums in one statement:
SELECT
tu.thing,
SUM(CASE WHEN usage_type=1 THEN tu.data ELSE 0 END) AS usage1,
SUM(CASE WHEN usage_type=2 THEN tu.data ELSE 0 END) AS usage2,
SUM(CASE WHEN usage_type=3 THEN tu.data ELSE 0 END) AS usage3
FROM
thing_usage tu
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