mysql select only X number of diffent Y row values - mysql

I have a table that I'm selecting from in which I only want results for 2 differt column values... Here is what I mean data wise...
some_table
+----+----------+-------------+
| id | some_id | some_column |
+----+----------+-------------+
| 1 | 10 | alpha |
| 2 | 10 | alpha |
| 3 | 10 | alpha |
| 4 | 20 | alpha |
| 5 | 30 | alpha |
+----+----------+-------------+
An example of the type of query I'm running is:
SELECT * FROM some_table WHERE some_column = `alpha`;
How do I modify that select so that it only gives me results for up to 2 diffent some_id's... an example result is:
some_table
+----+----------+-------------+
| id | some_id | some_column |
+----+----------+-------------+
| 1 | 10 | alpha |
| 2 | 10 | alpha |
| 3 | 10 | alpha |
| 4 | 20 | alpha |
+----+----------+-------------+
It would not include id = 5 row because we only grab results for up to 2 different some_id's (10, 20 in this case).

Actually figured it out on my own, just needed to use a JOIN / SELECT DISTINCT combo. Here is the correct query...
SELECT * FROM some_table s1 JOIN (SELECT DISTINCT some_id FROM s1 LIMIT 2) s2 ON s1.some_id = s2.some_id;

Possibly use a subselect to get the first 2 ids, and then inner join that against your table
SELECT a.id, a.some_id, a.some_column
FROM some_table a
INNER JOIN
(
SELECT DISTINCT some_id
FROM some_table
ORDER BY some_id
LIMIT 2
) b
ON a.some_id = b.some_id

