I have a table of all users and I have another array which has subset of that table.
Ex:table contains 1,2,3,4,5,6,7,8,9,10
my users: 2,4,6,8,10:
Ranking of my users among themselves w.r.t points and has nothing to do with 1,3,5,7,9
I currently have this table:
create table uservotes(id int, name varchar(50), vote int);
INSERT INTO uservotes VALUES
(1, 'A', 34),
(2, 'B', 80),
(3, 'bA', 30),
(4, 'C', 8),
(5, 'D', 4),
(6, 'E', 14),
(7, 'F', 304),
(8, 'AA', 42),
(9, 'Ab', 6),
(10, 'Aa', 10);
How do I get ranking among 2,4,6,8,10
Answer I am looking for:
id rank votes name
2 1 80 B
4 5 8 C
6 3 14 E
8 2 42 AA
10 4 10 Aa
I really appreciate any help.Thanks in Advance.
I suspect that this is what you want:
select uv.*, (#rank := #rank + 1) as rank
from uservotes uv cross join
(select #rank := 0) const
where uv.id in (2, 4, 6, 8, 10)
order by votes desc;
This is the standard way of calculating a rank efficiently in MySQL, along with a where clause to choose your ids.
EDIT:
Before starting, in most databases you would simply use row_number() or dense_rank() for this purpose. MySQL does not support this ANSI standard functionality.
The key is the variable #rank. The subquery const initializes this to 0. Then the query run. The where clause gets only the rows you are interested in. The order by then puts them in order by votes, with the biggest votes first. Finally, the #rank := #rank + 1 as rank both updates the #rank variable and assigns it to a column in the output.
You need to loop a sql question with an dynamic variable
something like
select * from `uservotes` where id = $someones_id
$someones_id could be an array for an example
Related
Here is a toy example:
CREATE TABLE TEST
(
ID INT,
AGG NVARCHAR(20),
GRP NVARCHAR(20)
);
INSERT INTO TEST VALUES
(1, 'AB', 'X'), (2, 'BC', 'X'), (3, 'AC', 'X'),
(4, 'EF', 'Y'), (5, 'FG', 'Y'), (6, 'DC', 'Y'),
(7, 'JI', 'Z'), (8, 'IJ', 'Z'), (9, 'JK', 'Z');
Now, I would like to do this (this is a valid code in MySQL, but not in MEMSQL):
SELECT
COUNT(*),
SUM(ID),
GROUP_CONCAT(AGG ORDER BY AGG),
GRP
FROM TEST
GROUP BY GRP
So that the output looks like this (Required Output):
3 6 AB,AC,BC X
3 15 DC,EF,FG Y
3 24 IJ,JI,JK Z
Note that the values in the third column are sorted for each row. My output looks like this (Current Wrong Output):
3 6 BC,AB,AC X
3 15 DC,EF,FG Y
3 24 IJ,JI,JK Z
Compare each row in the third column, the lists are sorted.
However, since the above query is not valid in MEMSQL, I have to remove the ORDER BY AGG part in GROUP_CONCAT which causes the third column to not be sorted.
As per the documentation of GROUP_CONCAT, the expression can also be a function, however, there is no built in function to sort. I have tried many combinations of SELECT ... ORDER BY statements in GROUP_CONCAT without success. Is this impossible to do, or am I missing something?
I think this works for my case.
SELECT
COUNT(*),
SUM(T.ID),
GROUP_CONCAT(T.AGG),
T.GRP
FROM (
SELECT
*,
RANK() OVER(PARTITION BY GRP ORDER BY AGG) AS R
FROM TEST
) T
GROUP BY T.GRP
ORDER BY T.R
It is rather convoluted, so I hope someone can suggest an improvement.
Try this:
SELECT
COUNT(*),
SUM(ID),
GROUP_CONCAT(AGG),
GRP
FROM TEST
GROUP BY GRP
ORDER BY GROUP_CONCAT(AGG)
I have a simple table
CREATE TABLE `example` (
`id` int(12) NOT NULL,
`food` varchar(250) NOT NULL
);
With the following data
INSERT INTO `example` (`id`, `food`) VALUES
(1, 'apple'),
(2, 'apple'),
(3, 'apple'),
(4, 'apple'),
(5, 'apple'),
(6, 'apple'),
(7, 'apple'),
(8, 'banana'),
(9, 'banana'),
(10, 'potato'),
(11, 'potato'),
(12, 'potato'),
(13, 'banana'),
(14, 'banana'),
(15, 'banana');
I want to get the oldest 10 rows
SELECT *
FROM example
ORDER BY id ASC
LIMIT 10
But I don't want to get more than 5 rows where food has the same value.
My current query receives 7 apple (more than I want), 2 banana, and 1 potato. In the data provided, I'd want to receive 5 apple, 2 banana, and 3 potato.
How can I accomplish this?
Update:
SQL Group BY, Top N Items for each Group is not a duplicate because it involves a different database. In particular, GROUP BY works different in sql-server than it does in MySQL
You can add a count (in reverse) for each food . . . using variables or a correlated subquery. This will use the latter:
select t.*
from (select t.*,
(select count(*) from example t2 where t2.food = t.food and t2.id >= t.id) as seqnum
from example t
) t
where seqnum <= 5
order by id desc
limit 10;
I didn't create the table and test this, but it should give you what you want. Just a different approach than the one above.
Select *
From (Select ID, Food
, Count(Food) Over(Partition By Food Order by ID) as Appearances
From Your_Table) as a
Where a.Appearances <= 5
Order By ID Asc
You can obviously put the limit if you want.
i have a schema look like this:
CREATE TABLE users
(
id int auto_increment primary key,
name varchar(20),
point int(255)
);
INSERT INTO users
(name, point)
VALUES
('Jack', 1),
('Rick', 5),
('Danny', 11),
('Anthony', 24),
('Barla', 3),
('James', 15),
('Melvin', 12),
('Orthon', 5),
('Kenny', 2),
('Smith', 30),
('Steven', 27),
('Darly', 45),
('Peter', 44),
('Parker', 66),
('Lola', 78),
('Jennifer', 94),
('Smart', 87),
('Jin', 64),
('David', 31),
('Jill', 78),
('Ken', 48),
('Martin', 19),
('Adrian', 20),
('Oliver', 16),
('Ben', 100);
and my sql is:
select id, name, point from users Order by point desc, rand() LIMIT 5
problem is, my query does not select 5 row randomly and order them by point. Any idea, how to solve it? here is sqlfiddle:
http://sqlfiddle.com/#!2/18f15/1
select id,name,point from
(select id, name, point from users Order by rand()
LIMIT 5) abc
order by point desc;
SQLFIDDLE
problem is, my query does not select 5 row randomly and order them by point.
It's because in your given Query you are using ORDER BY clause.
select id, name, point from users Order by point desc, rand() LIMIT 5
Try with removing point desc, in ORDER BY clause
select id, name, point from users Order by rand() LIMIT 5
SQL FIDDLE
Edit
select id,name,pont from
(select id, name, point from users Order by rand() LIMIT 5)temp
order by point desc
Note: There should be no Table with name temp in you DB (i.e. since you are using it in you alias)
I have a table of things. Here is a simplified structure:
CREATE TABLE `things` (
`thing_id` int(11) NOT NULL AUTO_INCREMENT,
`thing_group` int(11) NOT NULL,
`thing_status` int(1) NOT NULL DEFAULT '0'
);
There are 2 types of things. Primary, which would have thing_id = thing_group and secondary, which would having a unqiue thing_id but the same thing_group as the primary item.
INSERT INTO `things` (`thing_id`, `thing_group`, `thing_status`) VALUES
(1, 1, 0),
(2, 1, 1),
(3, 3, 1),
(4, 3, 0),
(5, 5, 1),
(6, 5, 1),
(7, 7, 0),
(8, 7, 0),
(9, 9, 1),
(10, 9, 1),
I have thousands of these pairs.
thing_status can be 0 for either the primary or the secondary (or both), but I want to select ONLY a pair (at random) that has thing_status = 1 both for primary and secondary thing.
So from the sample data I provided, it should only return pairs which are either thing_id 5 and 6, or 9 and 10 (at random)
Hard part:
Some things can just have the primary thing only, and no secondary. The query should still return those and treat them equally to things that come in pairs.
Am i better off doing 2 queries or a convoluted single query?
Group your rows by thing_group and select those where the number of rows is the same as the sum of thing_status. Join the resulting set back to the original table on thing_group to obtain the actual rows corresponding to the groups. So:
SELECT
t.thing_id,
t.thing_group
FROM things t
INNER JOIN (
SELECT thing_group
FROM things
GROUP BY thing_group
HAVING COUNT(*) = SUM(thing_status)
ORDER BY RAND()
LIMIT 1
) g ON t.thing_group = g.thing_group
Not so hard, maybe the random part is a bit more tricky:
select *
from things
where
thing_group = (select thing_group
from things
where thing_status = 1
group by thing_group
having count(thing_id) = 2
limit 1)
limit 1
My intuition says that you should use 2 queries with a UNION ALL. But... with MySQL it's not always clear what works and what doesn't.
I believe that this query does what you want though:
SELECT t1.thing_id, t1.group_id
FROM things t1
LEFT JOIN things t2
ON t2.thing_id = t2.thing_group
AND t1.thing_id != t2.thing_id
WHERE (
t1.thing_id = t1.thing_group
AND t2.thing_id IS NULL
) OR (
t1.thing_group = t2.thing_id
AND t1.thing_id != t1.thing_group
)
GROUP BY t1.thing_id, t1.group_id
For this (pseudo code) example I have two tables in MySQL:
member { id, name }
names { name }
There are 100 members in member and 10 names. I want to use a random name from names to update the member table. So far I've got this, but, not sure if there is a better method to achieve it.
UPDATE member SET name = (SELECT name FROM names ORDER BY RAND() LIMIT 1);
The code will be executed from a script so I'm looking to avoid functions etc.
Thanks in advance.
You could avoid ordering by rand() by adding id column to your names table and using:
UPDATE member SET name = (SELECT name FROM names WHERE id=floor(1 + rand()*10 ) );
With only 10 names the result won't be much faster, but you would see the difference if you wanted to choose from a bigger set of names as sorting by rand() starts being inefficient quite fast and you do it for every row in members.
Update:
Seems like rand() inside where gives unpredictable results.
Use this one instead:
UPDATE member m1
JOIN ( select id, floor(1+rand()*10) as rnd from member ) m2 on m1.id=m2.id
JOIN names n on n.id = m2.rnd
SET m1.name=n.name
Number of rows affected may vary, if random name matches the one already in the table it doesnt count as update.
Tried to improve piotrm's solution. Seems it works;-)
CREATE TABLE member (
id INT(11) NOT NULL AUTO_INCREMENT,
name VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (id)
);
CREATE TABLE names (
id INT(11) NOT NULL AUTO_INCREMENT,
name VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (id)
);
INSERT INTO member VALUES
(1, NULL),
(2, NULL),
(3, NULL),
(4, NULL),
(5, NULL),
(6, NULL),
(7, NULL),
(8, NULL),
(9, NULL),
(10, NULL),
(11, NULL),
(12, NULL),
(13, NULL),
(14, NULL),
(15, NULL);
INSERT INTO names VALUES
(1, 'text1'),
(2, 'text2'),
(3, 'text3'),
(4, 'text4'),
(5, 'text5'),
(6, 'text6'),
(7, 'text7'),
(8, 'text8'),
(9, 'text9'),
(10, 'text10');
UPDATE
member m1
JOIN (SELECT id, #i:=FLOOR(1 + RAND() * 10), (SELECT name FROM names n WHERE n.id = #i) name FROM member) m2
ON m1.id = m2.id
SET
m1.name = m2.name;