Getting a set with unique column values from MySQL - mysql

Say that I have a set with columns like this
user_id | username | updated_at | data...
user_id and username are not unique in the set, so you can have something like this
user_id | username | updated_at | data...
------------------------------------------
1 | test | 140****** | ...
4 | test2 | 140****** | ...
1 | test | 139****** | ...
7 | meh | 140****** | ...
But I would like to remove the duplicate occurrences; I tried GROUP BY but it gives me something unexpected as a lot of items are getting removed (I guess they appears later in the set as the query has a LIMIT in it).

If you need to select all the data - first of all u should decide how to get the updated_at and data columns.
In case you want to have the data concatenated and you want to have the latest updated_at you should do
SELECT user_id, username, max(updated_at), group_concat(data separator ',')
FROM table_name
GROUP BY user_id, username
ORDER BY user_id, username
LIMIT X
in that case your data will be ordered by user_id, and username
Note:
it is not clear from your question if you want to remove the data from the table itself or only from the result set.

Is this what you want?
select distinct user_id, username
from table t;

Related

select statement from 2 unrelated tables

There's 2 unconnected tables, with no common IDs
+---------------------+
| names |
+------+--------------+
| name | lastN |
+-------------+-------+
| Anthony | monta |
| Ryo | shizu |
+------+--------------+
+----------------------+
| nicknames |
+------+---------------+
| nickname |
+------+---------------+
| miso_hungry |
+------+---------------+
I'm trying to run a select query on both tables and currently doing something like:
SELECT names.name, nicknames.nickname
FROM names, nicknames
WHERE names.name="miso_hungry" OR nicknames.nickname="miso_hungry"
I'm getting back a weird results with repeating identical rows, which doesn't make sense.
For example if I search for miso_hungry with the query above it will return every row of "names" table for some reason and append the correct rows from the "nicknames" table..
Attaching a screenshot of the results
Above should show "NULL" under name column, since "miso_hungry" is not found in that column and I'm not sure why it prints every row of the "names" table also.
You can use UNION Clause
Each SELECT statement within UNION must have the same number of columns
The columns must also have similar data types
The columns in each SELECT statement must also be in the same order
So we need to made them satisfy above condition. We can use Aliasing to do this.
SELECT name,(SELECT NULL) as nickname FROM names WHERE name = "miso_hungry"
UNION
SELECT (SELECT NULL) as name, nickname FROM nicknames WHERE nickname = "miso_hungry"
Edited
If you want to get the match count from both table use query like below :
SELECT SUM(count) as count FROM (
SELECT count(*) as count FROM names WHERE name = "miso_hungry"
UNION ALL
SELECT count(*) as count FROM nicknames WHERE nickname = "miso_hungry"
) both_table
The order of execution in your statement is from,where,select. With and implicit join you get a cartesian product which given
use sandbox;
create table n(name varchar(20));
create table nn(nickname varchar(20));
insert into n values('Antony'),('Ryo');
insert into nn values('miso');
results in
MariaDB [sandbox]> SELECT n.name, nn.nickname
-> FROM n, nn;
+--------+----------+
| name | nickname |
+--------+----------+
| Antony | miso |
| Ryo | miso |
+--------+----------+
2 rows in set (0.00 sec)
The where clause is then applied - which yields the same result.

Need a SQL query statement for this case

