JOIN, GROUP BY, SUM Issue Mysql - mysql

Assuming I have this table
tableA
ID value
1 5
1 5
3 10
2 4
2 2
1 2
tableB
ID Name
1 apple
2 carrot
3 banana
If the expected max value of apple is 10, carrot is 5, and banana is 15 the output table would be
table output
ID Name value
1 apple 12
2 carrot 6
what SQL statement I need to solve this?
what I have done so far:
SELECT a,ID, b.name , sum(a.valueSUM) AS value FROM tableA a
INNER JOIN tableB b
ON a.id = b.id
GROUP BY id
what options i need on the WHERE clause to pull this off?

The inner subquery groups them normally and then the main query is what deals with limiting the results.
SELECT * FROM
(select
b.id,
b.name as name,
SUM(a.value) as the_sum
from tableA a inner join tableB b
on a.Id = b.id
group by b.name, b.id
) y
where (name = 'apple' and the_sum >= 10) OR
(name = 'banana' and the_sum >= 15) OR
(name = 'carrot' and the_sum >= 5)
It seems your sample data has changed, please try this. I thought the ID doesnt have to follow tableA/tableB's id and the id is auto-generated as per the results.
Would be nice if you have another table that sets the threshold per name

Assuming threshold can be specified in tableB (makes sense):
SELECT a.ID, b.name, sum(a.value) AS value
FROM tableA a
INNER JOIN tableB b
ON a.id = b.id
GROUP BY a.ID, b.name, b.Threshold
HAVING sum(a.value) > b.Threshold;
Demo: http://rextester.com/ICOQF10295

SELECT TableB.id, TableB.Name, MAX(TableA.value) AS Value
FROM TableA INNER JOIN TableB ON
TableA.id = TableB.id
GROUP BY TableB.id, TableB.Name
Instead of SUM, use MAX aggregate function

This works in SQL Server
--Existing tables
create table #tableA (ID int, value int)
create table #tableB (ID int, Name varchar(30))
insert into #tableA
select 1 , 5 union all
select 1 , 5 union all
select 3 , 10 union all
select 2 , 4 union all
select 2 , 2 union all
select 1 , 2
insert into #tableB
select 1 , 'apple' union all
select 2 , 'carrot' union all
select 3 , 'banana'
--Create new temporary table #tableC
create table #tableC (ID int, MAXvalue int)
insert into #tableC
select 1 , 10 union all
select 2 , 5 union all
select 3 , 15
select c.ID,b.Name, a.value from #tableC c
inner join #tableB b on b.ID = c.ID
inner join (
select ID,SUM(value) as value from #tableA
group by ID
) a on a.ID = c.ID
where a.value >= c.MAXvalue
drop table #tableA
drop table #tableB
drop table #tableC

Related

SQL Join where column a in table 1 matches a value from 1 of 4 columns (a-d) in table 2

Goal:
Trying to join together two tables
Table structure:
t1:
name | id
t2:
id_a | id_b | id_c | id_d | favorite color
Problem:
I'm trying to find out the favorite color that corresponds to each name, where the t1.id is found in 1 of the 4 id fields in t2. The tricky part is that the non-matching values aren't null, so a coalesce doesn't work.
What I've tried:
Tried a case when statement in the join, but that seems to be creating some endless loop that is never finishing.
Trying a union, but that is creating some unexpected duplication.
Also tried a multi- on condition (like below), but that's not working:
WITH test AS (
SELECT
t1.*
, t2.*
FROM t1
LEFT JOIN t2
ON ( t1.id = t2.id_a
OR t1.id = t2.id_b
OR t1.id = t2.id_c
OR t1.id = t2.id_d
)
)
SELECT COUNT(*) FROM test
;
Here's an example dataset:
WITH names AS(
SELECT
1 as id , 'alfred' as name
UNION ALL SELECT 2, 'becca'
UNION ALL SELECT 3, 'charlie'
UNION ALL SELECT 4, 'dezi'
)
, color AS(
SELECT
1 as id_a, 6 as id_b, 9 as id_c, 7 as id_d, 'green' as fave_color
UNION ALL SELECT 1,2,6,5, 'orange'
UNION ALL SELECT 5,7,9,3, 'blue'
UNION ALL SELECT 9,4,6,8, 'black'
)
SELECT
n.id
, n.name
, c.fave_color
FROM color c
LEFT JOIN names n
ON n.id IN (c.id_a,c.id_b,c.id_c,c.id_d)
GROUP BY 1,2,3
ORDER BY 1,2
;

how to exclude first and last row if group it on particular id

