MySQL Count name greater than a value - mysql

Please how can i check if a particular name is greater than a value in MySQL database. I want to do something like.
SELECT id FROM table WHERE COUNT(name = 'john') > 2
i know this does not work, but i really need to do something like this.
An Example: A student studying CS, From New York, and grad point is 4.5 wants to check into a hostel.
I have a hostel tables with fields course, state, and Grade_Point. i want to select the hostel_id where no same user with the same course > 2, state > 2 and grade_point > 2 are in the same room.

You can use the HAVING clause :
SELECT t.id FROM YourTable t
GROUP BY id
HAVING SUM(t.name = 'john') > 2
MySQL takes boolean expression as 0,1 , so SUM(t.name = 'john') will sum the number of occurences john appears for each ID , and will bring back those that appear more then twice.

Assuming that id is not unique and you want ids where 'john' appears 3 or more times:
select id
from t
where name = 'john'
group by id
having count(*) > 2;
This should be more efficient than any version that uses conditional aggregation because it reduces the size of the data before doing the aggregation.

Try this;)
SELECT id FROM table HAVING COUNT(IF(name = 'john', 1, null)) > 2

SELECT name, count(*)
FROM YourTable
where name = 'john'
GROUP BY name
HAVING count(*) > 2

Consiedr the following...
SELECT * FROM my_table ORDER BY id;
+----+------+
| Id | Name |
+----+------+
| 1 | Q |
| 2 | W |
| 3 | E |
| 4 | R |
| 5 | T |
| 6 | Y |
+----+------+
INSERT INTO my_table (name) SELECT 'Q' FROM (SELECT 1) x LEFT JOIN my_table y ON y.name = 'Q' WHERE y.id IS NULL;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
SELECT * FROM my_table ORDER BY id;
+----+------+
| Id | Name |
+----+------+
| 1 | Q |
| 2 | W |
| 3 | E |
| 4 | R |
| 5 | T |
| 6 | Y |
+----+------+
INSERT INTO my_table (name) SELECT 'Z' FROM (SELECT 1) x LEFT JOIN my_table y ON y.name = 'Z' WHERE y.id IS NULL;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0
SELECT * FROM my_table ORDER BY id;
+----+------+
| Id | Name |
+----+------+
| 1 | Q |
| 2 | W |
| 3 | E |
| 4 | R |
| 5 | T |
| 6 | Y |
| 7 | Z |
+----+------+
7 rows in set (0.00 sec)
Alternatively, you can just issue a simple INSERT on a UNIQUE column. And use the 'rows affected' as evidence of whether the name already exists.

Related

Query to get subjects of interest for all User Y where Y shares >=3 interests with a User X

These are two tables from a part of supposed Twitter like database where users can follow other users. The User.name field is unique.
mysql> select uID, name from User;
+-----+-------------------+
| uID | name |
+-----+-------------------+
| 1 | Alice |
| 2 | Bob |
| 5 | Iron Maiden |
| 4 | Judas Priest |
| 6 | Lesser Known Band |
| 3 | Metallica |
+-----+-------------------+
6 rows in set (0.00 sec)
mysql> select * from Follower;
+-----------+------------+
| subjectID | observerID |
+-----------+------------+
| 3 | 1 |
| 4 | 1 |
| 5 | 1 |
| 6 | 1 |
| 3 | 2 |
| 4 | 2 |
| 5 | 2 |
+-----------+------------+
7 rows in set (0.00 sec)
mysql> call newFollowSuggestionsForName('Bob');
+-------------------+
| name |
+-------------------+
| Lesser Known Band |
+-------------------+
1 row in set (0.00 sec)
I want to make an operation that will suggest for a user X a list of users they may be interested in following. I thought one heuristic could be to show X for all y who user y follows where X and y follow at least 3 of the same Users. Below is the SQL I came up with to do this. My question is if it could be done more efficiently or nicer in some other ways.
DELIMITER //
CREATE PROCEDURE newFollowSuggestionsForName(IN in_name CHAR(60))
BEGIN
DECLARE xuid INT;
SET xuid = (select uID from User where name=in_name);
select name
from User, (select subjectID
from follower
where observerID in (
select observerID
from Follower
where observerID<>xuid and subjectID in (select subjectID from Follower where observerID=xuid)
group by observerID
having count(*)>=3
)
) as T
where uID = T.subjectID and not exists (select * from Follower where subjectID=T.subjectID and observerID=xuid);
END //
DELIMITER ;
Consider the following refactored SQL code (untested without data) for use in stored procedure.
select u.`name`
from `User` u
inner join
(select subf.observerID, subf.subjectID
from follower subf
where subf.observerID <> xuid
) f
on u.UID = f.subjectID
inner join
(select f1.observerID
from follower f1
inner join follower f2
on f1.subjectID = f2.subjectID
and f1.observerID <> xuid
and f2.observerID = xuid
group by f1.observerID
having count(*) >= 3
) o
on f.observerID = o.observerID
I think the basic query starts as getting all "observers" who share three "subjects" with a given observer:
select f.observerid
from followers f join
followers f2
on f.subjectid = f2.subjectid and
f2.observerid = 2
group by f.observerid
having count(*) = 3;
The rest of the query is just joining in the names to fit into your paradigm of using names for references rather than ids.

