Calculating using SUM, query does not work? - mysql

I have two tables.
a) ai_account
b) ai_order_product
i want to do some calculations for particular supplier_id.
1, totalAmount, i want to do something like
SUM(ai_order_product.quantity * ai_order_product.cost)
2, amountPaid, this is total amount paid by the supplier that will be
something like SUM(ai_account.amount) with reference to supplier_id.
3) balance, this will be calculated by SUM(ai_order_product.quantity *
ai_order_product.cost) - SUM(ai_invoice.amount)
4) lastPayment date, that will be MAX(ai_account.addDate).
i tried doing something like this.
SELECT SUM(op.quantity * op.cost) as totalAmount,
SUM(ac.amount) as amountPaid,
SUM(op.quantity * op.cost) - SUM(ac.amount) as balance,
MAX(ac.addDate) as lastPayment
FROM ai_order_product op
LEFT JOIN ai_account ac
ON (op.supplier_id = ac.trader_id)
WHERE op.supplier_id = 42
it does not work properly, it fetches some unexpected values, whereas the result for the above being expected is,
for supplier_id = 42,
1) totalAmount = 1375,
2) amountPaid = 7000,
3) balance = -5625,
4) lastPayment = 2011-11-23
and for supplier_id = 35,
1) totalAmount = 1500,
2) amountPaid = 43221,
3) balance = -41721,
4) lastPayment = 2011-11-28
and for supplier_id = 41
1) totalAmount = 0
2) amountPaid = 3000,
3) balance = -3000,
4) lastPayment = 2011-11-09
i want to fetch one row by supplier_id.
P.S: i just entered some dummy values that is why the calculations are mostly negative whereas in application the calculated values will be positive.

Thats because each "ai_order_product" row is getting counted multiple times (once for each row present in the ai_account table).
Try this:
SELECT
op.totalAmount as totalAmount
, SUM(ac.amount) as amountPaid
, op.totalAmount - SUM(ac.amount) as balance
, MAX(ac.addDate) as lastPayment
FROM (
select supplier_id, sum(quantity * cost) as totalAmount
from ai_order_product
group by supplier_id) op
LEFT JOIN ai_account ac ON (op.supplier_id = ac.trader_id)
WHERE op.supplier_id = 42
This may be slightly off, but this general logic should work.

You have to use to state GROUP BY, when using aggregate functions like SUM in SELECT statements.
SELECT op.supplier_id as supplierId,
SUM(op.quantity * op.cost) as totalAmount,
SUM(ac.amount) as amountPaid,
SUM(op.quantity * op.cost) - SUM(ac.amount) as balance,
MAX(ac.addDate) as lastPayment
FROM ai_order_product op
LEFT JOIN ai_account ac
ON (op.supplier_id = ac.trader_id)
GROUP BY op.supplier_id
HAVING supplierId = 42

SELECT
SUM(op.quantity * op.cost) as totalAmount
, ac2.amountPaid
, SUM(op.quantity * op.cost) - ac2.balance
, ac2.lastPayment
FROM ai_order_product op
LEFT JOIN (SELECT
ac.supplier_id
, MAX(ac.addDate) as lastPayment
, SUM(ac.amount) as balance
FROM ai_account ac
WHERE (op.supplier_id = ac.supplier_id)
GROUP BY ac.supplier_id) ac2 ON (ac2.supplier_id = op.supplier_id)
WHERE op.supplier_id = 42
GROUP BY op.supplier_id
The group by clauses kick in when you're selecting more than one supplier_id.

Notice that your expected and actual values are doubled. After entering your sample data and running the query, I get (for supplier_id = 42)
+-------------+------------+---------+-------------+
| totalAmount | amountPaid | balance | lastPayment |
+-------------+------------+---------+-------------+
| 2750 | 14000 | -11250 | 2011-11-23 |
+-------------+------------+---------+-------------+
That's because you've got 2 rows in each table that match the join criteria, causing a doubling of the results.

I think you need to first get the sub totals for one of the tables so that you only have 1 row coming back. thus the inner select here returns the max and the sum, so when you join to it you only get 1 row.
SELECT SUM(op.quantity * op.cost) as totalAmount,
ac.addDate as lastPayment,
ac.amount as amountPaid,
SUM(op.quantity * op.cost) - SUM(ac.amount) as balance
FROM ai_order_product op
INNER JOIN (
SELECT max(IaiaddDate) as addDate, sum(iai.amount) as Amount, iai.supplier_ID
FROM ai_account iai
Group by supplier_ID) ac
ON AC.Supplier_ID = Op.Supplier_ID
WHERE op.supplier_id = 42
Group by Ac.addDate, ac.amount, op.supplier_ID --Just incase where clause is left off.

