SELECT only one entry of multiple occurrences - mysql

Let's say I have a Table that looks like this:
id fk value
------------
1 1 'lorem'
2 1 'ipsum'
3 1 'dolor'
4 2 'sit'
5 2 'amet'
6 3 'consetetur'
7 3 'sadipscing'
Each fk can appear multiple times, and for each fk I want to select the last row (or more precise the row with the respectively highest id) – like this:
id fk value
------------
3 1 'dolor'
5 2 'amet'
7 3 'sadipscing'
I thought I could use the keyword DISTINCT here like this:
SELECT DISTINCT id, fk, value
FROM table
but I am not sure on which row DISTINCT will return and it must be the last one.
Is there anything like (pseudo)
SELECT id, fk, value
FROM table
WHERE MAX(id)
FOREACH DISTINCT(fk)
I hope I am making any sense here :)
thank you for your time

SELECT *
FROM table
WHERE id IN (SELECT MAX(id) FROM table GROUP BY fk)

Try this:
SELECT a.id, a.fk, a.value
FROM tableA a
INNER JOIN (SELECT MAX(a.id) id, a.fk FROM tableA a GROUP BY a.fk
) AS b ON a.fk = b.fk AND a.id = b.id;
OR
SELECT a.id, a.fk, a.value
FROM (SELECT a.id, a.fk, a.value FROM tableA a ORDER BY a.fk, a.id DESC) AS a
GROUP BY a.fk;

Try this:
SELECT t.* FROM
table1 t
JOIN (
SELECT MAX(id) as id
FROM table1
GROUP BY fk
) t1
ON t.id = t1.id
Inner query will give you highest id for each fk using MAX(). Then we join this inner table with your main table.

You could also do
SELECT id, fk, value FROM table GROUP BY fk HAVING id = MAX(id)
I don't have mysql here, but it works in Sybase ASE

Related

Sql query to Select one result per all matches

I got two tables
Table 1:
id|value
1|Tom
1|Lucy
2|Tom
2|Lucy
3|Tom
3|Lucy
3|Bard
Table 2:
id|value
1|Tom
1|Lucy
2|Tom
2|wrong
3|Tom
3|Lucy
Results should be id where all the values match in both tables:
1
Tried this:
select distinct a.id
from table1 a
join table2 b on a.id=b.id and a.value=b.value
results are
1
2
3
INTERSECT comes to mind. Or a FULL OUTER JOIN maybe. MySQL supports neither.
The easiest way I can think of in MySQL:
select id
from table1
group by id
having (id, group_concat(value order by value)) in
(
select id, group_concat(value order by value)
from table2
group by id
);
Demo: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=768cc8fb2d01c2b5219a4d56d127d117

Select statement with where clause subquery returning multiple rows to be checked if contained in another subquery

This is roughly what I have been trying to do and I can not seem to figure out how to get it to work.
SELECT a.name FROM tableA a, TableB b
WHERE a.key = b.key
AND (SELECT b.values FROM tableA a, TableB b
WHERE a.key = b.key
AND a.name = Prime_Key) IN
(SELECT b.values FROM tableA a, TableB b WHERE a.key = b.key)
I have two tables with a one to many relationship from tableA to tableB. I need a select that find all the values from tableB for a specific name in tableA and then finds all the names that also are associated with all the values. So the final output will be a list of names that have a link to all of the values that the given Prime_Key has.
A bit of sample data would be:
tableA:
name key
Bob 1
Alice 2
Mark 3
Jill 4
Luke 5
and tableB:
key value
1 short
1 boy
2 tall
2 girl
2 blond
3 short
3 brownhair
3 boy
3 golf
4 girl
5 golf
5 boy
5 brownhair
So if I were to replace Prim_Key with Bob, the results would be Markas he has both values short and boy. Likewise if Prim_Key was Mark there would be no return as no one else has all the values that he does
You can use subquery joins + counting matches to achieve your results:
SELECT
person_name,
sum(total_match) total_matches,
num_attributes
FROM (
SELECT
search_name,
search_value,
num_attributes,
person_name,
sum(is_match) total_match
FROM (
SELECT
search_subject.name as search_name,
search_subject.value as search_value,
search_subject.total_attributes as num_attributes,
people.name as person_name,
people.value as person_value,
IF(search_subject.value=people.value,1,0) as is_match
FROM (
SELECT
name,
value,
total_attributes
FROM tablea
JOIN tableb USING(`key`)
JOIN (
SELECT count(*) total_attributes
FROM tablea
JOIN tableb using(`key`)
WHERE name = 'Bob'
) attributes_count
WHERE name = 'Bob'
) search_subject
JOIN (
SELECT
name,
value
FROM tablea
JOIN tableb using(`key`)
) people ON ( search_subject.name <> people.name)
) x
GROUP BY search_name, search_value, person_name
) y
GROUP BY person_name
HAVING total_matches = num_attributes
Firstly, I used GROUP_CONCAT function to group values for each key into one and, at the mean time, created the pattern for like clause.
SELECT key,
GROUP_CONCAT(VALUE ORDER BY VALUE DESC SEPARATOR '%' ) AS myValues
FROM tableB
GROUP BY key;
The result would be sth like this:
key value
1 boy%short
2 blond%girl%tall
3 boy%brownhair%golf%short
4 girl
5 boy%brownhair%golf
Then create the like query to get the result. For simplicity, you can create a view using:
CREATE VIEW table_ab AS (SELECT key, GROUP_CONCAT(VALUE ORDER BY VALUE DESC SEPARATOR '%' ) AS myValues
FROM tableB
GROUP BY key);
Finally you can get the result by:
SELECT
t2.name
FROM
table_ab t1
LEFT JOIN test_a t2
ON t1.key = t2.key
WHERE t1.myvalues LIKE
(SELECT myvalues FROM table_ab WHERE key = (SELECT key FROM test_a a WHERE a.name = 'Bob')) AND t2.name != 'Bob'

