MYSQL wrong sum in join query - mysql

I have a query in MySQL designed with multi JOINs.
But the sum total value is different if I use a Group or just one total value.
If I run the query like below I get e.b. 3 lines with the correct calculated price (price*tax_amount).
But if I don't use Group because I want just the overall total the result is different. I guess because the query use the average tax amount instead of the correct amount for each item.
Do you have any idea how I can fix this?
Table:
contracts (contractID, some more data)
objects (objectID, contractID, price, taxID)
tax (taxID, tax_amount)
Query (works):
SELECT SUM(price*tax_amount) AS t_price
FROM contracts
JOIN objects
ON contracts.contractID = objects.contractID
JOIN tax
ON tax.taxID = objects.taxID
GROUP BY contracts.contractID
Result:
233.44 / 345.33 / 22.11
Query (Not work):
SELECT SUM(price*tax_amount) AS t_price
FROM contracts
JOIN objects
ON contracts.contractID = objects.contractID
JOIN tax
ON tax.taxID = objects.taxID
Result: 527.33

Related

sum and diffrence from two sql table according to item - laravel

I'm trying to get the result of the sum of two different tables and find difference of this table: so here are my table
Orders Table
Ship Table
Table and Query
i need to get query result according to item if no quantity then ZERO Tried using ISNULL throws null all values and not result from IFNULL. code or SQL Query Which i have used.
select orders.item,
SUM(orders.quantity) as aQuantity,
SUM(ship.quantity) AS oQuantity,
SUM(orders.quantity) - SUM(ship.quantity) AS diffrence
FROM orders,
ship
GROUP BY orders.item
required Output
Give it a try:
select a.item,IFNULL(o_quant,0) as "o_quant",IFNULL(s_quant,0) as "s_quant",(IFNULL(sum(o_quant),0) - IFNULL(sum(s_quant),0)) as "difference" from (select o.item,sum(o.quantity) "o_quant"
from orders o group by o.item) a left join (select s.item,sum(s.quantity) "s_quant"
from ships s group by s.item) b on a.item = b.item group by a.item,o_quant,s_quant;

SQL Fetch multiple result counts from same set of data using same query