I am not sure if this is the optimal solution but it should do the trick:
SET #firstId:=(select distinct some_id from some_table limit 1) ;
SET #secondId:=(select distinct some_id from some_table limit 1,1) ;
SELECT *
FROM some_table
WHERE some_column="alpha"
AND some_id IN (#firstId, #secondId);

Related

select count only showing 1 result and the wrong one

I want to search TABLE1 and count which number_id has the most 5's in experience column.
TABLE1
+-------------+------------+
| number_id | experience |
+-------------+------------+
| 20 | 5 |
| 20 | 5 |
| 19 | 1 |
| 18 | 2 |
| 15 | 3 |
| 13 | 1 |
| 10 | 5 |
+-------------+------------+
So in this case it would be number_id=20
Then do an inner join on TABLE2 and map the number that matches the number_id in TABLE1.
TABLE2
+-------------+------------+
| id | number |
+-------------+------------+
| 20 | 000000000 |
| 29 | 012345678 |
| 19 | 123456789 |
| 18 | 223456789 |
| 15 | 345678910 |
| 13 | 123457898 |
| 10 | 545678910 |
+-------------+------------+
So the result would be:
000000000 (2 results of 5)
545678910 (1 result of 5)
So far I have:
SELECT number, experience, number_id, COUNT(*) AS SUM FROM TABLE1
INNER JOIN TABLE2 ON TABLE1.number_id = TABLE2.id
WHERE experience = '5' order by SUM LIMIT 10
But it's returning just
545678910
How can I get it to return both results and by order of number of instances of 5 in the experience column?
Thanks
This query will give you the results that you want. The subquery fetches all the number_id that have experience values of 5. The SUM(experience=5) works because MySQL uses a value of 1 for true and 0 for false. The results of the subquery are then joined to table2 to give the number field. Finally the results are ordered by the number of experience=5:
SELECT t2.number, t1.num_fives
FROM (SELECT number_id, SUM(experience = 5) AS num_fives
FROM table1
WHERE experience = 5
GROUP BY number_id) t1
JOIN table2 t2
ON t2.id = t1.number_id
ORDER BY num_fives DESC
Output:
number num_fives
000000000 2
545678910 1
SQLFiddle Demo
Add a group by clause:
SELECT number, experience, number_id, COUNT(*) AS SUM
FROM TABLE1
JOIN TABLE2 ON TABLE1.number_id = TABLE2.id
WHERE experience = '5'
GROUP BY 1, 2, 3 -- <<< Added this clause
ORDER BY SUM
LIMIT 10

Select two items with maximum number of common values

I have the following table:
+----+-----------+-----------+
| id | teacherId | studentId |
+----+-----------+-----------+
| 1 | 1 | 4 |
| 2 | 1 | 2 |
| 3 | 1 | 1 |
| 4 | 1 | 3 |
| 5 | 2 | 2 |
| 6 | 2 | 1 |
| 7 | 2 | 3 |
| 8 | 3 | 9 |
| 9 | 3 | 6 |
| 10 | 1 | 6 |
+----+-----------+-----------+
I need a query to find two teacherId's with maximum number of common studentId's.
In this case teachers with teacherIds 1,2 have common students with studentIds 2, 1, 3, which is greater than 1,3 having common students 6.
Thanks in Advance!
[Edit]: After several hours I've had the following solution:
SELECT * FROM (
SELECT r1tid, r2tid, COUNT(r2tid) AS cnt
FROM (
SELECT r1.teacherId AS r1tid, r2.teacherId AS r2tid
FROM table r1
INNER JOIN table r2 ON r1.studentId=r2.studentId AND r1.teacherId!=r2.teacherId
ORDER BY r1tid
) t
GROUP BY r1tid, r2tid
ORDER BY cnt DESC
) t GROUP BY cnt ORDER BY cnt DESC LIMIT 1;
I was sure that there must exist more short and elegant solution, but I could not find it.
You would do this with a self-join. Assuming no duplicates in the table:
select t.teacherid, t2.teacherid, count(*) as NumStudentsInCommon
from table t join
table t2
on t.studentid = t2.studentid and
t.teacherid < t2.teacherid
group by t.teacherid, t2.teacherid
order by NumStudentsInCommon desc
limit 1;
If you had duplicates, you would just replace count(*) with count(distinct studentid), but count(distinct) requires a bit more work.
select t.teacherId, t2.teacherId, sum(t.studentId) as NumStudentsInCommon
from table1 t join
table1 t2
on t.studentId = t2.studentId and
t.teacherId < t2.teacherId
group by t.teacherId, t2.teacherId
order by NumStudentsInCommon desc

I need to get the average for every 3 records in one table and update column in separate table

Table Mytable1
Id | Actual
1 ! 10020
2 | 12203
3 | 12312
4 | 12453
5 | 13211
6 | 12838
7 | 10l29
Using the following syntax:
SELECT AVG(Actual), CEIL((#rank:=#rank+1)/3) AS rank FROM mytable1 Group BY rank;
Produces the following type of result:
| AVG(Actual) | rank |
+-------------+------+
| 12835.5455 | 1 |
| 12523.1818 | 2 |
| 12343.3636 | 3 |
I would like to take AVG(Actual) column and UPDATE a second existing table Mytable2
Id | Predict |
1 | 11133
2 | 12312
3 | 13221
I would like to get the following where the Actual value matches the ID as RANK
Id | Predict | Actual
1 | 11133 | 12835.5455
2 | 12312 | 12523.1818
3 | 13221 | 12343.3636
IMPORTANT REQUIREMENT
I need to set an offset much like the following syntax:
SELECT #rank := #rank + 1 AS Id , Mytable2.Actual FROM Mytable LIMIT 3 OFFSET 4);
PLEASE NOTE THE AVERAGE NUMBER ARE MADE UP IN EXAMPLES
you can join your existing query in the UPDATE statement
UPDATE Table2 T2
JOIN (
SELECT AVG(Actual) as AverageValue,
CEIL((#rank:=#rank+1)/3) AS rank
FROM Table1, (select #rank:=0) t
Group BY rank )T1
on T2.id = T1.rank
SET Actual = T1.AverageValue

Select the lastest one of each result in MySQL

Say if I have a table similar to this but including more columns and more rows (These are the only relevant ones):
+-------+----+
| name | id |
+-------+----+
| james | 1 |
| james | 2 |
| james | 3 |
| adam | 4 |
| max | 5 |
| adam | 6 |
| max | 7 |
| adam | 8 |
+-------+----+
How could I get it so that it would only show the max(id) from each name like:
+-------+----+
| name | id |
+-------+----+
| adam | 8 |
| max | 7 |
| james | 3 |
+-------+----+
I currently just have this
"select * from table order by id desc"
but this just shows the latest ids. I only want to be able to see one of each name.
So basically show only the highest id of each name
You would use aggregation and max():
select name, max(id)
from table t
group by name
order by max(id) desc
limit 40;
EDIT:
If you need select * with the highest id, then use the not exists approach:
select *
from table t
where not exists (select 1 from table t2 where t2.name = t.name and t2.id > t.id)
order by id desc
limit 40;
The "not exists" essentially says: "Get me all rows in the table where there is no other row with the same name and a higher id". That is a round-about way of getting the maximum row.
One way to achieve this is to leverage a non-standard GROUP BY extension in MySQL
SELECT *
FROM
(
SELECT *
FROM table1
ORDER BY id DESC
) q
GROUP BY name
-- LIMIT 40
or another way is to grab a max id per name first and then join back to your table to fetch all other columns
SELECT t.*
FROM
(
SELECT MAX(id) id
FROM table1
GROUP BY name
-- LIMIT 40
) q JOIN table1 t
ON q.id = t.id
ORDER BY name;
Output:
| NAME | ID |
|-------|----|
| adam | 8 |
| james | 3 |
| max | 7 |
Here is SQLFiddle demo

Mysql Group by clause help

$construct = "SELECT * FROM mytable GROUP BY nid HAVING nid>1";
mytable:
+----+----------+
| id | nid |
+----+----------+
| 1 | null |
| 2 | 1 |
| 3 | 1 |
| 4 | 1 |
| 5 | 2 |
| 6 | 2 |
| 7 | 3 |
| 8 | 3 |
| 9 | 4 |
| 10 | 4 |
-----------------
How do i GROUP BY nid except nid=1? This is a brief example but with my code i am not getting the desired results. Is the query correct for what i am trying to accomplish?
How about this:
SELECT * FROM mytable WHERE nid != 1 ORDER BY nid
GROUP BY causes an aggregate query which you can only sensibly use with an aggregation function. For example, SELECT COUNT(*), nid GROUP BY nid would give you the counts of rows with a given nid.
Update: Not sure I'm understanding you, but how about this then:
(SELECT * FROM mytable WHERE nid = 1 UNION SELECT * FROM mytable WHERE nid != 1 GROUP BY nid) ORDER BY nid
I'm not sure it makes sense to mix aggregate and non-aggregate queries, though -- on the aggregate side you'll just end up with an indeterminate representative row of that group.
SELECT count(*), nid FROM mytable where nid <> 1 GROUP BY nid;
or
SELECT count(*), nid FROM mytable where nid != 1 GROUP BY nid;
Not sure if you are using Oracle or MySQL.
…
GROUP BY CASE nid WHEN 1 THEN -id ELSE nid END
…