sum function is returning wrong value - mysql

I have 3 tables
1.Franchiese
Id Name
1 Vivek
2.Purchase
Id Fran_id commission_amount
1 1 100
2 1 1
3.Fran_payment
Id Fran_id amount
1 1 50
My SQL Query is
select franchiese.id,franchiese.name,sum(fran_payment.amount) as paid,sum(purchase.commission_amount) as tot,sum(purchase.commission_amount)-sum(fran_payment.amount) as rem from franchiese left join fran_payment on franchiese.id=fran_payment.fran_id left join purchase on franchiese.id=purchase.fran_id
It's giving me
Id Name Tot Paid Rem
1 vivek 101 100 1
Expected Answer
Id Name Tot Paid Rem
1 vivek 101 50 51

I think you have two identical entries in the Fran_payment table. Your SQL statement should work as intended, and is giving you logically correct values, but I think you have unexpected data in your table.

You are joining 3 tables which have unequal number of rows. Purchase table has 2 rows, while fran_payment has only one. At the time of join, the row in fran_payment is repeated to match the number of rows in purchase. Hence the row is duplicated and sum becomes 50 + 50 = 100 and your data would look like something like this-
ID | Name | fran_payment.amount | purchase.comission_amount
1 | Vivek | 50 | 100
1 | Vivek | 50 | 1
Try something like this
Select fran_id, sum(fran_payment.amount) as paid from purchase;
This should work.
Also, you'll need to run a sub query to only fetch data for given entry. Or, normal sum function would return the sum of while column, irrespective of the ID.
Select id, sum(fran_payment.amount from fran_payment where fran_payment.fran_id = id) as paid from franchise;
I hope that works. All the best.
PS: It's franchise, not franchiese.

Related

MYSQL:Selecting SUM of a column but the column is based of another row ID

I want to have the sum of the beginning inventory of the entire year. The beginning inventory is based of the end_inventory of another month. The beginning_inventory_id contains the ID of another row which points to the end_inventory. How do I properly get the sum of the beginning_inventory of a certain year when it's based of another row's end_inventory. I have the following table
id
time_period
beginning_inventory_id
end_inventory
gross_sales
1
2020-09-01
null
1000
500
2
2020-10-01
1
2000
500
3
2020-11-01
2
3000
500
4
2020-12-01
3
4000
500
5
2021-01-01
4
5000
500
I have the following SQL query
SELECT SUM(a.gross_sales) as gross_sales, SUM(a.end_inventory) as end_inventory,
(SELECT SUM(b.end_inventory) FROM fs_summary as b WHERE a.beginning_inventory_id = b.id) as beginning_inventory
FROM fs_summary as a
WHERE YEAR(a.time_period) = 2020
Output I would like to generate is:
beginning_inventory = 6000
end_inventory = 10000
gross_sales = 2000
Instead, I am getting null on the beginning_inventory.
Any help would be great!
I am Assuming that you want to retrieve data from 1 table with self join.
SELECT SUM(a.gross_sales),SUM(a.end_inventory),SUM(b.end_inventory)
FROM fs_summary a, fs_aummary b
WHERE b.id=a.beginning_inventory_id AND YEAR(a.time_period) = 2020
using self join can help you in this situation
EDIT: You can also write this script as,
SELECT SUM(a.gross_sales),SUM(a.end_inventory),SUM(b.end_inventory)
FROM fs_summary a
INNER JOIN fs_aummary b
ON b.id=a.beginning_inventory_id
WHERE YEAR(a.time_period) = 2020
Using self-join SQL you can achieve your result instead of sub-queries.
You should specify the same table with two different names. Your query looks as below
select sum(virtual_tb.end_inventory) as 'beginning_inventory', sum(org_tb.end_inventory) as 'end_inventory', sum(org_tb.gross_sales) as 'gross_sales'
from fs_summary org_tb left join fs_aummary virtual_tb on (virtual_tb.beginning_inventory_id = org_tb.id)
where year(org_tb.time_period) = 2020;
(Approx Output)
beginning_inventory
end_inventory
gross_sales
6000
10000
2000

MySQL - Select row with column + X > column