I am working on product data, part of which has the below structure (let's call it product_serials):
The table is a collection of product serial numbers. The snapped field determines whether a specific product has been purchased or not via it's serial number. Am trying to query the table to get a count of both all serials and also all unpurchased serials of the same product_id, using a single SQL query. So far using COUNT(ps1.id) AND COUNT(ps2.id) ... WHERE ps2.snapped = FALSE does not seem to work, it still counts the same values for both all serials and unpurchased serials, and even exaggerates the count, so am definitely doing something wrong.
What could I be missing?
My SQL query as requested:
SELECT pd.id AS product_id, pd.description,
COUNT(pds.id) AS total, COUNT(pds2.id) AS available
FROM products pd
LEFT JOIN product_serials pds ON pds.product_id = pd.id
LEFT JOIN product_serials pds2 ON pds2.product_id = pd.id
WHERE pds2.snapped = FALSE
GROUP BY pd.id
ORDER BY pd.date_added DESC
Here you join tables (even multiplying them) and then apply a WHERE condition to both.
I suggest something like the following:
SELECT product_id, count(serial), count(unpurchased)
FROM (SELECT product_id, serial,
CASE WHEN snapped THEN NULL ELSE 1 END AS unpurchased)
GROUP BY product_id

SQL Query: How to use sub-query or AVG function to find number of days between a new entry?

I have a two tables, one called entities with these relevant columns:
id, company_id ,and integration_id. The other table is transactions with columns id, entity_id and created_at. The foreign keys linking the two tables are integration_id and entity_id.
The transactions table shows the number of transactions received from each company from the entities table.
Ultimately, I want to find date range with highest volume of transactions occurring and then from that range find the average number of days between transaction for each company.
To find the date range I used this query.
SELECT DATE_FORMAT(t.created_at, '%Y/%m/%d'), COUNT(t.id)
FROM entities e
JOIN transactions t
ON ei.id = t.entity_id
GROUP BY t.created_at;
I get this:
Date_FORMAT(t.created_at, '%Y/%m/%d') | COUNT(t.id)
+-------------------------------------+------------
2015/11/09 4
etc
From that I determine the range I want to use as 2015/11/09 to 2015/12/27
and I made this query
SELECT company_id, COUNT(t.id)
FROM entities e
INNER JOIN transactions t
ON e.integration_id = t.entity_id
WHERE tp.created_at BETWEEN '2015/11/09' AND '2015/12/27'
GROUP BY company_id;
I get this:
company_id | COUNT(t.id)
+-----------+------------
1234 17
and so on
Which gives me the total transactions made by each company over this date range. What's the best way now to query for the average number of days between transactions by company? How can I sub-query or is there a way to use the AVG function on dates in a WHERE clause?
EDIT:
playing around with the query, I'm wondering if there is a way I can
SELECT company_id, (49 / COUNT(t.id))...
49, because that is the number of days in that date range, in order to get the average number of days between transactions?
I think this might be it, does that make sense?
I think this may work:
Select z.company_id,
datediff(max(y.created_at),min(created_at))/count(y.id) as avg_days_between_orders,
max(y.created_at) as latest_order,
min(created_at) as earliest_order,
count(y.id) as orders
From
(SELECT entity_id, max(t.created_at) latest, min(t.created_at) earliest
FROM entities e, transactions t
Where e.id = t.entity_id
group by entity_id
order by COUNT(t.id) desc
limit 1) x,
transactions y,
entities z
where z.id = x.entity_id
and z.integration_id = y.entity_id
and y.created_at between x.earliest and x.latest
group by company_id;
It's tough without the data. There's a possibility that I have reference to integration_id incorrect in the subquery/join on the outer query.

Merge two rows into one

When i run the below written procedure, the returned result set which i get is like
But Actually according to the scenario, what i want is that I want a single record against the #ContractId parameter. So, I want to merge the rows which my result set returns.
PS: This image shows only few columns, there also exists some other columns which have different values.
This is My Procedure:
ALTER PROCEDURE [dbo].[sp_Tbl_Contract_SearchOne]
-- Add the parameters for the stored procedure here
#ContractID int
AS
BEGIN
select
tbl_Contract.ContractID,
KeyWinCountNumber,
ItemName,
BrandName,
CountName,
SellerName,
BuyerName,
ContractNumber,
ContractDate,
CountryFromName,
CountryToName,
TotalQty,
Vans,
UnitPrice,
Amount
from tbl_Contract
inner join tbl_CountDetail
on
tbl_CountDetail.ContractID = Tbl_Contract.ContractID
inner join tbl_Count tcount
on
tcount.CountID = tbl_CountDetail.CountID
INNER JOIN Tbl_Item
on Tbl_Contract.ItemID = Tbl_Item.ItemID
INNER JOIN Tbl_Brand
on Tbl_Contract.BrandID = Tbl_Brand.BrandID
INNER JOIN Tbl_Seller
on Tbl_Contract.SellerID = Tbl_Seller.SellerID
INNER JOIN Tbl_Buyer
on Tbl_Contract.BuyerID = Tbl_Buyer.BuyerID
INNER JOIN Tbl_CountryFrom
ON Tbl_Contract.CountryFromID=Tbl_CountryFrom.CountryFromID
INNER JOIN Tbl_CountryTo
ON Tbl_Contract.CountryToID = Tbl_CountryTo.CountryToID
inner join tbl_CostUnit
on Tbl_Contract.CostUnitID = tbl_CostUnit.CostUnitID
where Tbl_Contract.ContractID = 1
and Tbl_Contract.IsDeleted = 0 and tbl_CountDetail.IsDeleted = 0
END
It depends what you want to do with the CountName field (the only value that differs between the two) but in theory you could just put it through an aggregation using GROUP BY (If you excluded CountName) or if you wanted to include CountName then maybe PIVOT would do the job.
This falls under aggregation, quite often aggregation means doing an operation (sum, average, standard deviation) on th rows you want to compress into a single row. For example, if your data consisted off number of cookie sales per person per day:
day person sales
======================
1 Bob 5
1 Jane 8
2 Bob 2
2 Jane 10
And you wanted to see over all days what the total sales per person is, you would select person and the sum(sales) grouping by the person
select
person
sum(sales)
from salesData
group by person
Your case is somewhat less standard, in that you are trying to aggregate a filed which is character-based, or alphanumeric. This is fine, sort of, in that there are some aggregations which will work with a character-field. MIN will still work, as wil MAX - returning the first and last field respectively.
ie, doing a min over the set a,b,c will return a as it is first (Minimum ordered by string ordering rules). You seem to have some other numeric fields (Amount,UnitPrice,TotalQty) - these you can pick the correct aggregation for - I suspect SUM is most likely
So you could do this:
select
tbl_Contract.ContractID,
KeyWinCountNumber,
ItemName,
BrandName,
MIN(CountName) as FirstCountName,
SellerName,
BuyerName,
ContractNumber,
ContractDate,
CountryFromName,
CountryToName,
SUM(TotalQty) AS SumTotalQuantity,
Vans,
SUM(UnitPrice) as TotalUnitPrice,
SUM(Amount) AS TotalAmount
from tbl_Contract
[...snip...]
group by tbl_Contract.ContractID,
KeyWinCountNumber,
ItemName,
BrandName,
SellerName,
BuyerName,
ContractNumber,
ContractDate,
CountryFromName,
CountryToName,
Vans
This will now return 1 row, where FirstCountName has the value Count1 502 as this is the first (min) value from the aggregated fields.

mysql - How to fix this query?

I am really having a headache since the other day on how to fix this mysql statement to get my desired result. I also want to inform that I am new to mysql and prorgramming.
I have 4 tables CUSTOMER, CUSTOMER_ACCT_SETTING, DEBT, and PAYMENT.
Here are the 4 tables with their record so you can relate.
CUSTOMER
CUSTOMER_ACCT_SETTING
DEBT
PAYMENT
When I run this mysql statement:
SELECT C.CUSTOMER_ID, C.NAME, C.ADDRESS, C.CONTACT_NUMBER,
SUM(((CAS.INTEREST_RATE / 100) * D.AMOUNT) + D.AMOUNT) - COALESCE(SUM(P.AMOUNT), 0) AS CURRENT_BALANCE
FROM CUSTOMER C
INNER JOIN CUSTOMER_ACCT_SETTING CAS ON (C.CUSTOMER_ID = CAS.CUSTOMER_ID)
LEFT JOIN DEBT D ON (C.CUSTOMER_ID = D.CUSTOMER_ID)
LEFT JOIN PAYMENT P ON C.CUSTOMER_ID = P.CUSTOMER_ID
GROUP BY (C.CUSTOMER_ID)
ORDER BY C.NAME
The result is below:
PS: The result is ordered by name.
My question is:
1.) Why did I get a negative result on the CURRENT_BALANCE column in the first row? I am expecting the result to be around 16374.528.
My desired result is like this:
You are projecting your payments through all your debts by doing a join with both tables at the same time. So you essentially get 5 applications of your payment on customer 4 and zero applications on all the other customers. (so NULL on P.AMOUNT yields X - NULL = NULL). To see this, remove the "GROUP BY" and the "SUM" and just return your amounts paid and debited. Then if you group/sum these results manually by customer, you'll see what's going on.
To get the results you expect, you will need to use subqueries or some other mechanism like temporary tables. Something like this:
SELECT C.CUSTOMER_ID,
(SELECT SUM(P.AMOUNT) FROM PAYMENT P
WHERE P.CUSTOMER_ID = C.CUSTOMER_ID) AS TOTAL_PAID_BY_CUSTOMER
FROM CUSTOMER C
The answer to #1 is that each row in your result set has the payment attached to it. That is, for customer #1, you're getting three instances of the 8132.