MySQL LEFT JOIN query is very slow - mysql

SELECT bi.id,
bi.location,
bi.expense_group,
bi.level,
bi.is_active,
bi.type,
full_name,
Sum(DISTINCT bl.amount) AS
BudgetAmount,
Sum(DISTINCT Ifnull(( bl.amount * 6 ) - ( + bal1.amount + bal2.amount +
bal3.amount
+ bal4.amount + bal5.amount +
bal6.amount ), 0)) AS
Difference,
Sum(DISTINCT Ifnull(Round(( + bal1.amount + bal2.amount + bal3.amount
+ bal4.amount + bal5.amount + bal6.amount ) /
6), 0)
) AS Average,
Sum(DISTINCT bal1.amount) AS BAL1,
Sum(DISTINCT bal2.amount) AS BAL2,
Sum(DISTINCT bal3.amount) AS BAL3,
Sum(DISTINCT bal4.amount) AS BAL4,
Sum(DISTINCT bal5.amount) AS BAL5,
Sum(DISTINCT bal6.amount) AS BAL6
FROM (SELECT *
FROM budget_items
WHERE bi.location IS NOT NULL) AS bi
LEFT JOIN budget_lines AS bl
ON bi.id = bl.budget_item_id
AND bl.budget_id = 5983
LEFT JOIN balance_lines AS bal1
ON bi.id = bal1.budget_item_id
AND bal1.balance_id = 28839
LEFT JOIN balance_lines AS bal2
ON bi.id = bal2.budget_item_id
AND bal2.balance_id = 28633
LEFT JOIN balance_lines AS bal3
ON bi.id = bal3.budget_item_id
AND bal3.balance_id = 26664
LEFT JOIN balance_lines AS bal4
ON bi.id = bal4.budget_item_id
AND bal4.balance_id = 14500
LEFT JOIN balance_lines AS bal5
ON bi.id = bal5.budget_item_id
AND bal5.balance_id = 10199
LEFT JOIN balance_lines AS bal6
ON bi.id = bal6.budget_item_id
AND bal6.balance_id = 7204
GROUP BY bi.id
ORDER BY bi.position
As you can see actually there are only 3 tables, but I need to query one of them for each of the balances.
This is taking a lot of time. Where is my mistake?
After struggling with #Gordon Linoff post, I tried to fix it myself. #Gordon Linoff is that what you meant?
SELECT bi.id,
bi.location,
bi.expense_group,
bi.level,
bi.is_active,
bi.type,
full_name,
(bl.bud_amount) AS BudgetAmount,
(coalesce(( bl.bud_amount * 6 ) - (bal.bal_amount1 + bal.bal_amount2 + bal.bal_amount3 + bal.bal_amount4 + bal.bal_amount5 + bal.bal_amount6),
0)) AS Difference,
(coalesce(Round(( bal.bal_amount1 + bal.bal_amount2 + bal.bal_amount3 + bal.bal_amount4 + bal.bal_amount5 + bal.bal_amount6 ) /
6), 0)
) AS Average,
bal.bal_amount1 AS BAL1,
bal.bal_amount2 AS BAL2,
bal.bal_amount3 AS BAL3,
bal.bal_amount4 AS BAL4,
bal.bal_amount5 AS BAL5,
bal.bal_amount6 AS BAL6
FROM (SELECT *
FROM budget_items bi
WHERE bi.location IS NOT NULL
) AS bi
LEFT JOIN
(select budget_item_id, Sum(case when budget_id = 5983 then amount end) AS bud_amount
from budget_lines
group by budget_item_id
) AS bl
on bl.budget_item_id = bi.id
JOIN
(select budget_item_id,
IFNULL(Sum(case when balance_id = 28839 then amount end), 0) AS bal_amount1,
IFNULL(Sum(case when balance_id = 28633 then amount end), 0) AS bal_amount2,
IFNULL(Sum(case when balance_id = 26664 then amount end), 0) AS bal_amount3,
IFNULL(Sum(case when balance_id = 14500 then amount end), 0) AS bal_amount4,
IFNULL(Sum(case when balance_id = 10199 then amount end), 0) AS bal_amount5,
IFNULL(Sum(case when balance_id = 7204 then amount end), 0) AS bal_amount6
from balance_lines
group by budget_item_id
) AS bal
on bal.budget_item_id = bi.id
ORDER BY bi.location

Whenever you have sum(distinct . . . ) you have a problem. You are getting cartesian products on the left outer join, and your overall results will not be accurate if there are two lines that have the same amount.
I think you want to replace all those left outer join with a subquery like this:
select budget_item_id,
Sum(case when budget_id = 5983 then amount end) AS BAL,
Sum(case when budget_id = 28839 then amount end) AS BAL1,
Sum(case when budget_id = 28633 then amount end) AS BAL2,
Sum(case when budget_id = 26664 then amount end) AS BAL3,
Sum(case when budget_id = 14500 then amount end) AS BAL4,
Sum(case when budget_id = 10199 then amount end) AS BAL5,
Sum(case when budget_id = 7204 then amount end) AS BAL6
from balance_lines
group by budget_item_id
and then fix the rest of the query.
Here is an attempt to write the query. This undoubtedly has syntax errors:
SELECT bi.id,
bi.location,
bi.expense_group,
bi.level,
bi.is_active,
bi.type,
full_name,
(bl.bal) AS BudgetAmount,
(coalesce(( bl.bal * 6 ) - (bl.bal1 + bl.bal2 + bl.bal3 + bl.bal4 + bl.bal5 + bl.bal6),
0)) AS Difference,
(coalesce(Round(( bl.bal1 + bl.bal2 + bl.bal3 + bl.bal4 + bl.bal5 + bl.bal6 ) /
6), 0)
) AS Average,
bl.bal1 AS BAL1,
bl.bal2 AS BAL2,
bl.bal3 AS BAL3,
bl.bal4 AS BAL4,
bl.bal5 AS BAL5,
bl.bal6 AS BAL6
FROM (SELECT *
FROM budget_items bi
WHERE bi.location IS NOT NULL
) bi left outer join
(select budget_item_id,
Sum(case when budget_id = 5983 then amount end) AS BAL,
Sum(case when budget_id = 28839 then amount end) AS BAL1,
Sum(case when budget_id = 28633 then amount end) AS BAL2,
Sum(case when budget_id = 26664 then amount end) AS BAL3,
Sum(case when budget_id = 14500 then amount end) AS BAL4,
Sum(case when budget_id = 10199 then amount end) AS BAL5,
Sum(case when budget_id = 7204 then amount end) AS BAL6
from balance_lines
group by budget_item_id
) bal
on bal.budget_item_id = bi.id
ORDER BY bi.position
Note that I entirely removed the outer group by, assuming that bi.id is a unique key on the budget items table.

Related

Drop down parameter to restrict dataset on a column not in resultset

I have an SSRS report based upon a dataset. In the datasets query my where clause looks something like this
TM.term_grp_id in (SELECT distinct term_grp_id from ig_mrvCustomisations.dbo.vw_TerminalsByProfitCentre WHERE store_name = #STORENAME))
If I run the report without any further development, I won't be prompted for the #STORENAME value.
Instead, I manually created a parameter and tried to link it to the above value, but because I do not include the store_name value in my resultset, it seems i was unable to restrict on it.
I have created a drop down parameter in SSRS based upon the distinct values in the table above, but I am unable to tie them together.
How do I create a prompt that will restrict on #STORENAME ?
Full Query:
--DECLARE #STARTDATE DATETIME
--DECLARE #ENDDATE DATETIME
DECLARE #STORENAME NVARCHAR(800)
--SET #STARTDATE = GETDATE()-1 + '06:00:00:000'
--SET #ENDDATE = GETDATE() + '05:59:59:997'
SET #STORENAME = 'IVY'
select
(DATENAME(dw,GETDATE()-1 + '06:00:00:000')) as 'Day',
CONVERT(date,GETDATE()-1 + '06:00:00:000') as 'Date',
one.term_grp_name AS 'Terminal Group Name',
one.check_type_name AS 'Check Type Name',
(CASE WHEN LEFT(one.check_type_name,2) = 'EV' THEN 'Y' ELSE 'N' END) AS 'Event?',
LEFT(one.revenue_category_name,5) AS 'T3 Coding',
(CASE WHEN LEFT(one.revenue_category_name,2) = '71' THEN '99500'
WHEN LEFT(one.revenue_category_name,2) = '72' THEN '99550'
ELSE '99600' END) AS 'T3 Coding for comps',
LEFT(one.term_grp_name,4) AS 'Department',
(CASE WHEN LEFT(one.revenue_category_name,2) = '71' THEN 1010
WHEN LEFT(one.revenue_category_name,2) = '72' THEN 1020
WHEN LEFT(one.revenue_category_name,5) = '77700' THEN 1070
WHEN LEFT(one.revenue_category_name,5) = '77750' THEN 6165
ELSE 1090 END) as 'Account',
(CASE WHEN one.revenue_category_name = '' THEN 'Total' ELSE one.revenue_category_name END) AS 'Lookup',
LEFT(one.term_grp_name,4) + ' ' +
(CASE WHEN one.revenue_category_name = '' THEN 'Total' ELSE one.revenue_category_name END) AS 'Dept/Lookup',
one.revenue_category_name as 'Revenue Category',
sum(CONVERT(money,one.Tax)) + sum(CONVERT(money,one.NetRev)) + sum(CONVERT(money,one.Grat)) AS 'Net Tender',
sum(CONVERT(money,one.NetRev)) as 'Net Revenue',
sum(CONVERT(money,one.disc)) as 'Discount',
sum(CONVERT(money,one.gross)) as 'Gross Revenue',
(CASE WHEN LEFT(check_type_name,2) = 'EV' THEN 0 ELSE sum(CONVERT(money,one.gross)) END) as 'Gross Rev (excl Events)',
(CASE WHEN LEFT(check_type_name,2) = 'EV' THEN 0 ELSE SUM(CONVERT(MONEY,one.grat)) END) AS 'Gratuity (excl Events)',
(CASE WHEN LEFT(check_type_name,2) = 'EV' THEN 0 ELSE SUM(CONVERT(MONEY,one.tax)) END) AS 'Tax (excl Events)',
sum(CONVERT(money,one.Tax)) as 'Tax',
sum(CONVERT(money,one.Grat)) as 'Gratuity',
sum(CONVERT(money,one.SC)) as 'Service Charge',
sum(CONVERT(money,one.Tip)) as 'Tip',
sum(CONVERT(money,one.Covers)) as 'Covers',
Sum(CONVERT(decimal(30,2),one.avecover)) as 'Average Cover',
sum(CONVERT(money,one.Checks)) as 'Checks',
CONVERT(decimal(30,2),(sum(one.NetRev) / nullif(sum(one.Checks),0))) as 'Average Check'
from
(select
sum(CSD.sales_gross_amount - CSD.discount_amount) as 'NetRev',
sum(CSD.sales_gross_amount) as Gross,
sum(CSD.discount_amount) as Disc,
sum(CSD.gratuity_amount) as Grat,
sum(CSD.service_charge_amount) as SC,
sum(CSD.tip_amount) as Tip,
sum(CSD.tax_amount) as Tax,
sum(CSD.num_covers) as Covers,
(sum(CSD.sales_gross_amount - CSD.discount_amount) / nullif(sum(CSD.num_covers),0)) as 'AveCover',
0 as Checks,
'' as revenue_category_name,
TGM.term_grp_name,
CTD.check_type_name
from ig_business..Check_Sales_Detail CSD (NoLock)
join it_cfg..Terminal_Master TM (NoLock) on TM.term_id = CSD.tendered_terminal_id
join it_cfg..Term_Grp_Master TGM (NoLock) on TGM.term_grp_id = TM.term_grp_id and TGM.ent_id = 1
join ig_dimension..Check_Type_Dimension CTD (NoLock) on CTD.check_type_dim_id = CSD.check_type_dim_id
where CSD.transaction_data_id in
(select transaction_data_id
from ig_business..Check_Sales_Detail CSD (NoLock)
join it_cfg..Terminal_Master TM on TM.term_id = CSD.tendered_terminal_id
where tendered_date_time between GETDATE()-1 + '06:00:00:000' and GETDATE() + '05:59:59:997'
and TM.term_grp_id in (SELECT distinct term_grp_id from ig_mrvCustomisations.dbo.vw_TerminalsByProfitCentre WHERE store_name = #STORENAME))
and CSD.tendered_terminal_id <> 0
and CSD.void_state <> 2
group by TGM.term_grp_name, CTD.check_type_name
union all
select
sum(CRC.gross_sales_amount_tax_included - CRC.discount_amount_tax_included) as 'NetRev',
sum(CRC.gross_sales_amount_tax_included) as Gross,
sum(CRC.discount_amount_tax_included) as Disc,
0 as Grat,
0 as SC,
0 as Tip,
0 as Tax,
0 as Covers,
0 as 'AveCover',
0 as Checks,
RCD.revenue_category_name,
TGM.term_grp_name,
CTD.check_type_name
from
ig_business..Check_Revenue_Category_Detail CRC (NoLock)
join ig_dimension..Revenue_Category_Dimension RCD (NoLock) on RCD.revenue_category_dim_id = CRC.revenue_category_dim_id
left join ig_business..Check_Sales_Detail CSD (NoLock) on CRC.transaction_data_id = CSD.transaction_data_id
join it_cfg..Terminal_Master TM (NoLock) on CSD.tendered_terminal_id = TM.term_id
join it_cfg..Term_Grp_Master TGM (NoLock) on TGM.term_grp_id = TM.term_grp_id and TGM.ent_id = 1
join ig_dimension..Check_Type_Dimension CTD (NoLock) on CTD.check_type_dim_id = CSD.check_type_dim_id
where CRC.transaction_data_id in (select transaction_data_id
from ig_business..Check_Sales_Detail CSD (NoLock)
join it_cfg..Terminal_Master TM on TM.term_id = CSD.tendered_terminal_id
where tendered_date_time between GETDATE()-1 + '06:00:00:000' and GETDATE() + '05:59:59:997'
and TM.term_grp_id in (SELECT distinct term_grp_id from ig_mrvCustomisations.dbo.vw_TerminalsByProfitCentre WHERE store_name = #STORENAME))
Group By
RCD.revenue_category_name,
TGM.term_grp_name,
CTD.check_type_name
union all
select
0 as 'NetRev',
0 as Gross,
0 as Disc,
0 as Grat,
0 as SC,
0 as Tip,
0 as Tax,
0 as Covers,
0 as 'AveCover',
COUNT(distinct(CSD.check_number))as Checks,
'' as revenue_category_name,
TGM.term_grp_name,
CTD.check_type_name
from ig_business..Check_Sales_Detail CSD (NoLock)
join it_cfg..Terminal_Master TM (NoLock) on TM.term_id = CSD.tendered_terminal_id
join it_cfg..Term_Grp_Master TGM (NoLock) on TGM.term_grp_id = TM.term_grp_id and TGM.ent_id = 1
join ig_dimension..Check_Type_Dimension CTD (NoLock) on CTD.check_type_dim_id = CSD.check_type_dim_id
where transaction_data_id in (select transaction_data_id
from ig_business..Check_Sales_Detail CSD (NoLock)
join it_cfg..Terminal_Master TM on TM.term_id = CSD.tendered_terminal_id
where tendered_date_time between GETDATE()-1 + '06:00:00:000' and GETDATE() + '05:59:59:997'
and TM.term_grp_id in (SELECT distinct term_grp_id from ig_mrvCustomisations.dbo.vw_TerminalsByProfitCentre WHERE store_name = #STORENAME))
and (CSD.associated_check_number = 0 and CSD.refund_flag = 0 and void_reason_dim_id = 0)
group by TGM.term_grp_name, CTD.check_type_name
) as one
Group By one.term_grp_name,
one.revenue_category_name,
one.check_type_name
ORDER BY [Date] asc, [Terminal Group Name] asc
Update: When I remove the Declare and set from the beginning of the query I get the following error:
You have declared and specified the #STREENAME variable in your code so SSRS has not need to set it, it will always be 'IVY'
Comment out the following two lines
DECLARE #STORENAME NVARCHAR(800)
SET #STORENAME = 'IVY'
It should not work.
NOTE: Parameter names are case sensistive so the query parameter name #STORENAME should match the SSRS parmatername EXACTLY excluding the # symbol.

MySQL query that returns amount of contacts per day of week in subquery

I'm trying to come up with a query that enables me to select the amount of contacts a employee has had, per day of week.
I came up with the following, but it returns 0,0,0,0,0 for each day and each employee.
SELECT
#emp := A.id,
A.first_name,
(
SELECT
CONCAT_WS(',', mo, tu, we, th, fr)
FROM
(
SELECT
COALESCE(SUM(CASE WHEN WEEKDAY(B.contact_date) = 0 THEN 1 ELSE 0 END), 0) AS mo,
COALESCE(SUM(CASE WHEN WEEKDAY(B.contact_date) = 1 THEN 1 ELSE 0 END), 0) AS tu,
COALESCE(SUM(CASE WHEN WEEKDAY(B.contact_date) = 2 THEN 1 ELSE 0 END), 0) AS we,
COALESCE(SUM(CASE WHEN WEEKDAY(B.contact_date) = 3 THEN 1 ELSE 0 END), 0) AS th,
COALESCE(SUM(CASE WHEN WEEKDAY(B.contact_date) = 4 THEN 1 ELSE 0 END), 0) AS fr
FROM
`contacts` AS B
WHERE
B.user_id = #emp
AND
YEAR(B.contact_date) = 2018
AND
WEEK(B.contact_date) = 2
) q
) AS call_attempts
FROM
`users` AS A
WHERE
A.deactivated = 0
AND
A.type = 1
ORDER BY
A.first_name
Fiddle: http://sqlfiddle.com/#!9/4f682c/7

sql query with DISTINCT make huge performance issue

i have a query to get summary of donations
SELECT CONVERT(CHAR(2), CAST(pb.PayrollDate AS DATETIME), 101)
+ '/' + CONVERT(CHAR(4), CAST(pb.PayrollDate AS DATETIME), 120) AS Closing_Month ,
CONVERT(CHAR(6), CAST(pb.PayrollDate AS DATETIME), 112) AS Closing_Year ,
COUNT(DISTINCT Donation.Employee) + ( SELECT COUNT(*)
FROM dbo.Donation
INNER JOIN PayrollBatch pbd ON Donation.PayrollBatch = pbd.ID
WHERE CONVERT(CHAR(6), CAST(pbd.PayrollDate AS DATETIME), 112) = CONVERT(CHAR(6), CAST(pb.PayrollDate AS DATETIME), 112)
AND DonationType = 5
)AS 'Donors' ,
COUNT (DISTINCT( CASE WHEN Donation.DonationType = 1 OR Donation.DonationType = 5 THEN CharityDetails.ID
END ))AS 'Charities',
( CAST(COUNT(DISTINCT Donation.Employee) AS DECIMAL(18, 2))
/ ( SELECT SUM(NumberOfEmployees)
FROM OrganisationDetail
WHERE ID = Donation.OrganisationDetail
AND IsDeleted = 0
) ) * 100 AS 'Participation_Rate' ,
SUM(CASE WHEN Donation.DonationType = 1 OR Donation.DonationType = 5 THEN Donation.Amount
ELSE 0
END) AS 'Employee_Donations' ,
SUM(CASE WHEN Donation.DonationType = 2 THEN Donation.Amount
ELSE 0
END) AS 'Matched_Donations' ,
SUM(CASE WHEN Donation.DonationType = 1
OR Donation.DonationType = 2 OR Donation.DonationType = 5 THEN Donation.Amount
ELSE 0
END) AS 'Total_Donations'
FROM Donation
INNER JOIN OrganisationDetail AS OrganisationDetail_1 ON Donation.OrganisationDetail = OrganisationDetail_1.ID
INNER JOIN CharityProjectDetails ON Donation.CharityProjectDetails = CharityProjectDetails.ID
INNER JOIN CharityDetails ON CharityProjectDetails.CharityDetails = CharityDetails.ID
INNER JOIN PayrollBatch pb ON Donation.PayrollBatch = pb.ID
LEFT JOIN Employee ON Donation.Employee = Employee.ID
LEFT JOIN DonationIntent ON Donation.DonationIntent = DonationIntent.ID
LEFT JOIN EmployeeAddress ON Employee.ID = EmployeeAddress.Employee
LEFT JOIN dbo.PayrollBatchOther pbo ON pbo.PayrollBatch = pb.ID
GROUP BY CONVERT(CHAR(2), CAST(pb.PayrollDate AS DATETIME), 101)
+ '/' + CONVERT(CHAR(4), CAST(pb.PayrollDate AS DATETIME), 120) ,
CONVERT(CHAR(6), CAST(pb.PayrollDate AS DATETIME), 112) ,
Donation.OrganisationDetail
ORDER BY Closing_Year;
i need to get unique donors count from result set COUNT(DISTINCT e.ID) but with distinct query takes 7-9 sec to complete execution but without that it took only 1 sec how to improve that performance
Update
Here is the Paste The Plan

how to calc difference between two column with results

Could i calc for each row column Profit ?
SELECT
SUM(CASE WHEN m.billable = 0 THEN r.rate ELSE 0 END) AS Revenue, -- 33 + 34 + 456 + 52...etc = 5500
SUM(CASE WHEN m.billable = 1 AND m.optimized = 0 THEN r.rate ELSE 0 END) AS Costs,-- 33 + 4...etc = 339
5500 - 339 AS Profit -- I need to get this difference
FROM messages AS m
JOIN rates AS r ON (r.id = m.rate_id )
GROUP BY
m.client_account_id,
m.mcc,
m.mnc
I want to get
| Revenue | Costs | Profit
5500 500 5000
Move your query into a subquery, then subtract the results.
SELECT Revenue, Costs, Revenue - Costs AS Profit
FROM (
SELECT
SUM(CASE WHEN m.billable = 0 THEN r.rate ELSE 0 END) AS Revenue,
SUM(CASE WHEN m.billable = 1 AND m.optimized = 0 THEN r.rate ELSE 0 END) AS Costs
FROM YourTable) AS x
Joining your two tables, and showing the results grouped by account, it would be:
SELECT client_account_id, mmc, mnc, Revenue, Costs, Revenue - Costs AS Profit
FROM (
SELECT
m.client_account_id, m.mmc, m.mnc
SUM(CASE WHEN m.billable = 0 THEN r.rate ELSE 0 END) AS Revenue,
SUM(CASE WHEN m.billable = 1 AND m.optimized = 0 THEN r.rate ELSE 0 END) AS Costs
FROM messages AS m
JOIN rates AS r ON r.id = m.rate_id
GROUP BY m.client_account_id, m.mmc, m.mnc
) AS x
Simply put it in a sub query :
SELECT Revenue - Costs as Profit
FROM (
SELECT
SUM(CASE WHEN m.billable = 0 THEN r.rate ELSE 0 END) AS Revenue,
SUM(CASE WHEN m.billable = 1 AND m.optimized = 0 THEN r.rate ELSE 0 END) AS Costs
) as temp

Mysql - Help for optimizing query

I have this query:
SELECT bi.id,
bi.location,
bi.expense_group,
bi.level,
bi.is_active,
bi.type,
full_name,
( bl.bud_amount ) AS BudgetAmount,
( COALESCE(( ( bl.bud_amount * 3 ) - (
+ bal.bal_amount1 + bal.bal_amount2
+ bal.bal_amount3 ) ), 0) ) AS Difference,
( COALESCE(Round(( + bal.bal_amount1 + bal.bal_amount2
+ bal.bal_amount3 ) / 3), 0) ) AS Average,
bal.bal_amount1 AS BAL1,
bal.bal_amount2 AS BAL2,
bal.bal_amount3 AS BAL3
FROM (SELECT *
FROM budget_items bi
WHERE bi.location IS NOT NULL) AS bi
LEFT JOIN (SELECT budget_item_id,
Sum(CASE
WHEN budget_id = 21491 THEN amount
END) AS bud_amount
FROM budget_lines
GROUP BY budget_item_id) AS bl
ON bl.budget_item_id = bi.id
JOIN (SELECT budget_item_id,
Ifnull(Sum(CASE
WHEN balance_id = 12841 THEN amount
END), 0) AS bal_amount1,
Ifnull(Sum(CASE
WHEN balance_id = 18647 THEN amount
END), 0) AS bal_amount2,
Ifnull(Sum(CASE
WHEN balance_id = 18674 THEN amount
END), 0) AS bal_amount3
FROM balance_lines
GROUP BY budget_item_id) AS bal
ON bal.budget_item_id = bi.id
ORDER BY bi.location
It takes a lot of time. In the budget_lines and balance_lines tables I have more than 5,000,000 rows in each.
I also attach the EXPLAIN of the query, so you'll ne able to see the problem.
All ids in every table are indexed. Is there any column that if would be indexed spped up the query? Or maybe I need to change it.
*** LEFT JOIN is necessary because I need to get all the items from nudget_items, even if they don't exist in the balance/budget_line table.
Schema is: every budget has its budget_lines. Every balance has its balance_lines. The query is aimed to have ONE table to summarize the differences between a budget and several balances.
You can see a bigger image here: http://i.stack.imgur.com/dlF8V.png
EDIT:
After #Sebas answers:
For #sabes hunger, I put here the DESCRIBE:
budget_items
budget_lines
balance_lines
Maybe something like this; but without sample data, and indexes it's difficult to see
SELECT *
FROM budget_items bi
WHERE bi.location IS NOT NULL) AS bi
INNER JOIN --Added inner for clarity -changed order I just like my inner's before my outers.
(SELECT budget_item_id, Sum(CASE WHEN balance_id = 12841 THEN coalesce(amount,0) END), 0) AS bal_amount1,
Sum(CASE WHEN balance_id = 18647 THEN coalesce(amount,0) END), 0) AS bal_amount2,
Sum(CASE WHEN balance_id = 18674 THEN coalesce(amount,0) END), 0) AS bal_amount3
FROM balance_lines
WHERE balance_ID in (12841, 18647, 18674) --This way balance_IDs which aren't in this list don't even get evaluated
GROUP BY budget_item_id) AS bal
ON bal.budget_item_id = bi.id
LEFT JOIN
(SELECT budget_item_id, Sum(CASE WHEN budget_id = 21491 THEN coalesce(amount,0) END) AS bud_amount
FROM budget_lines
WHERE budget_Id = 21491 --Again since we only care about anything but budget_ID 21491, we can limit the results to JUST that
GROUP BY budget_item_id) AS bl
ON bl.budget_item_id = bi.id