Count rows until value in column changes in MySQL

I have same problem like in this question Count rows until value in column changes mysql
But although the issue was resolved I not understand this query. Because I have low reputation points I can't leave comment there and must open new question.
My example:
mysql> select * from example;
+----+-------+------+
| id | name | succ |
+----+-------+------+
| 1 | peter | 1 |
| 2 | bob | 1 |
| 3 | peter | 0 |
| 4 | peter | 0 |
| 5 | nick | 1 |
| 6 | bob | 0 |
| 7 | peter | 1 |
| 8 | bob | 0 |
| 9 | peter | 1 |
| 10 | peter | 1 |
+----+-------+------+
10 rows in set (0.00 sec)
I want to count successive true values for peter (descending id, and results must be 3), I know how to set query like this :
mysql> select count(succ)
from example
where id > (select max(id) from example where succ = 0);
+-------------+
| count(succ) |
+-------------+
| 2 |
+-------------+
1 row in set (0.00 sec)
But how to get results just for peter, and if it is possible to get results grouped by name, like this:
+--------+------+
|name | succ |
+--------+------+
| peter | 3 |
| bob | 0 |
| nick | 1 |
+--------+------+
Use variables to count consecutive successes (re-starting when seeing a failure), and join with a query which selects highest id per name (somewhat similar to McNets's answer)
SELECT a.name, a.count FROM (
SELECT e1.id, e1.name, e1.succ,
#count_success := IF (#prev_name = e1.name AND e1.succ = 1, #count_success + 1, e1.succ) AS `count`,
#prev_name := e1.name AS `prev_name`
FROM `example` e1, (SELECT #count_success :=0, #prev_name := NULL) init
ORDER BY e1.name, e1.id ) `a`
JOIN (SELECT MAX(id) AS `max` FROM `example` GROUP BY `name`) `b` ON a.id = b.max
One way to solve this is with a self join. Using an outer join you exclude the rows that have a matching row with a higher id value and succ = 0, and then count the rows with succ = 1 using SUM() and CASE.
Here's the query for your example:
select e1.name,
sum(case when e1.succ = 1 then 1 else 0 end) as succ
from example e1
left outer join example e2 on e2.id > e1.id
and e2.name = e1.name
and e2.succ = 0
where e2.id is null
group by e1.name
if you need the count of records
select name, count(succ) from example group by name
or if you need the sum of the succ of every person you can use
select name, sum(succ) from example group by name

MYSQL: How to fill null values in column with the previous entry?

I've got a program at work that exports to CSV but leaves blanks in the most irritable places. I want to view the carrier and destination on the same row and currently the carrier is 1 row above the destination like below:
I have a database that is like the following:
|Key|Carrier ||Destination|
|-------------------------|
| 1 | HULL2 || |
| 2 | || C14A102 |
| 3 | DONC1 || |
| 4 | || D15A012 |
What I want:
|Key|Carrier ||Destination|
|-------------------------|
| 1 | HULL2 || |
| 2 | HULL2 || C14A102 |
| 3 | DONC1 || |
| 4 | DONC1 || D15A012 |
Either that or insert a new column with the information from carrier column.
Sorry if this is confusing its confusing me to explain it!
James
Here is a solution, by cloning another table and then deleting it:
CREATE TABLE t1(Key_id INT PRIMARY KEY, Carrier CHAR(20), Destination CHAR(20));
INSERT INTO t1 VALUES(1, 'HULL2', ''),(2,'','C14A102'),(3,'DONC1',''),(4,'','D15A012');
CREATE TABLE t2 LIKE t1;
INSERT INTO t2 SELECT * FROM t1;
SELECT * FROM t1;
UPDATE t1 SET Carrier =
(
SELECT t2.Carrier
FROM t2
WHERE t2.Key_id < t1.Key_id AND t2.Carrier != ''
ORDER BY t2.Key_id DESC
LIMIT 1
)
WHERE Carrier = '';
SELECT * FROM t1;
DROP TABLE t2;
Output:
mysql> SELECT * FROM t1;
+--------+---------+-------------+
| Key_id | Carrier | Destination |
+--------+---------+-------------+
| 1 | HULL2 | |
| 2 | | C14A102 |
| 3 | DONC1 | |
| 4 | | D15A012 |
+--------+---------+-------------+
4 rows in set (0.00 sec)
mysql> UPDATE t1 SET Carrier =
-> (
-> SELECT t2.Carrier
-> FROM t2
-> WHERE t2.Key_id < t1.Key_id AND t2.Carrier != ''
-> ORDER BY t2.Key_id DESC
-> LIMIT 1
-> )
-> WHERE Carrier = '';
Query OK, 2 rows affected (0.00 sec)
Rows matched: 2 Changed: 2 Warnings: 0
mysql> SELECT * FROM t1;
+--------+---------+-------------+
| Key_id | Carrier | Destination |
+--------+---------+-------------+
| 1 | HULL2 | |
| 2 | HULL2 | C14A102 |
| 3 | DONC1 | |
| 4 | DONC1 | D15A012 |
+--------+---------+-------------+
4 rows in set (0.00 sec)
Assuming that the column 'key' can be trusted in this way, I would update with a self join where the join uses key = key+1, and then make sure it's only affecting even rows.
UPDATE tablename as even_row JOIN tablename as odd_row
ON even_row.Key = odd_row.Key + 1
SET even_row.Carrier = odd_row.Carrier
WHERE odd_row.Key % 2;

mysqli SUM and MAX results

hi guys im having trouble understanding how to get a MAX() and a SUM() from a Database
my database have 3 colums id - stuff - score looks like this
id-stuf-score
1-1-2
1-1-3
1-2-1
1-2-3
1-3-1
1-3-3
i need to make a
MAX(score) where stuff=1 and id = 1
MAX(score) where stuff=2 and id = 1
MAX(score) where stuff=3 and id = 1
.
.
etc
and then a
SUM(score) all the MAX(score)
i have hundred of rows and i cant think of a way to make it happens
make subquery table derivatives for each thing you need the max of, then add them all together.
SELECT SUM(a.max+b.max+c.max) as total
FROM (
(
SELECT MAX(score) as max
FROM tablename
WHERE stuff = 1 AND id = 1
) as a,
(
SELECT MAX(score) as max
FROM tablename
WHERE stuff = 2 AND id = 1
) as b,
(
SELECT MAX(score) as max
FROM tablename
WHERE stuff = 3 AND id = 1
) as c
);
Output:
_____________
| total |
+-----------+
| 12345 |
+-----------+
Try using group by to get your max scores, then sum the results.
Records in Table
I added a few more records to so the max(score) wouldn't be the same for every stuf.
mysql> select * from stuff;
+------+------+-------+
| id | stuf | score |
+------+------+-------+
| 1 | 1 | 2 |
| 1 | 1 | 3 |
| 1 | 2 | 1 |
| 1 | 2 | 3 |
| 1 | 3 | 1 |
| 1 | 3 | 3 |
| 1 | 3 | 4 |
| 1 | 3 | 1 |
| 1 | 2 | 5 |
| 1 | 2 | 1 |
+------+------+-------+
10 rows in set (0.00 sec)
Group By
mysql> select id, max(score) as max_score from stuff group by stuf;
+------+-----------+
| id | max_score |
+------+-----------+
| 1 | 3 |
| 1 | 5 |
| 1 | 4 |
+------+-----------+
3 rows in set (0.00 sec)
Sum It Up
mysql> select sum(max_score) from (select id, max(score) as max_score
from stuff group by stuf) sum_me;
+----------------+
| sum(max_score) |
+----------------+
| 12 |
+----------------+
1 row in set (0.00 sec)
One Note
Keep in mind that if you have more ids then you will need to limit your query to whichever id you are interested in or appropriately group the last query.
mysql> select id, sum(max_score) from (select id, max(score) as max_score
from stuff group by id, stuf) sum_me group by id;
you can try this
SELECT SUM(a.max) as total
FROM (
(
SELECT MAX(score) as max
FROM tablename
GROUP BY stuf, id
) as a
);

mysql select only X number of diffent Y row values

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);