I have two Mysql queries:
1:
select TblC.name,
SUM(TblC.total) as Sum
from TblC
left join TblCli on TblC.id_cli = TblCli.id
group by TblCli.name asc
The result is
NAME SUM
john 1000
peter 500
Alicia 300
2:
select TblCli.name,
SUM(TblRec.total) as Pay
from TblRec
left join TblCli on TblRec.id_cli = TblCli.id
group by TblCli.name asc
The result is
NAME Pay
john 500
peter 100
There are two different tables with no direct relation
I need to join these two queries and get a result like this:
NAME SUM PAY Difference
john 1000 500 500
peter 500 100 400
Alicia 300 0 300
How can I perform that?
The following should work. Demo with your data: http://sqlfiddle.com/#!9/ba6264/6
I highly recommend you do joins by TblCli.id instead of TblCli.name
select A.name, sum , IFNULL(pay,0) as pay, (sum - IFNULL(pay,0)) Difference FROM
(select TblC.name,
SUM(TblC.total) as Sum
from TblC
left join TblCli on TblC.id_cli = TblCli.id
group by TblCli.name) A
LEFT JOIN
(select TblCli.name,
SUM(TblRec.total) as Pay
from TblRec
left join TblCli on TblRec.id_cli = TblCli.id
group by TblCli.name) B
ON A.name = B.name;
Related
I am trying to find a way to add a country code to a database call record based on a phone number column. I have a table with countries and their dialling codes called countries. I can query all records and add the country code after but I need to be able to filter and paginate the results.
I am working with a system I don't have much control over so adding new columns to tables or rewriting large blocks of code isn't really an option. This is what I have to work with.
Countries Table.
id
name
dialling_code
1
Ireland
353
2
America
1
Call Record table.
id
startdatetime
enddatetime
route_id
phonenumber
duration_seconds
1
2014-12-18 18:51:12
2014-12-18 18:52:12
23
3538700000
60
2
2014-12-18 17:41:02
2014-12-18 17:43:02
43
18700000
120
Routes table.
id
number
enabled
23
1234567890
1
43
0987654321
1
I need to get sum values of duration, total unique phone numbers all grouped by route_id, route_number but now we need to group these results by country_id so we can group callers by country. I use the mysql query below to get sum values of duration, total unique phone numbers all grouped by route_id, route_number. This query was written by another developer a long time ago.
SELECT
phone_number,
route_number,
COUNT(callrecord_id) AS total_calls,
SUM(duration_sec) AS total_duration,
callrecord_join.route_id
FROM routes
RIGHT JOIN (
SELECT
DATE(a.startdatetime) AS call_date,
a.id AS callrecord_id,
a.route_id AS route_id,
a.phonenumber AS phone_number,
a.duration_seconds as duration_sec,
b.inboundnumber AS route_number,
FROM callrecord AS a
INNER JOIN routes AS b ON a.route_id = b.id
WHERE DATE_FORMAT(a.startdatetime, '%Y-%m-%d') >= '2014-12-18'
AND DATE_FORMAT(a.startdatetime, '%Y-%m-%d') <= '2014-12-18'
AND b.isenabled = 1
) AS callrecord_join ON routes.id = callrecord_join.route_id
GROUP BY route_id, route_number
LIMIT 10 offset 0;
I have everything up to adding a country_id in the right join table so I can group by the country_id.
I know I could loop through each country using php and get the results using a where clause, something like the below but I cannot paginate these results or filter them easily.
WHERE LEFT(a.phonenumber, strlen($dialling_code)) = $dialling_code
How can I use the countries table to add a column to the join table query with the country id so I can group by route_id, route_number and country_id? Something like the table below.
id
startdatetime
enddatetime
route_id
phonenumber
duration_seconds
country_id
1
2014-12-18 18:51:12
2014-12-18 18:52:12
23
3538700000
60
1
2
2014-12-18 17:41:02
2014-12-18 17:43:02
43
18700000
120
2
The RIGHT JOIN from routes to callrecord_join serves no purpose, as you already have the INNER JOIN between routes and callrecord in the sub-query, which is on the righthand side of the join.
You can use the join you have described -
JOIN countries c ON LEFT(a.phonenumber, LENGTH(c.dialling_code)) = c.dialling_code
but it will give the same result as:
JOIN countries c ON a.phonenumber LIKE CONCAT(c.dialling_code, '%')
which should be slightly less expensive.
You should test the join to countries to make sure none of your numbers in callrecord join to multiple countries. Some international dialling codes are ambiguous, so it depends on which list of dialling codes you are using.
SELECT a.*, COUNT(*), GROUP_CONCAT(c.dialling_code)
FROM callrecord a
JOIN country c ON a.phonenumber LIKE CONCAT(c.dialling_code, '%')
GROUP BY a.id
HAVING COUNT(*) > 1;
Obviously, you will need to batch the above query if your dataset is very large.
I hope I am not grossly over-simplifying things, but from what I understand of your question the query is just:
SELECT
r.id AS route_id,
r.number AS route_number,
c.name AS country_name,
SUM(a.duration_seconds) AS total_duration,
COUNT(a.id) AS total_calls,
COUNT(DISTINCT a.phonenumber) AS unique_numbers
FROM callrecord AS a
JOIN routes AS r ON a.route_id = r.id
JOIN countries c ON a.phonenumber LIKE CONCAT(c.dialling_code, '%')
WHERE a.startdatetime >= '2014-12-18'
AND a.startdatetime < '2014-12-19'
AND r.isenabled = 1
GROUP BY r.id, r.number, c.name
LIMIT 10 offset 0;
Please note the removal of DATE_FORMAT() from the startdatetime to make these criteria sargable, assuming a suitable index is available.
i have query select of 3 tables using left joins by that i want sum of second table column value but by adding third table join we get some extra column on summing second table column value i need to avoid this
here explanation,
indents(table 1)
indent_no | indent_name | request_qty
1131 AAA 834
purchase_order(table 2)
pur_id | pur_qty | indent_no
121 34 1131
122 100 1131
123 10 1131
grn (table 3)
grn_no | grn_val | pur_id
1 34 121
2 23 121
3 21 122
my query to get sum(purchase_order.pur_qty) it should be 144 right
but i am getting 178 because the grn table contains 2 rows for pur_id(121)
pls note i can only allowed to use group by clause for indents.indent_no
only
i tried to get 144 but getting 178 ... see you can get actual result if you use group by purchase_order.pur_id and with the select of sum(purchase_order.pur_qty)/count(grn.pur_id) but i cant use group by column other than indents.indent_no
select sum(purchase_order.pur_qty) from indents
left join purchase_order on purchase_order.indent_no = indents.indent_no
left join grn on grn.pur_id = purchase_order.pur_id
group by indents.indent_no
i want the result
indent_no sum(purchase_order.pur_qty) SUM(grn_val)
1131 144 78
Try this query,
select indents.indent_no,sum(DISTINCT(purchase_order.pur_qty)),sum(grn.grn_val) from indents
left join purchase_order on purchase_order.indent_no = indents.indent_no
left join grn on grn.pur_id = purchase_order.pur_id
group by indents.indent_no
You can try below - you don't need to join with grn table as you only want to sum of purchage qty
select indents.indent_no,sum(purchase_order.pur_qty) from indents
left join purchase_order on purchase_order.indent_no = indents.indent_no
group by indents.indent_no
In case you need to join with grn table then you can do this using subquery of grn table -
You can see that grn table has multiple value of one purchase id and that's reason of duplication and you get wrong result from your current query
select indents.indent_no,sum(purchase_order.pur_qty) from indents
left join purchase_order on purchase_order.indent_no = indents.indent_no
left join (select pur_id, sum(grn_va) as gval from grn group by pur_id) as grn
on grn.pur_id = purchase_order.pur_id
group by indents.indent_no
MEMBERS_TABLE
member_id
---------------------------------------------
1
ACCOUNTS_TABLE
account_id member_id
---------------------------------------------
1 1
INVESTMENTS_TABLE
investment_id account_id
---------------------------------------------
1 1
2 1
FUNDS_TABLE
fund_id investment_id
---------------------------------------------
1 1
2 2
This is my current query:
SELECT
m.member_id,
a.account_id,
i.investment_id,
f.fund_id,
COUNT(a.account_id) AS member_accounts_total,
COUNT(i.investment_id) AS member_investments_total,
COUNT(f.fund_id) AS member_funds_total
FROM members AS m
LEFT JOIN accounts AS a ON m.member_id = a.member_id
LEFT JOIN investments AS i ON a.account_id = i.account_id
LEFT JOIN funds AS f ON f.fund_id = i.fund_id
I would like to see the following results:
member_accounts_total: 1
member_investments_total: 2
member_funds_total: 2
Instead, I am getting these results:
member_accounts_total: 2
member_investments_total: 2
member_funds_total: 2
I really don't want to write multiple queries for this.
Just need to change
COUNT(a.account_id) AS member_accounts_total,
to
COUNT( distinct a.account_id) AS member_accounts_total,
The reason you're getting 2 is because the left join on accounts to investments results in 2 records. To get a distinct count of members you need to add well... distinct.
Note you may have problems with the other totals as well (Distinct may be needed there as well in the long run...) say if a member had multiple accounts. you may get odd counts as well (if each account had the same investment... would you want to see the count only once or twice?
I have three tables that I'm working with.
AccountingLine - Holds the generic account details
Budget - Holds the budget data for each AccountingLine (Many rows per AccountingLine)
Actual - Holds the actual cost data for each AccountingLine (Many rows per AccountingLine)
I'm trying to get the results in a single query which will return ALL ROWS from the AccountingLine table, and SUM the Amounts for each AccountingLine from the Budget and Actuals table.
Using the SQL below, the SUM isn't working for the Budget or Actual data. If I remove one of the joins and one of the SUM functions then it calculates correctly for the single joined table. Very strange... anyone run across this with multiple SUM functions on three or more tables in MySQL?
SELECT A.*, SUM(B.`amount`) AS BudgetAmount, SUM(ACT.`amount`) as ActualAmount
FROM accounting_line A
LEFT JOIN budget B ON B.accounting_line_id = A.accounting_line_id
LEFT JOIN actual ACT ON ACT.accounting_line_id = A.accounting_line_id
GROUP BY A.`accounting_line_id`
By issuing the statement above, I'd expect to see the accounting_line fields, the SUM of the Budget amounts for each accounting_line and the SUM of the Actual amounts for each accounting_line.
I've searched all over and can't find an instance of multiple SUM functions. Thanks so much for any advice.
Josh
Table Data is below:
Table: AccountingLine
act_line_id department
----------------------------------
1 Sales
2 HumanResources
Table: Budget
budget_id actg_line_id amount
----------------------------------------------
1 1 3500.00
2 2 5000.00
3 2 15000.00
Table: Actual
actual_id actg_line_id amount
----------------------------------------------
1 1 1000.00
2 2 500.00
3 2 9000.00
A join repeats each matching row in the other table. So if you have 3 rows in three tables and join them together, you end up with 9 rows. If you sum, each sum from the second and third table is 3x too high.
One solution is to sum in a subquery, so that the join only finds one row:
SELECT A.*
, B.SumAmount as BudgetAmount
, ACT.SumAmount as ActualAmount
FROM accounting_line A
LEFT JOIN
(
select accounting_line_id
, sum(amount) as SumAmount
from budget
group by
accounting_line_id
) as B
ON B.accounting_line_id = A.accounting_line_id
LEFT JOIN
(
select accounting_line_id
, sum(amount) as SumAmount
from actual
group by
accounting_line_id
) as ACT
ON ACT.accounting_line_id = A.accounting_line_id
try this modified one, calculate it's totals on a subquery
SELECT a.*, b.totalBudget, c.totalActual
FROM AccountingLine a LEFT JOIN
(
SELECT actg_line_id, SUM(amount) totalBudget
FROM Budget
GROUP BY actg_line_id
) b on a.act_line_id = b.actg_line_id
LEFT JOIN
(
SELECT actg_line_id, SUM(amount) totalActual
FROM Actual
GROUP BY actg_line_id
) c on a.act_line_id = c.actg_line_id
SQLFiddle Demo
Try this
Select A.* ,SUM(B.Amount) As BudgetAmount,SUM(Act.Amount) As ActualAmount
from AccountingLine A
INNER JOIN Budget B
ON B.budget_id = A.actg_line_id
INNER JOIN Actual Act
ON Act.actual_id = A.accounting_line_id
Grounp By A.accounting_line_id
I have two tables: DATA and USERS
USERS
id sqft postal province city
==========================================================
1 1 Y7R BC Vancouver
2 2 Y7R BC Vancouver
3 1 L5B ON Toronto
and
DATA
id uid power
=======================
1 1 1000
2 2 1300
3 1 1500
uid in table DATA matches to id in table USERS
I want to be able to count the the number of distinct uid in DATA where the postal code is Y7R and sqft is 1
SELECT COUNT(id)
FROM `DATA` AS `d`
INNER JOIN `USERS` AS `u`
ON u.id=d.uid
WHERE u.postal='Y7R' AND u.sqft=1
GROUP BY u.id;
They should be distinct anyway if you have a proper schema, if so just remove the group by clause.
SELECT COUNT(DISTINCT D.UID) FROM DATA D
LEFT JOIN USERS U ON D.UID=U.ID
WHERE U.POSTAL='Y7R' AND U.SQFT=1)
In case you need distinct
You can use this solution:
SELECT COUNT(DISTINCT a.id)
FROM USERS a
JOIN DATA b ON a.id = b.uid
WHERE a.sqft = 1 AND
a.postal = 'Y7R'
Try this one:
SELECT COUNT(DISTINCT a.id)
FROM USERS a
INNER JOIN DATA b
ON a.id = b.uid
WHERE a.sqft = 1 AND
a.postal = 'Y7R'