This is the structure of the table
mysql> select * from p1;
+----------+-------+-----------+
| username | token | last_used |
+----------+-------+-----------+
| a | aacs | 5 |
| d | dddd | 3 |
| a | aaaaa | 3 |
+----------+-------+-----------+
How can I delete the record who has the minimum last_used value from the set queried by username?
In this case ,the given username parameter is 'a',then I shold delete the record 'a','aaaaa',3 because 3 is smaller than 5(the username of last_used(5) is 'a',too).
My answer is
delete from persistent_logins
where last_used=(select *
from (select MIN(last_used)
from persistent_logins where username=?)as t
)
and username=?
but it's useful,I need a statement like delete .... from..where username=?
It is important that only one parameter is allowed.But my answer has two parameter.
You can actually use ORDER BY and LIMIT with DELETE. The rows will be deleted in that order with LIMIT controlling how many are deleted.
If the ORDER BY clause is specified, the rows are deleted in the order that is specified. The LIMIT clause places a limit on the number of rows that can be deleted.
(From: https://dev.mysql.com/doc/refman/5.0/en/delete.html)
Try something like this:
DELETE FROM p1
WHERE username = ?
ORDER BY last_used ASC
LIMIT 1

Counting votes in a MySQL table only once or twice

I've got the following table:
+-----------------+
| id| user | vote |
+-----------------+
| 1 | 1 | text |
| 2 | 1 | text2|
| 3 | 2 | text |
| 4 | 3 | text3|
| 5 | 2 | text |
+-----------------+
What I want to do is to count the "votes"
SELECT COUNT(vote), vote FROM table GROUP BY vote
That works fine. Output:
+-------------------+
| count(vote)| vote |
+-------------------+
| 3 | text |
| 1 | text2|
| 1 | text3|
+-------------------+
But now I only want to count the first or the first and the second vote from a user.
So result what I want is (if I count only the first vote):
+-------------------+
| count(vote)| vote |
+-------------------+
| 2 | text |
| 1 | text3|
+-------------------+
I tried to work with count(distinct...) but can get it work.
Any hint in the right direction?
You can do this in a single SQL statement with something like this:
SELECT vote, COUNT(vote)
FROM
(
SELECT MAX(user), vote
FROM table1
GROUP BY user
) d
GROUP BY vote
Note that this only gives you 1 vote not 1 or 2.
The easiest way would be to use one of the "row numbering" solutions listed in this SO question. Then your original query's almost there:
SELECT
COUNT(vote),
vote
FROM tableWithRowNumberAdded
WHERE MadeUpRowNumber IN (1,2)
GROUP BY vote
My alternative is much longer winded and calls for working tables. These can be "real" tables in your schema, or whatever flavour of intermediate resultsets you are comfortable with.
Start by getting the first vote for each user:
SELECT user, min(id) FROM table GROUP BY user
Put this in a working table; let's call it FirstVote. Next we can get each user's second vote, if any:
SELECT user, min(id) FROM table WHERE id not in (select id from FirstVote) GROUP BY user
Let's call the result of this SecondVote. UNION FirstVote to SecondVote, join this to the original table and group by vote. There's your answer!
SELECT
vote,
COUNT(*)
FROM table
INNER JOIN
(
SELECT id FROM FirstVote
UNION ALL
SELECT id FROM SecondVote
) as BothVotes
ON BothVotes.id = table.id
GROUP BY vote
Of course it could be structured as a single statement with multiple sub-queries but that would be horrendous to maintain, or read in this forum.
This is a very triky question for MySQL. On other systems there windowed functions: it performs a calculation across a set of table rows that are somehow related to the current row.
MySQL lacks this functionality. So one should look for a workaround. Here is the problem description and couple solutions suggested: MySQL and window functions.
I also assume that first 2 votes by the User can be determined by Id: earlier vote has smaller Id.
Based on this I would suggest this solution to your problem:
SELECT
Vote,
Count (*)
FROM
Table,
(
SELECT
user_id, SUBSTRING_INDEX(GROUP_CONCAT(Id ORDER BY user_id ASC), ',', 2) AS top_IDs_per_user
FROM
Table
GROUP BY
user_id
) s_top_IDs_per_User
WHERE
Table.user_id = s_top_IDs_per_User.User_id and
FIND_IN_SET(Id, s_top_IDs_per_User.top_IDs_per_user)
GROUP BY Vote
;

filter sql rows using update statement

I am trying to write a query which can get invalid refby(is related to id), please check following db structure...
| id | acnumber | refby |
+----+-----------+--------+
| 1 | ac01 | 2 |
+----+-----------+--------+
| 2 | ac02 | 1 |
+----+-----------+--------+
| 3 | ac03 | 5 |
+----+-----------+--------+
As you can find there is no id with value of 5 in above table so query must return 3rd row as result.
I have tried...
SELECT * FROM tbl.members WHERE refby != (SELECT id FROM tbl.members WHERE id = refby)
But this is not giving correct results, please help, thanks.
SELECT * FROM members WHERE refby not in (SELECT id FROM members)
This should solve your problem
You can try this using not in:-
SELECT * FROM tbl.members WHERE refby not in (SELECT id FROM members)
This should be a LEFT JOIN, NOT IN is slow on large tables... assuming id and refid is an PRIMARY KEY or UNIQUE key (read unique within your dataset) then this query should return the same results.
SELECT
*
FROM
members members1
LEFT JOIN
members members2
ON members1.id = members2.refby
WHERE members2.id IS NULL
check the sqlfriddle http://sqlfiddle.com/#!2/05731/1

How to select records where two fields are unique

I have a table that looks something like this:
+-------------+----------+---------------+------------+
| Contract_ID | Name | Username | Password |
+-------------+----------+---------------+------------+
| 12345671 | Facebook | john.doe | password |
| 12345672 | Google | john.doe | password |
| 12345673 | Apple | martha.malone | doodlebear |
| 12345674 | Samsung | jimmy47 | parkour445 |
| 12345675 | HTC | rick.grimes | simpsons33 |
+-------------+----------+---------------+------------+
I'd like to select only records where there is a one to one ratio between username/password combination and contract id. In this case, that would mean I'd like to select the 3rd, 4th and 5th records in this table.
I've tried different combinations of the DISTINCT keyword but that doesn't seem to be the correct route to go. Is there a query that can return this information?
As a sort of bonus question: is there a query that can produce the opposite results (ie. only records where there is greater than 1 to 1 ratio between contract ids and username/password combination)?
You should use the GROUP BY clause together with the HAVING clause, for example:
SELECT Username, Password FROM Table
GROUP BY Username, Password
HAVING COUNT(*) = 1
The opposite is:
SELECT Username, Password FROM Table
GROUP BY Username, Password
HAVING COUNT(*) > 1
Group by (Name, Password) doesn't work?
Very naughty way of doing it,not good at all, but it works:
select distinct
least(col1, col2) as value1
, greatest(col1, col2) as value2
from yourtable