Related

add some column and minus another column

I have two table insert1 and received1
in insert1 table have column and column name is recharge_account.
received table have one column and column name is received_amount.
I want to total recharge_ammount - total received_amount as dues.
recharge_Account Received_Amount dues
500 - 400 100
SELECT
SUM(Account_recharge) AS `Total Recharge`,
SUM(Amount_Received) AS `Total Received`,
SUM(Account_recharge) - SUM(Amount_Received) AS dues
FROM insert1 i1
INNER JOIN received1 r1
i am not get to exact calculation .
You just need a join condition such as ON i1.id = r1.ins_id, and COALESCE() function against null values :
SELECT
SUM(COALESCE(Account_recharge,0)) AS `Total Recharge`,
SUM(COALESCE(Amount_Received,0)) AS `Total Received`,
SUM(COALESCE(Account_recharge,0)) - SUM(COALESCE(Amount_Received,0)) AS dues
FROM insert1 i1
JOIN received1 r1 ON i1.id = r1.ins_id
I would recommend union all and group by:
SELECT SUM(ir.Account_recharge) AS `Total Recharge`,
SUM(ir.Amount_Received) AS `Total Received`,
SUM(ir.Account_recharge) - SUM(ir.Amount_Received) AS dues
FROM ((SELECT Account_recharge, NULL as Amount_Received
FROM insert1 i1
) UNION ALL
(SELECT NULL as Account_recharge, Amount_Received
FROM received1 r1
)
) ir
Actually, a CROSS JOIN also works:
SELECT SUM(i.Account_recharge) AS `Total Recharge`,
SUM(r.Amount_Received) AS `Total Received`,
SUM(i.Account_recharge) - SUM(r.Amount_Received) AS dues
FROM (SELECT SUM(Account_recharge) as Account_recharge
FROM insert1 i1
) i CROSS JOIN
(SELECT SUM(Amount_Received) as Amount_Received
FROM received1 r1
) r;
The key in this case is that you need to aggregate before joining.
As I understand you don't need any kind of join.
You can sum over each column and return the 2 total columns in a subquery to subtract them:
SELECT t.`Total Recharge`, t.`Total Received`,
t.`Total Recharge` - t.`Total Received` AS dues
FROM (
SELECT
(SELECT SUM(Account_recharge) FROM insert1) AS `Total Recharge`,
(SELECT SUM(Amount_Received) FROM received1) AS `Total Received`
) AS t

Mysql query from table 2 using value from table 1

I want to search both table with all the records for cid 23 here
Total is table1-cid:23&w_id:1+2->(500+300),
Advance is table1-cid:23&w_id:1+2(100+100)+table 2-w_id:1+2(100+100+100+150)
Pending is Total-Advance
Tried using below query to display last table in pic with no luck.
SELECT E.cid, SUM(E.total) as Total, SUM(E.advance)as Advance, (SUM(E.total)-SUM(E.advance)- SUM(R.advance)) as Pending
FROM table1 AS E
LEFT JOIN table2 R ON E.w_id=R.w_id
WHERE (E.cid =23)
This is not the best query I've done but I obtain the result you want:
wwtest1 = table-1 , wwtest2 = table 2.
SELECT w1.cid AS cid,
(SELECT SUM(total) FROM wwtest WHERE cid = 23) AS total,
((SELECT SUM(advance) FROM wwtest WHERE cid = 23) + (SELECT SUM(advance) FROM wwtest2)) AS advance,
((SELECT SUM(total) FROM wwtest WHERE cid = 23) - ((SELECT SUM(advance) FROM wwtest WHERE cid = 23) + (SELECT SUM(advance) FROM wwtest2))) AS pending
FROM wwtest w1
WHERE w1.cid = 23 GROUP BY w1.cid;

In Join condition I want to use group by and having clause but get error? How to use group by and having clause