We have a database for patients that shows the details of their various visits to our office, such as their weight during that visit. I want to generate a report that returns the visit (a row from the table) based on the difference between the date of that visit and the patient's first visit being the largest value possible but not exceeding X number of days.
That's confusing, so let me try an example. Let's say I have the following table called patient_visits:
visit_id | created | patient_id | weight
---------+---------------------+------------+-------
1 | 2006-08-08 09:00:05 | 10 | 180
2 | 2006-08-15 09:01:03 | 10 | 178
3 | 2006-08-22 09:05:43 | 10 | 177
4 | 2006-08-29 08:54:38 | 10 | 176
5 | 2006-09-05 08:57:41 | 10 | 174
6 | 2006-09-12 09:02:15 | 10 | 173
In my query, if I were wanting to run this report for "30 days", I would want to return the row where visit_id = 5, because it's 28 days into the future, and the next row is 35 days into the future, which is too much.
I've tried a variety of things, such as joining the table to itself, or creating a subquery in the WHERE clause to try to return the max value of created WHERE it is equal to or less than created + 30 days, but I seem to be at a loss at this point. As a last resort, I can just pull all of the data into a PHP array and build some logic there, but I'd really rather not.
The bigger picture is this: The database has about 5,000 patients, each with any number of office visits. I want to build the report to tell me what the average wait loss has been for all patients combined when going from their first visit to X days out (that is, X days from each individual patient's first visit, not an arbitrary X-day period). I'm hoping that if I can get the above resolved, I'll be able to work the rest out.
You can get the date of the first and next visit using query like this (Note that this doesn't has correct syntax for date comparing and it is just an schema of the query):
select
first_visits.patient_id,
first_visits.date first_date,
max(next_visit.created) next_date
from (
select patient_id, min(created) as "date"
from patient_visits
group by patient_id
) as first_visits
inner join patient_visits next_visit
on (next_visit.patient_id = first_visits.patient_id
and next_visit.created between first_visits.created and first_visits.created + 30 days)
group by first_visits.patient_id, first_visits.date
So basically you need to find start date using grouping by patient_id and then join patient_visits and find max date that is within the 30 days window.
Then you can join the result to patient_visits to get start and end weights and calculate the loss.

Perform action on selected columns depending on their name

I've got a huge table, containing three "selection"-columns and many "data"-columns.
ID Thing1 Thing2 Thing3 avgData1 avgData2 highestEtc
---- -------- -------- -------- ---------- ---------- ------------
1 1 2 2 321 654 999
2 2 1 1 123 456 11
3 2 1 1 987 789 77
4 2 1 1 765 567 11
In my queries, I'm now selecting all entries with "Thing1" = x, "Thing2" = y, "Thing3" = z (Those three columns are selection-criteria.)
The purpose of getting those lines is to perform an action on each of the following data-columns: If it starts with "avg", I want to calculate an average of the specific column on all selected entries. On another prefix I want to count which number appears the most.
Is there a way of letting the MySQL Database do all this for me? I need a SQL-Statement that calculates the averages of the columns automatically, and performs other actions too.
For example, let's say I'd select the criteria Thing1=2, Thing2=1 and Thing3=1. Is there a way of writing the statement so that it returns only ONE entry, with the calculated things?
Result
----------------- ----------------- ----
(123+987+765)/3 (456+789+567)/3 11
I heard that this should be possible, and that it is a bad method of NOT letting the database perform those actions directly. Unfortunately, I have no idea how to do it.
Try this:-
SELECT ID, AVG(avgData1) AS RESULT1, AVG(avgData2) AS RESULT2, highestEtc
FROM YOUR_TAB
WHERE Thing1 = 2
AND Thing2 = 1
AND Thing3 = 1
GROUP BY ID
HAVING COUNT(highestEtc) > 1;
Hope this helps you.

MySQL query records for continuous date range

here's my example table (room reservation system):
id available room_id
----------------------------
1 2014-02-05 4
2 2014-02-06 4
3 2014-02-07 4
4 2014-02-09 4
5 2014-02-10 4
i want to query if room with id 4 is available between 2014-02-05 and 2014-02-10.
i know i can query by using the BETWEEN operator, but the problem is that i need to consider continuous date ranges, so it should return zero records as the record for 2014-02-08 is missing.
any ideas?
thanks
Here is an idea. Count the number of rows that match and then compare these to the number of days in the period:
select room_id
from example
where available between date('2014-02-05') and date('2014-02-10')
group by room_id
having count(*) = datediff(date('2014-02-05'), date('2014-02-10')) + 1;

Get IDs based corresponding value pairs uniquely

Think of a table like this,
ID Value
100 1
100 2
101 1
101 2
102 1
103 2
104 1
Now i want to retrieve the IDs based on their corresponding value combination uniquely. (ie) 100 is having both 1 and 2 as values. 101 is also having 1 and 2. Now i don't want both 100 and 101. i want only one of them (either 100 or 101). similarly, i don't want both 102 and 104 since they both have values 1. i want only of them. Typically, my result should be as follows
ID
100
102
103
I want the IDs with corresponding value pairs uniquely.
i am using MYSQL. please help me write the query to find this.
You could try something like this:
select
min(id)
from (
select
id,
group_concat(value order by value) as values
from <table>
group by id
) r
group by values
How this works:
the subquery returns one row for each id, with an extra column that has all of the values (in sorted order, which is important for the next step)
the outer query selects the minimum id for each set of values