SQL Keep running count, after inner Join - mysql

I am working with a local mysql server and I have two tables.
Table A:
ID | Name
1 Joe
2 Bob
3 John
Table B:
ID | DATE | Name_ID | Point
1 2010-01-01 1 1
2 2011-01-01 1 1
3 2013-01-01 1 -1
4 2010-01-01 2 -1
5 2012-01-01 2 -1
6 2013-01-01 2 -1
7 2014-01-01 2 1
For each ID in Table A, I am trying to get the
max date and
a running count of their points. (dates and points being in Table B).
Wanted Result:
Name | Latest_Date | Point_total
John NULL NULL
Joe 2013-01-01 1
Bob 2014-01-01 -2
So far I Have this Query:
SELECT DISTINCT a.Name, b.Date, SUM(b.point) OVER (PARTITION BY b.Name_ID) Point_total FROM
TableA a
LEFT OUTER JOIN TableB b
ON a.ID = b.Name_ID
INNER JOIN (
SELECT b.Name_ID, MAX(b.Date) Latest_Date
FROM TableB b GROUP BY b.Name_ID ) m
ON (m.Latest_Date = b.Date or (b.Date is NULL)) AND
(b.Name_ID = m.Name_ID OR (b.Name_ID is NULL))
ORDER BY Name_ID;
The resulting table does output the correct max date, but the running total only takes into account the point of the entry with the max date.
What am I missing here?

This just looks like aggregation:
SELECT a.Name, MAX(b.Date), SUM(b.point) as Point_total
FROM TableA a LEFT OUTER JOIN
TableB b
ON a.ID = b.Name_ID
GROUP BY a.name

That's an aggregation query:
select a.name, max(b.date) latest_date, sum(b.point) point_total
from a
left join b on b.name_id = a.id
group by a.id, a.name

SELECT A.Name, MAX(B.Date) as Max_Date, SUM(b.point) as Total_Points
FROM TableA as A
LEFT JOIN TableB as B
ON A.ID = B.Name_ID
GROUP BY A.name

Related

Question about SQL select within left join

I have a question about my SQL code. My aim is to create a table2 containing all information about people who had ever had Y >=3 based on table1.
table1
ID Y date
A 1 2020-01-01
A 2 2020-01-02
A 3 2020-01-03
A 4 2020-01-04
B 1 2020-01-01
B 2 2020-01-02
C 1 2020-01-01
C 2 2020-01-02
C 3 2020-01-03
Table2
ID Y date
A 1 2020-01-01
A 2 2020-01-02
A 3 2020-01-03
A 4 2020-01-04
C 1 2020-01-01
C 2 2020-01-02
C 3 2020-01-03
My current SQL code:
select a.ID, b.* from
(select distinct ID from table1
where Y >2) as a
left join table1 as b
on a.ID = b.ID;
It returns error 1064 saying that I have some syntax error.
Would someone kindly help me with this?
I would use exists logic here:
SELECT t1.*
FROM table1 t1
WHERE EXISTS (SELECT 1 FROM table1 t2
WHERE t2.ID = t2.ID AND t2.Y >= 3);
On MySQL 8+, we can use analytic functions:
WITH cte AS (
SELECT *, COUNT(Y >= 3) OVER (PARTITION BY ID) cnt
FROM table 1
)
SELECT ID, Y, date
FROM cte
WHERE cnt > 0;
You may use the following
select * from table1 where id in
(select id from table1 where Y >=3)
A JOIN works nicely...
SELECT DISTINCT a.*
FROM my_table a
JOIN my_table b
ON b.id = a.id
WHERE b.y >2;

Selecting Most Recent Date Relative to Another Table

Just stumped on syntax for this...
I have Two tables in mysql & I need to fetch records from Table A when following criteria are met:
1) Name in Table A matches the name in Table B
AND
2) The price for the most recent day in Table B is less than the record in Table A
So...running the query on example tables below would fetch me these two records:
03-17-2019 Bob 8
03-20-2019 John 10
Essentially, I need to evaluate each row in Table A, check the matching name in Table B that has the most recent date relative to the record under evaluation in Table A, and then determine if the price in Table A is greater than the price for the most recent matching name in Table B. After that, I need to calculate the difference between the prices. So, in the two records above, the difference would be 2 and 4
Table A
Date | Name | Price
03-08-2019 Bob 6
03-25-2019 Bob 2
03-17-2019 Bob 8
03-20-2019 John 10
Table B
Date | Name | Price
03-16-2019 Bob 4
03-28-2019 Bob 9
03-02-2019 Bob 12
03-10-2019 John 6
Thank you for the help!
Join twice the tables, once to get the min date difference and then to get the row with the min date difference:
select a.*
from tablea a
inner join tableb b on b.name = a.name
inner join (
select a.name, min(abs(datediff(b.date, a.date))) mindatediff
from tablea a inner join tableb b
on b.name = a.name
group by a.name
) g on g.name = a.name and abs(datediff(b.date, a.date)) = g.mindatediff
See the demo.
or:
select a.*
from tablea a inner join tableb b
on b.name = a.name
where abs(datediff(b.date, a.date)) = (
select min(abs(datediff(x.date, y.date)))
from tablea x inner join tableb y
where x.name = a.name and y.name = b.name
)
See the demo.
Results:
| date | name | price |
| ---------- | ---- | ----- |
| 2019-03-17 | Bob | 8 |
| 2019-03-20 | John | 10 |
In MySQL 8+, you would use window functions
select ab.*, (price - b_price)
from (select a.*, b.price as b_price,
row_number() over (partition by a.name order by datediff(b.date, a.date) as seqnum
from a join
b
on a.name = b.name and
a.date >= b.date
) ab
where seqnum = 1;

MySQL Inner join and sum two columns

I have the following tables
TABLE: appointments
ID | PRICE | PAID
48 | 100 | 180
TABLE: appointments_products
ID | APPOINTMENT_ID | PRODUCT_ID | TOTAL
10 | 48 | 1 | 30
11 | 48 | 9 | 30
12 | 48 | 6 | 30
I Would like to somehow run a MySQL query that will:
a) join the two tables, SUM the "TOTAL" of appointments_products for each appointment_id and if the "PAID" is not equal of the PRICE (from appointments table) + TOTAL (from appointments_products table) then to show it.
This is what I have done so far:
select a.*, b.appointment_id as AppId, b.total as ProdTotal
from appointments a
INNER JOIN appointments_products b ON a.id = b.appointment_id
But this query does not sum the total for each appointment_id
select a.ID,a.PRICE,a.PAID,a.id as AppId,
sum(b.total) as ProdTotal
from appointments a
INNER JOIN appointments_products b ON a.id = b.appointment_id
group by a.ID,a.PRICE,a.PAID;
Use where to check if price is equal to paid and the use group by to group with appointment_id.
select b.Appointment_Id, a.price, a.PAID, a.id, sum(b.total) AS TotalProd FROM appointments_products AS b inner join appointments as a On Appointment_Id = a.Id group by Appointment_Id, a.Price , a.PAID , a.id HAVING a.PAID != (a.Price + sum(b.Total))

