I am generating a report to show outstanding Fee Like which Fee Type, How much amount is Fixed for that Fee Type, How Much Amount Paid for that Fee type and finally Balance Amount to be paid for that fee Type.
Here I am pulling data from 5 tables like Class Names from Classes table, Roll no & Student Name from admissions table, Fee Types from Feevars table, amount fixed for fee type from studentfees table, and finally amounts paid for fee types from fee collection table.
I am able to generate the partial results by mentioning the fee type names in select statment by summing and subtracting operations.
Here is the full database and my query producing the result. Please review **@ my query in this demo, in the select statement I have mentioned the fee types manually.
But I want to generate the result without mentioning the Fee type as Column names.
For this I did one thing, I had taken all the fee types into a sql variable
like this
set @sqlList = null;SELECT GROUP_CONCAT(concat('tsf.', Replace(FeeName,' ',''))) INTO @sqlList FROM tbl_feevars;
this will result all the Fee types into single line as column names.
And Finally I have written code to produce output what I am expecting, but I am getting error like Error Code 1064: You have error in your sql syntax.
This is My final code
Please anyone tell me, what is error in my sql query. And suggest me if any?? other way to do this report.
My Tables:
CREATE TABLE `tbl_admission` (
`AdmNo` varchar(50) NOT NULL,
`Grp` varchar(45) NOT NULL,
`Cls` varchar(45) NOT NULL,
`rollno` int(11) NOT NULL,
`StdNm` varchar(50)
);
CREATE TABLE `tbl_classes` (
`C_Id` int(11),
`C_Name` varchar(255) NOT NULL,
`G_Id` int(11) NOT NULL,
`status` tinyint(1)
);
CREATE TABLE `tbl_feevars` (
`id` int(11) NOT NULL,
`FeeName` varchar(70) NOT NULL
);
CREATE TABLE `tbl_stdfees` (
`id` int(11),
`Admno` varchar(50) default NULL,
`admissionfee` float(10,2) default '0.00',
`splfee` float(10,2) default '0.00',
`tutionfee` float(10,2) default '0.00',
`computerfee` float(10,2) default '0.00',
`stationary` float(10,2) default '0.00',
`transport` float(10,2) default '0.00',
`hostelfee` float(10,2) default '0.00',
`lab` float(10,2) default '0.00',
`library` float(10,2) default '0.00',
`miscell` float(10,2) default '0.00'
);
CREATE TABLE `tbl_feecollection` (
`auto_id` int(11) NOT NULL auto_increment,
`GrupNm` varchar(40) NOT NULL,
`class` varchar(30) NOT NULL,
`rollno` int(2) NOT NULL,
`sadmno` int(11) NOT NULL,
`PaM` varchar(30) NOT NULL,
`DDCN` int(25) NOT NULL,
`bank` varchar(30) NOT NULL,
`cheqd` date NOT NULL,
`remarks` varchar(150) NOT NULL,
`pdate` date NOT NULL,
`admissionfee` float(10,2) default '0.00',
`splfee` float(10,2) default '0.00',
`tutionfee` float(10,2) default '0.00',
`computerfee` float(10,2) default '0.00',
`stationary` float(10,2) default '0.00',
`transport` float(10,2) default '0.00',
`hostelfee` float(10,2) default '0.00',
`lab` float(10,2) default '0.00',
`library` float(10,2) default '0.00',
`miscell` float(10,2) default '0.00',
PRIMARY KEY (`auto_id`)
);
My current query is:
set @sqlList = null;
SET @sqlList1 = null;
set @query = null;
SELECT
GROUP_CONCAT(concat('tsf.', Replace(FeeName,' ','')))
INTO @sqlList
FROM tbl_feevars;
SELECT
GROUP_CONCAT(concat('tfc.', Replace(FeeName,' ','')))
INTO @sqlList1
FROM tbl_feevars;
SET @query
= CONCAT('SELECT tsf.Admno,',@sqlList,',ta.StdNm,
sum(',@sqlList1,') as ''feepaid'',
(',@sqlList,' - sum(',@sqlList1,')) as ''outstanding fee''
FROM
tbl_stdfees tsf,
tbl_Admission ta,
tbl_feecollection tfc
where
tsf.admno = ta.admno
and tfc.sadmno = tsf.admno group by ta.stdnm);');
select @query;
PREPARE stmt FROM @query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Best Answer
Well there are a few issues that I see with your existing query. You current sql statement is the following:
The problem is that you are attempting to aggregate multiple columns in your
sum()
. Thesum()
can only aggregate one column at a time.Second, in my opinion your tables
tbl_stdfees
andtbl_feecollection
are poorly designed. You have basically created a spreadsheet in you table to contain the fees required and then the fees that were paid. The problem is if you need to add a new fee you have to add a new column, that demonstrates a poor design.I don't think that you need to use dynamic SQL to get the result, you need to unpivot or normalize the data in those two tables. To unpivot the data you will use a UNION ALL query to convert the multiple columns into multiple rows.
The query to unpivot the data would be similar to the following:
tbl_stdfees
:tbl_feecollection
:Once you have unpivoted the data, you can easily get the total fees for each
admno
and the total fees paid. The entire query to get the result would be:See SQL Fiddle with Demo.
As I said I would suggest that you normalize the tables in your database. I would suggest making the following changes to your database.
Create a
payment
table:Create a table to join the standard fees to each
admno
:Then create a table to join the
admno
to each payment and fee collected:If you normalize the tables, then you would use a query similar to the following:
See SQL Fiddle with Demo. The second version could then be converted into a dynamic SQL version to get a list of all of the fees that you have in the
tbl_feevars
tables. Both versions will give a result: