something wrong with the result of mysql query with joins and select - mysql

Good day,
I am trying to join 3 tables for my inventory report but I am getting weird results out of it.
my query
SELECT i_inventory.xid,
count(x_transaction_details.xitem) AS occurrence,
i_inventory.xitem AS itemName,
SUM(i_items_group.or_qty) AS `openingQty`,
avg(x_transaction_details.cost) AS avg_cost,
SUM(x_transaction_details.qty) AS totalNumberSold,
SUM(i_items_group.or_qty) - SUM(x_transaction_details.qty) AS totalRemQty
FROM x_transaction_details
LEFT JOIN i_inventory ON x_transaction_details.xitem = i_inventory.xid
LEFT JOIN i_items_group ON i_inventory.xid = i_items_group.xitem
WHERE (x_transaction_details.date_at BETWEEN '2015-01-18 03:14:54' AND '2015-10-18 03:14:54')
AND i_inventory.xid = 3840
GROUP BY x_transaction_details.xitem
ORDER BY occurrence DESC
This query gives me this result:
See the openingQty column, I then tried to do a simple query to verify the result,
here's my query for checking the openingQty with joining only 2 tables i_items_group table (batches are stored) and i_inventory table (item Information are stored).
SELECT i_inventory.xid,
i_inventory.xitem,
SUM(i_items_group.or_qty) AS openingQty,
i_items_group.cost
FROM i_inventory
INNER JOIN i_items_group ON i_inventory.xid = i_items_group.xitem
WHERE i_inventory.xid = 3840
AND (i_items_group.date_at BETWEEN '2015-01-18 03:14:54' AND '2015-10-18 03:14:54')
my result was:
which is the correct data.
I also made a query on my x_transaction_details table also to verify if its correct or not.
heres my query:
select xitem, qty as qtySold from x_transaction_details where xitem = 3840
AND (date_at BETWEEN '2015-01-18 03:14:54' AND '2015-10-18 03:14:54')
result:
Which would total to: 15-quatitySold.
I'm just confused on how did I get 3269 as a result of my query where as the true openingQty should be only 467.
I guess the problem was in my query with joins, its messing up with number of transactions then it sums it up (I really dont know though).
Can you please help me identify it, and help me come up with the correct query.

This is a common problem with multiple SUM statements in a single query. Keep in mind how SQL does aggregation: first it generates a set of data that is not aggregated, then it aggregates it. Try your query without the GROUP BY or aggregate functions, and you'll be surprised what you turn up. There aren't enough of the right details in your post for me to determine where the breakdown is, but I can guess.
It looks like you have an xitem corresponding to some kind of product, then you have joined that to both transactions and items groups. Suppose a particular xitem matches with 3 transactions and 5 item groups. You'll get 15 records from that join. And when you sum it, any SUM calculations based on fields from the transaction table will be 5x higher than you expect, and any SUM calculations from the item groups table will be 3x higher than you expect. The key symptom here is the aggregate result being a multiple of the correct value, but seemingly different multiples for different rows.
There are multiple ways to address this kind of error. Some developers like to calculate one of hte aggregates in a subquery, then do the other aggregate in the main query and group by the already correct result from the subquery. Others like to write in-line queries to do the aggregate right in the expression:
SELECT xitem, (SELECT SUM(i_items_group.or_qty) FROM i_items_group WHERE i_inventory.xid = i_items_group.xitem) AS `openingQty`
, -- select more fields
Find what approach works best for you. But if you want to see the evidence for yourself, run this query with the aggregates gone and you'll see why those SUMs are doing what they are doing:
SELECT i_inventory.xid,
x_transaction_details.xitem AS occurrence,
i_inventory.xitem AS itemName,
i_items_group.or_qty,
x_transaction_details.cost,
x_transaction_details.qty,
i_items_group.or_qty - x_transaction_details.qty AS RemainingQty
FROM x_transaction_details
LEFT JOIN i_inventory ON x_transaction_details.xitem = i_inventory.xid
LEFT JOIN i_items_group ON i_inventory.xid = i_items_group.xitem
WHERE (x_transaction_details.date_at BETWEEN '2015-01-18 03:14:54' AND '2015-10-18 03:14:54')
AND i_inventory.xid = 3840
ORDER BY occurrence DESC

Related

i want to get all column of Accounts table with this query but it is giving error

select Accounts.name, Accounts.regno Accounts.model , Accounts.slacc, count (servicing.dt) as total
from Accounts l,eft
outer join servicing on Accounts.slacc = servicing.slacc
group by Accounts.slacc,Accounts.name
The error message is
Major Error 0x80040E14, Minor Error 25515
> select Accounts.name,Accounts .model , Accounts.regno, Accounts.slacc, count (servicing.dt) as total from Accounts left outer join servicing on Accounts.slacc = servicing.slacc group by Accounts.slacc,Accounts.name
In aggregate and grouping expressions, the SELECT clause can contain only
aggregates and grouping expressions. [ Select clause = Accounts,model ]
Your query has a group by clause. If you use a group by clause in the query, then every column in the select statement has to do one of two things - either it has to be part of the group by list, or it has to be an aggregate of some kind (Sum, Count, Avg, Max, etc). If you don't do this, SQL doesn't know what to do with the column. In your case Accounts.regno and Accounts.model are listed in the select, but they are not in the group by clause and they are not aggregates - hence your error.
Assume for the moment you have two account records with the same account name and slacc, but different Regno (or model). The group by clause says they have to be joined into one record for display, but you haven't told SQL how to do that. It doesn't matter if the data isn't like that, SQL looks for possible errors first.
In this case, you probably just want all the details grouped. The simplest way is just to make sure you add all the columns needed to the group by, like this
select Accounts.name, Accounts.regno, Accounts.model, Accounts.slacc, count(servicing.dt) as total
from Accounts
left outer join servicing on Accounts.slacc = servicing.slacc
group by Accounts.slacc, Accounts.name, Accounts.regno, Accounts.model
This will fix the error, but does extra grouping you don't need, and would get very cumbersome if you had a lot more columns you wanted from account, as you'd have to add them all. Another way to handle it is to use the minimum amount of columns for the group query, then join the result of that to your main query to get the other columns. This would probably look something like this
select Accounts.name, Accounts.regno, Accounts.model, Accounts.slacc, Totals.Total
from Accounts
left outer join
( Select slacc, count(dt) as total
from servicing
group by slacc
) Totals on Totals.slacc = Accounts.slacc

How do I sum [add] multiple columns from joined tables

I need to write a query that joins several tables and totals several columns in different tables & can't seem to figure out how to do it:
here are the tables:
The result I am trying to get is a result with the contract budgets for a particular budget name added: i.e. [this does not work but gives an idea]
select c.contract_budget_f1, c.contract_budget_f2, cb.budget_type_id, c.id, sum(cb.budget_f1) as bf1, sum(cb.budget_f2) as bf2
from `flow_contract` c
left join `flow_contract_budget` cb on cb.contract_id = c.id
where c.program_id = '69'
group by cb.budget_type_id
with the whole result set looking like:
[budget_type_id]
[contract_budget_f1]
[contract_budget_f2]
[bf1]
[bf2]
where it will return 3 rows with the budgets for each budget type added
How can I do this, is it even possible?
Here are links to the tables - sorry, didn't realize you couldn't click on them...
http://media.bigblockstudios.ca/stack/program-name.gif
http://media.bigblockstudios.ca/stack/contract-budget.gif
http://media.bigblockstudios.ca/stack/contracts.gif
UPDATE
I got it working like this:
select c.id, c.program_id, c.contract_budget_f1, c.contract_budget_f2, cb.budget_f1, cb.budget_f2, cb.budget_type_id, c.id,
sum(cb.budget_f1) as bf1, sum(cb.budget_f2) as bf2
from `flow_contract` c
left join `flow_contract_budget` cb on cb.contract_id = c.id
where c.program_id = '".$formfields['program_id']."'
group by cb.budget_type_id
order by cb.budget_type_id
I think what you want is:
group by cb.budget_type_id, cb.contract_id
Or the other way around. Could you make an sql fiddle?
Short Answer: subquery
Try this:
Start with a subquery.
Write a query that produces the column values that you want to sum. This is now the subquery.
Write an outter query that sums the desired columns in the inner query.
After you get it working, review it to see if you can optimize out the subquery and just have one query.

Invalid results returning from a multi-table SELECT Statement

I have a Database with the following structure:
http://i.imgur.com/DFZz3Py.png
I'm trying to run a select statement, getting information from multiple tables, however it keeps bringing me duplicate results. The statement I'm using is:
SELECT StockReceipts.StockID, StockReceipts.Quantity, StockPriceHistory.Price
FROM StockReceipts,StockPriceHistory,Receipts
WHERE (Receipts.ReceiptID = 1) AND (Receipts.OrderDate BETWEEN StockPriceHistory.DateStart AND StockPriceHistory.DateEnd)
And the results i'm getting are:
http://i.imgur.com/2ZrgYyZ.png
What I actually want is matching rows from the stockreceipts table,
but with the price for each item of stock (the price that was within the date & time of ordering - OrderDate taken from the Receipts table) as well, taken from the StockPriceHistory table. I don't understand why it's making up duplicate/incorrect rows when there are only two rows in the StockReceipts table for that receipt.
Can anyone help? Thanks
SELECT
SR.StockID,
SR.Quantity,
SPH.Price
FROM
Receipts R
JOIN StockReceipts SR
on R.ReceiptID = SR.ReceiptID
JOIN StockPriceHistory SPH
on SR.StockID = SPH.StockID
WHERE
R.ReceiptID = 1
AND R.OrderDate BETWEEN SPH.DateStart AND SPH.DateEnd
You had no JOIN conditions between the tables leaving it a Cartesian result... For every record in one, grabbed entries from all other table rows.

MySQL grouping error

I'm trying to run a query on a table to see how many unique users have a usage record in the system at a given point. I've been working with the following query, but I've yet to see a proper result.
SELECT count(distinct usageUser), divisionName
FROM records R
INNER JOIN locate L
ON L.computerID=R.usageComputerID
WHERE R.usageWhen LIKE "2012-07-08T12:%"
GROUP BY L.divisionName;
Currently the query returns 18, for each division in the joined table. Without the GROUP BY clause I get the same number of records.
EDIT:
I ran the query again, with suggestions from a comment. By removing the group by and count clause, I get this this (too big to post). This data is very poorly formatted, unfortunately it's inherited and fairly large.
It is not possible for these users to have used every lab like it's listed.
SELECT count(*) cnt, L.divisionName, R.usageUser
FROM records R
INNER JOIN locate L
ON L.computerID=R.usageComputerID
WHERE R.usageWhen LIKE "2012-07-08T12:%"
GROUP BY L.divisionName,R.usageUser;

SQL Sum Query Behaving Strangely?

I'm having an issue getting this SQL query to work properly.
I have the following query
SELECT apps.*,
SUM(IF(adtracking.appId = apps.id AND adtracking.id = transactions.adTrackingId, transactions.payoutAmount, 0)) AS 'revenue',
SUM(IF(adtracking.appId = apps.id AND adtracking.type = 'impression', 1, 0)) AS 'impressions'
FROM apps, adtracking, transactions
WHERE apps.userId = '$userId'
GROUP BY apps.id
Everything is working, HOWEVER for the 'impressions' column I am generating in the query, I am getting a WAY larger number than there should be. For example, one matching app for this query should only have 72 for 'Impressions' yet it is coming up with a value of over 3,000 when there aren't even that many rows in the adtracking table. Why is this? What is wrong here?
Your problem is you have no join conditions, so you are getting every row of every table being joined in your query result - called a cartesian product.
To fix, change your FROM clause to this:
FROM apps a
LEFT JOIN adtracking ad ON ad.appId = a.id
LEFT JOIN transactions t ON t.adTrackingId = ad.id
You haven't provided the schema for your tables, so I guessed the names of the relevant columns - you may have to adjust them. Also, your transaction table may join to adtracking - it's impossible to know from your question, so agin you have have to alter things slightly. Hopefully you get the idea.
Edit:
Note: your group-by clause is incorrect. You either need to list every column of apps (not recommended), or change your select to only select the id column from apps (recommended). Change your select to this:
SELECT apps.id,
-- rest of query the same
Otherwise you'll get weird, incorrect, results.