When I want to fetch data from table it_Service_ticket. The error is
Unknown column 'it_service_ticket.xetr' in 'having clause'
how to use group by and having condition? Please help me
SELECT Assignedto,COUNT(Assignedto) as TC
,CONCAT(count(case when STATUS = 'CLOSE' then 1 else null end) * 100 / count(1), '%') as SC
,CONCAT(count(case when STATUS = 'PENDING' then 1 else null end) * 100 / count(1), '%') as PC
,SUM(TIMESTAMPDIFF(MINUTE,Request_Date, Xetr))/60 as WH ,(540-sum(TIMESTAMPDIFF(MINUTE,Request_Date, Xetr)))/60 as VH,
COUNT(Feedback_Rate)/COUNT(Assignedto)*100 as Feed_Percent,
SUM(Feedback_Rate)/(count(Feedback_Rate)*5)*5 as AVG_Feedback
FROM `it_service_ticket`
INNER JOIN `it_problem`
ON `it_service_ticket`.`it_problem_id`=`it_problem`.`it_problem_id`
INNER JOIN `city_master`
ON `it_service_ticket`.cityid=`city_master`.city_id
GROUP BY Assignedto
HAVING `it_service_ticket`.`xetr` BETWEEN '2017-01-01 12:00:00 AM' AND '2017-03-31 12:00:00 PM'
;
I think you just want where, not having:
SELECT Assignedto, COUNT(Assignedto) as TC,
CONCAT(AVG(STATUS = 'CLOSE') * 100, '%') as SC,
CONCAT(AVG(STATUS = 'PENDING') * 100, '%') as PC,
SUM(TIMESTAMPDIFF(MINUTE, Request_Date, Xetr))/60 as WH ,
(540-SUM(TIMESTAMPDIFF(MINUTE, Request_Date, Xetr)))/60 as VH,
COUNT(Feedback_Rate)/COUNT(Assignedto)*100 as Feed_Percent,
SUM(Feedback_Rate)/(count(Feedback_Rate)*5)*5 as AVG_Feedback
FROM it_service_ticket st INNER JOIN
it_problem` p
ON st.it_problem_id = p.it_problem_id INNER JOIN
`city_master` cm
ON st.cityid = cm.city_id
WHERE st.xetr BETWEEN '2017-01-01 00:00:00' AND '2017-03-31 12:00:00'
GROUP BY Assignedto;
In general, only use HAVING when you are filtering on aggregation functions.
Notes:
I simplified the logic for calculating ratios. You might want to use format() to get a particular number of decimal places.
Don't use backticks if they are not necessary. They just make the query harder to write and to read.
Similarly, table aliases make the query easier to write and to read.
Use 24-hour time formats -- much less prone to mistakes.
I question whether the calculation for Feed_Percent is correct. COUNT() counts the number of non-NULL values, so they ratio is likely to be 1.
You have to add Xetr in Select field. Without using this you cannot use having condition with Xetr.
Try this
SELECT Assignedto,COUNT(Assignedto) as TC
,CONCAT(count(case when STATUS = 'CLOSE' then 1 else null end) * 100 / count(1), '%') as SC
,CONCAT(count(case when STATUS = 'PENDING' then 1 else null end) * 100 / count(1), '%') as PC
,SUM(TIMESTAMPDIFF(MINUTE,Request_Date, Xetr))/60 as WH ,(540-sum(TIMESTAMPDIFF(MINUTE,Request_Date, Xetr)))/60 as VH,
COUNT(Feedback_Rate)/COUNT(Assignedto)*100 as Feed_Percent,
SUM(Feedback_Rate)/(count(Feedback_Rate)*5)*5 as AVG_Feedback,Xetr
FROM `it_service_ticket`
INNER JOIN `it_problem`
ON `it_service_ticket`.`it_problem_id`=`it_problem`.`it_problem_id`
INNER JOIN `city_master`
ON `it_service_ticket`.cityid=`city_master`.city_id
GROUP BY Assignedto
HAVING `it_service_ticket`.`Xetr` BETWEEN '2017-01-01 12:00:00 AM' AND '2017-03-31 12:00:00 PM';
But in My View you have to use Xetr in where clause for performance as i mentioned below :
SELECT Assignedto,COUNT(Assignedto) as TC
,CONCAT(count(case when STATUS = 'CLOSE' then 1 else null end) * 100 / count(1), '%') as SC
,CONCAT(count(case when STATUS = 'PENDING' then 1 else null end) * 100 / count(1), '%') as PC
,SUM(TIMESTAMPDIFF(MINUTE,Request_Date, Xetr))/60 as WH ,(540-sum(TIMESTAMPDIFF(MINUTE,Request_Date, Xetr)))/60 as VH,
COUNT(Feedback_Rate)/COUNT(Assignedto)*100 as Feed_Percent,
SUM(Feedback_Rate)/(count(Feedback_Rate)*5)*5 as AVG_Feedback,Xetr
FROM `it_service_ticket`
INNER JOIN `it_problem`
ON `it_service_ticket`.`it_problem_id`=`it_problem`.`it_problem_id`
INNER JOIN `city_master`
ON `it_service_ticket`.cityid=`city_master`.city_id
where `it_service_ticket`.`Xetr` BETWEEN '2017-01-01 12:00:00 AM' AND '2017-03-31 12:00:00 PM'
GROUP BY Assignedto;

Combining the result of two queries to one result SQL

I'm trying t create a compare, now i'm only able to make it as multiple result (two different result).
both of the result above is from two queries.
My first result query
SELECT
customercode,
CONVERT(DATE, TransDate) transdate,
SUM(TotalReceivable) AS total
FROM
SalesOrderHeader
WHERE
CustomerCode = 'K-MDMM4'
AND TransDate BETWEEN '2016-07-25' AND '2016-07-30'
GROUP BY
CONVERT(DATE, TransDate), customercode
and my second query
SELECT
b.OutletCode AS outlet,
tanggal,
(cash + cc + dc + flash + piutang + reject + disc50 +
isnull(spesial_item,0)) total
FROM
transaksi a
LEFT JOIN
Outlet b ON a.Outlet = b.OutletCode
LEFT JOIN
area c ON b.areacode = c.areacode
WHERE
b.active = 1
AND b.OutletCode LIKE 'K-MDMM4'
AND flag = 1
AND tanggal BETWEEN '2016-07-25' AND '2016-07-30'
GROUP BY
b.OutletCode, tanggal, cash, cc, dc, flash,
piutang, reject, disc50, spesial_item, ba, mpm, tf,
ul,remarks
ORDER BY
tanggal DESC
I want this result.
customercode | transdate | total_tbl1 | total_tbl2
K-MDMM4 2016-07-25 6004050 6004050
K-MDMM4 2016-07-26 6880340 6880340
K-MDMM4 2016-07-27 5745040 5745040
K-MDMM4 2016-07-28 7424820 7424820
I can't use jsfiddle :(. I don't know why. I can't create table via queries.
From now, I have this query
SELECT
b.OutletCode AS outlet,
tanggal,
(cash + cc + dc + flash + piutang + reject + disc50 +
isnull(spesial_item, 0)) total,
SUM(d.TotalReceivable) AS total
FROM
transaksi a
LEFT JOIN
Outlet b ON a.Outlet = b.OutletCode
LEFT JOIN
area c ON b.areacode = c.areacode
LEFT JOIN
salesorderheader d ON CONVERT(DATE, a.tanggal) = CONVERT(DATE, d.transdate)
WHERE
b.active = 1
AND b.BrandCode LIKE '%%'
AND b.OutletCode LIKE '%%'
AND flag = 1
AND YEAR(tanggal) = '2016'
AND MONTH(tanggal) = '7'
AND outlet = 'K-MDMM4'
GROUP BY
OutletCode, tanggal, cash, cc, dc, flash,
piutang, reject, disc50, spesial_item, transdate, totalreceivable
ORDER BY
tanggal DESC
and the result so far from my desired result....
Combine both queries into a single join and select
SELECT tbl1.customercode,
CAST(tbl1.transdate AS DATE) AS transdate,
tbl1.total AS total_tbl1,
tbl2.total AS total_tbl2
FROM
(
-- Query 1
SELECT customercode,convert(date,TransDate) transdate,SUM(TotalReceivable) as total
FROM SalesOrderHeader
where CustomerCode = 'K-MDMM4'
and TransDate between '2016-07-25' and '2016-07-30'
group by convert(date,TransDate),customercode
) AS tbl1
INNER JOIN (
-- Query 2
select b.OutletCode as outlet,tanggal, (cash + cc + dc + flash + piutang + reject + disc50 +
isnull(spesial_item,0)) total From transaksi a
left join Outlet b on a.Outlet = b.OutletCode
left join area c on b.areacode = c.areacode
where b.active = 1 and b.OutletCode like 'K-MDMM4' and flag = 1 and tanggal
between '2016-07-25' and '2016-07-30'
group by b.OutletCode,tanggal,cash,cc,dc,flash,piutang,reject,disc50,spesial_item,ba,mpm,tf,ul,remarks
) AS tbl2 ON tbl2.outlet = tbl1.customercode AND CAST(tbl2.trnggal AS DATE) = CAST(tbl1.transdate AS DATE)
order by CAST(tbl1.transdate AS DATE) DESC;
I don't have a database installed on this PC but what you're looking for is:
SELECT val1, val2 FROM
(SELECT1_of_your_code AS table1) INNER JOIN
(SELECT2_of_your_code AS table2) ON
table1.x == table2.y

mySQL trouble building query with multiple limits

I Have this query which works with the single limit imposed at the end.
select distinct
loc.mID,
loc.city,
loc.state,
loc.zip,
loc.country,
loc.latitude,
loc.longitude,
baseInfo.firstname,
baseInfo.lastname,
baseInfo.profileimg,
baseInfo.facebookID,
(((acos(sin(('37.816876'*pi()/180)) * sin((`latitude`*pi()/180))+cos(('37.816876'*pi()/180)) * cos((`latitude`*pi()/180)) * cos((('-121.285410' - `longitude`)*pi()/180))))*180/pi())*60*1.1515) AS `distance`,
teams.teamName,
teams.leagueType,
teams.teamType,
teams.subcat
FROM memb_geo_locations loc
left join memb_friends friends on (friends.mID = loc.mID or friends.friendID = loc.mID) and (friends.mID = '100018' or friends.friendID = '100018')
join memb_baseInfo baseInfo on baseInfo.mID = loc.mID
join memb_teams teams on teams.mID = loc.mID
where
loc.primaryAddress = '1'
and ((friends.mID is null or friends.friendID is null)
or (friends.isactive = 2))
and (
teams.teamName like '%Anaheim Ducks%'
or teams.teamName like '%San Jose Sharks%'
or teams.teamName like '%New England Patriots%'
or teams.teamName like '%New York Yankees%'
or teams.teamName like '%Orlando Magic%'
)
and loc.mID != 100018
having `distance` < 50
order by baseInfo.firstname
asc limit 30
However I want my results to be limited by the teamName to 3 results max per, And I have tried stuff to the extent of
select distinct
loc.mID,
loc.city,
loc.state,
loc.zip,
loc.country,
loc.latitude,
loc.longitude,
baseInfo.firstname,
baseInfo.lastname,
baseInfo.profileimg,
baseInfo.facebookID,
(((acos(sin(('37.816876'*pi()/180)) * sin((`latitude`*pi()/180))+cos(('37.816876'*pi()/180)) * cos((`latitude`*pi()/180)) * cos((('-121.285410' - `longitude`)*pi()/180))))*180/pi())*60*1.1515) AS `distance`,
teams.teamName,
teams.leagueType,
teams.teamType,
teams.subcat
FROM memb_geo_locations loc
left join memb_friends friends on (friends.mID = loc.mID or friends.friendID = loc.mID) and (friends.mID = '100018' or friends.friendID = '100018')
join memb_baseInfo baseInfo on baseInfo.mID = loc.mID
join memb_teams teams on teams.mID = loc.mID
where
loc.primaryAddress = '1'
and ((friends.mID is null or friends.friendID is null)
or (friends.isactive = 2))
and (
(select * from memb_teams where teamName like '%Buffalo Bills%' limit 2),
(select * from memb_teams where teamName like '%San Jose Sharks%' limit 2),
(select * from memb_teams where teamName like '%New England Patriots%' limit 2)
)
and loc.mID != 100018
having `distance` < 150
order by baseInfo.firstname
asc limit 30
With no success, usually just syntax errors.. or Operand Should 1 Column(s) so I am reaching out here hopefully someone can give me some idea how to refine my query a bit so I can limit the results to 3 per teamName.. rather than having staggered results where I could have 20 of one and 4 of another 2 of another and 1 and 1 (which is not desired). 3 or less per team is desired, Just don't know how. Ideas, that don't involve tackling a huge data set from the query and looping over it via server side code to output results I desire?
IN MSSQL I use ROW_NUMBER function, and it would be something like this:
SELECT * FROM dbo.MyTable WHERE recno
IN (SELECT recno FROM (SELECT Teamname, ROW_NUMBER() OVER (PARTITION BY Teamname ORDER BY recno DESC) AS intRow FROM dbo.MyTable) AS T
WHERE intRow IN (1,2,3))
recno=your unique record number
Basically your Subquery selects the top 3 records, adding a new "ROW NUMBER" column.
The Top Query selects all the records with Rownumber between 1 to 3.
I know there is no ROW_NUMBER() native function in MYSQL, so you could use this instead:
MySQL - Get row number on select