I have sample table with data like this
id uniqueid values
1 6 0
2 6 1
3 6 2
4 6 0
5 6 1
I want result like this
id uniqueid values
2 6 1
3 6 2
4 6 0
I tried like this
select id,uniqueid,values
FROM t1
WHERE
id not in(SELECT concat(MAX(message_id_pk),',',min(message_id_pk)) FROM t1
where uniqueid=6)
and `uniqueid`=6
GROUP BY uniqueid
but its not working
You can achieve the desired results by doing self join, Inner query will get the the max and min ids for per group and outer query will filter out the results by using minid and maxid
select a.*
from demo a
join (
select `uniqueid`,min(id) minid, max(id) maxid
from demo
where uniqueid=6
group by `uniqueid`
) b using(`uniqueid`)
where a.id > b.minid and a.id < b.maxid /* a.id <> b.minid and a.id <> b.maxid */
Demo
Also you can do it by using 2 sub-queries with EXISTS to exclude the min and max id of each uniqueid.
Query
select `id`, `uniqueid`, `values`
from `your_table_name` t1
where exists (
select 1 from `your_table_name` t2
where t2.`uniqueid` = t1.`uniqueid`
and t2.`id` > t1.`id`
)
and exists(
select 1 from `your_table_name` t2
where t2.`uniqueid` = t1.`uniqueid`
and t2.`id` < t1.`id`
);
Here is a sql fiddle demo
Try this -
SELECT id, uniqueid, values
FROM YOUR_TABLE
WHERE id NOT IN (MIN(id), MAX(id));

Select date closest to date in another table

I have two tables, one having a entry date, and the other with an effective date. What I need to do is select the row were the entrydate is closest to the effective date. The only resource I can find is row_number() which does not seem to work in MySQL.
data
Table A Table B
id effdate id Aid entrydate
1 2015-10-19 1 1 2015-12-17
2 1 2015-12-18
3 1 2015-12-20
What I am trying to do is select
id effdate entrydate
1 2015-10-19 2015-12-17
So far I have tried using min() on entrydate, but it will just time out.
SELECT a.id, a.effdate, b.entrydate
FROM tableA a
JOIN tableB b on a.id = b.Aid
SELECT a.id, a.effdate, b.entrydate
FROM tableA a
JOIN tableB b on a.id = b.Aid
ORDER BY DATEDIFF(entrydate, effdate) ASC
-- you might want to order here by additional fields to break the ties
LIMIT 1;
If entry date is always greater than the effective date you can use the following
select a.id, a.effdate, b.entrydate from aa a, bb b
where a.id = b.aid
and b.entrydate = (select Min(bi.entrydate)
from bb bi
where bi.id = a.id
);

deleting all b,a from table mysql

I have a table with 3 fields as below
id a b
1 1 2
2 1 3
3 2 1
4 2 3
5 3 1
6 3 2
(a,b) and (b,a) both exist in this table ( a=1 and b=2 and a=2 and b=1). i need to remove all (b,a) from the above table .
Output:
id a b
1 1 2
2 1 3
4 2 3
i tried a self join like this
select v1.id, v2.id from val v1,val v2 where v1.a=v2.b and v1.b=v2.a
and found out the corresponding ids which match. But , not able to proceed after this. Pls help.
If you want to permanently delete those duplicate records, here's the DELETE statement which uses MySQL's LEAST and GREATEST built-in functions.
DELETE a
FROM tableName a
LEFT JOIN
(
SELECT LEAST(a, b) aa,
GREATEST(a,b) bb,
MIN(ID) min_ID
FROM tableName
GROUP BY aa, bb
) b ON a.ID = b.min_ID
WHERE b.min_ID IS NULL
SQLFiddle Demo
the SELECT statement
SELECT *
FROM tableName
WHERE (LEAST(a, b),GREATEST(a,b), ID)
IN
(
SELECT LEAST(a, b) aa,
GREATEST(a,b) bb,
MIN(ID) min_ID
FROM tableName
GROUP BY aa, bb
)
SQLFiddle Demo
You could do this to select the output you want.
select id, v1.a, v2.a from test v1 left join test v2 on (v1.id = v2.id and v1.a > v2.b)
where v2.id is null
If you want to only show the "half" results:
SELECT *
FROM val
WHERE a <= b ;
and if you want to delete the other half:
DELETE *
FROM val
WHERE a > b ;

including limit to select top n rows within a group by clause

I have the following 2 tables:
create table1
(
SENDER int,
RECEIVER int,
TIME time,
TYPE char(1)
);
create table2
(
ID int,
Y int,
CONTACT int,
DATE time
);
I am executing the following join query:
SELECT B.ID, A.RECEIVER AS Z, A.SENDER AS CONTACT, A.TYPE, A.TIME
FROM table1 A
JOIN table2 B ON A.RECEIVER = B.CONTACT
WHERE A.TYPE = 'A'
AND A.TIME < B.DATE
How do I modify the query to return only the top 40 results for each (ID,CONTACT) pair using GROUP BY?
I can order the data using the field table2.DATE
since i wanted top 40 results for each ID, i made ID,autoId as a primary key, here autoId is an autoincrement key. so after executing the following query:
SELECT B.ID, A.RECEIVER AS Z, A.SENDER AS CONTACT, A.TYPE, A.TIME
FROM table1 A
JOIN table2 B ON A.RECEIVER = B.CONTACT
WHERE A.TYPE = 'A'
AND A.TIME < B.DATE
i get results such that, the autoId initializes to 1 for each ID
for eg:
ID CONTACT autoId
1 2 1
1 3 2
1 11 3
1 34 4
2 5 1
2 33 2
2 56 3
since autoId is autoincrement, there is already an index on it. after this table is created, i can easily delete the results where autoId is greater than 40. and this while process runs really fast!