How to merge two tables on ID

I have two tables, who have the exact same columns. I want to merge table b into table a and if the dataset has the same ID, I want to use the dataset of table b.
I tried something like:
SELECT *
FROM
((SELECT
*
FROM
tableA) UNION (SELECT
*
FROM
tableB)) AS temp
GROUP BY temp.ID
ORDER BY temp.ID
but that gave me a mix of both tables.
You can do this using union all along with some additional logic:
select b.*
from b
union all
select a.*
from a
where not exists (select 1 from b where b.id = a.id);

SQL Table Counting and Joining

I have Table A, Column 1.
This table has values such as:
1
2
3
3
4
4
4
5
I have Table B, Column 2.
Which lists certain values, like:
1
3
4
I need a query to Count each unique value in Table A, but ONLY if that value is present in Table B.
So with the above, the end result would be:
1 has a quantity of 1,
3 has a quantity of 2,
and 4 has a quantity of 3.
My only problem is that I do not have this ability. Any help out there?
Based on your question, something like the following should solve your problem.
select b.column1,
count(a.column2)
from tableb as b
inner join tablea as a on b.column1 = a.column2
group by b.column1
Since you wanted only records which are in both tables, I am using an inner join. Then I am just grouping by the ID found in tableb, and getting the count of rows in tablea.
Let me know if you have any problems.
For more information regarding inner join, see : http://www.w3schools.com/sql/sql_join_inner.asp, and for group by, see : http://www.w3schools.com/sql/sql_groupby.asp
I would use an INNER JOIN query with GROUP BY aggregate function
SELECT a.column1,
count(a.column1) as total
FROM tablea a
INNER JOIN tableb b
ON a.column1 = b.column2
GROUP BY a.column1
SELECT column1,COUNT(column1)
FROM table1
WHERE column1 IN
(SELECT DISTINCT column2 FROM table2)
GROUP BY column1
Try this
MsSql
Select Distinct Column1,Count(Column1) Over (Partition by Column1)
From Table1
Where Column1 IN (Select Column2 From Table2)
Fiddle Demo
MySQl
Select Column1,Count(Column1)
From Table1
Where Column1 IN (Select Column2 From Table2)
group by column1
Fiddle Demo

MySQL: find MAX(var1) but return var2 of that entry instead

I have a table (or rather a long join) with fields (id, name, prio) where I group over id
SELECT id, group_concat(name)
FROM my_table
GROUP BY id
Now I'd also like to have a column with the name of the lowest prio score. Like
SELECT id, group_concat(name), min(prio)
FROM my_table
GROUP BY id
but instead of having the minimum value of prio I'd like to see the corresponding 'name'
Any idea?
I think you can make this a sub-query and then join it to the table something like:
SELECT * FROM (
SELECT id, group_concat(name), min(prio) AS lowest
FROM my_table
GROUP BY id ) foo
JOIN my_table mt ON foo.lowest = mt.prio AND foo.id=mt.id;
You cannot do it in one select , use joined select
SELECT a.id, ..., b.name FROM my_table JOIN ( SELECT id, name FROM my_table ORDER BY prio ASC LIMIT 1 ) AS b ON b.id = a.id ...