MYSQL LEFT JOIN BRINGS WRONG RESULTS

I am trying to figure out why the join brings back the results it does.
Here is a simple test im working on.
I have two tables : Table1 and Table2.
table1
-------------------
id name amount
---------------------
1 | Fred | 2
3 | Fred | 3
5 | Fred | 4
2 | Hellen | 3
4 | Hellen | 3
6 | Hellen | 3
table2
-------------------
id name amount
---------------------
1 | Fred |4
2 | Hellen |3
3 | Paul |3
4 | Fridah |5
When i use the following statement
SELECT p.name,sum(p.amount) as amount FROM `table1` as p
left join table2 as c on p.name = c.name GROUP BY c.name , p.name
I get this result
---------------
name amount
---------------
Fridah | 5
Paul | 3
Fred | 12
Hellen | 9
But this is really wierd. I want the sum of amount from just table1, b ut the join gives me a sum of both tables. Why is this?
This is your query:
SELECT p.name, sum(p.amount) as amount
FROM `table1` as p left join
table2 as c
on p.name = c.name
GROUP BY c.name , p.name;
Your results suggest that the query you are running is:
SELECT p.name, sum(c.amount) as amount
-------------------^
FROM `table1` as p left join
table2 as c
on p.name = c.name
GROUP BY c.name , p.name;
If you run the correct query, you will get the results you expect.
EDIT:
The correct query would look like:
SELECT c.name, sum(p.amount) as amount
FROM table2 as c left join
table1 as p
on p.name = c.name
GROUP BY c.name;
Change the group by clause and include only p.name like GROUP BY p.name as below. See a demo fiddle here http://sqlfiddle.com/#!2/6c0e3/1
SELECT p.name,sum(p.amount) as amount
FROM `table1` as p
left join table2 as c on p.name = c.name
GROUP BY p.name
Results in
NAME AMOUNT
Fred 9
Hellen 9
EDIT:
You can calculate the sum individually and then join the derived tables in order to get the correct sum amount from both tables as below. See update fiddle Here
select X.name,X.amount,Y.amount2
from
(
select name,sum(amount) as amount
from table1
group by name
) X
left join
(
select name,sum(amount) as amount2
from table2
group by name
) Y on X.name = Y.name
Results In:
NAME AMOUNT AMOUNT2
Fred 9 4
Hellen 9 3
I have found an answer.
By adding distinct to the columns being summed, i was able to get the correct results.
have a look http://sqlfiddle.com/#!2/6c0e3/12/0
Thank you all for your help.

MySQL total sum based on previous select by date

I have a not-very-normalized MySQL table with the following values:
customer_ID | date | score | sale
As I am scoring the "purchase experience", I would like to check the total sale value for each customer based on his last score. I do not mind about previous scores, just about last one.
Let's say I have:
customer_ID | date | score | sale
a | yesterday | 3 | 10
a | today | 6 | 35
b | today | 10 | 20
c | yesterday | 4 | 5
The result for customers purchases with score > 5 should be:
num of customers | total sale values
2 | 65
Any idea of how to create such query?
Edit:
What I want to know is how much has a customer spent in purchases in total, but just on customers whose last score was bigger than 5.
SELECT COUNT(DISTINCT aa.customer_ID) `num of customers`,
SUM(aa.sale) `total sale values `
FROM table1 aa
INNER JOIN
(
SELECT a.customer_ID
FROM table1 a
INNER JOIN
(
SELECT customer_ID, max(date) max_date
FROM table1
GROUP BY customer_ID
) b ON a.customer_ID = b.customer_ID AND
a.date = b.max_date AND a.score > 5
) final ON aa.customer_ID = final.customer_ID
SQLFiddle Demo
much more simplified,
SELECT COUNT(DISTINCT c.customer_ID) `num of customers`,
SUM(c.sale) `total sale values `
FROM table1 a
INNER JOIN
(
SELECT customer_ID, max(date) max_date
FROM table1
GROUP BY customer_ID
) b ON a.customer_ID = b.customer_ID AND
a.date = b.max_date AND a.score > 5
INNER JOIN table1 c
ON a.customer_ID = c.customer_ID
SQLFiddle Demo