Mysql delete 5th element of a table - mysql

I have a table:
ID Friend
John Rita
John Jack
Jack Rita
Rita John
John Peter
John Owen
John Eric
John Louis
I want to write a query where I delete all ID's after the 5th element. In other words I want to keep for each ID maximum 5 friends.
I have tried with a group by or something like that, but I don't now exactly how I have to do the delete.
The result must be:
ID Friend
John Rita
John Jack
Jack Rita
Rita John
John Peter
John Owen
John Eric

Short answer, no. The reason is that RDBMS's do not do not guarantee the order of entries.
If you need to be certain of the rows you are deleting, then you will need to know the order. I would recommend starting by adding an auto incrementing primary key column. From that, you will at least be certain of the order of entries. Eg:
ALTER TABLE table_name ADD column_name INT AUTO_INCREMENT PRIMARY KEY;
Note: This will only guarantee the order of future entries, not previously inserted entries.

Related

How to get actual index number of rows in MySQL when using Where clause

I'm working on Users table on which I'm adding a where clause like this :
SELECT F_Name, L_Name FROM Users Where HouseCode = 'ABC';
which is returning all the Users having ABC in their HouseCode column.
But I want the actual index number or actual row numbers of those Users from the table rows.
Example :
Those Users who have HouseCode = 'ABC' are on row number
10,18,24,77,82
So how to get the actual row numbers or index of these users using query?
Note : I do have id as primary key which is auto incremented but I've to delete Users sometimes. So can't rely on it.
Thank you
Edited :
I understand what you're trying to say but let me explain it to you by your own example : Now tomorrow if i delete the 3rd record of Jason then in the actual index Karen's record which have id of 4 will actually become 3rd & which is the real index of that record. Just like this :
id | F_Name | L_Name | HousecCode
-------------------------------------------------
1 Mark Dine 123
2 Mary Codd ABC
3 Jason Trex ABC
4 Karen Port 456
5 Jan Hellopei ABC
INDEX_NO | id | F_Name | L_Name | HousecCode
----------------------------------------------------------------------
1 1 Mark Dine 123
2 2 Mary Codd ABC
3 4 Karen Port 456
4 5 Jan Hellopei ABC
So when i fetch records it should give me the actual index by counting it's position in table. This is the reason i can't rely on id column.
Just to state the obvious, that is already said:
Relational database engines such as MySQL do not have row numbers, like an Excel sheet would have.
To support the correct answer by The Impaler
Note : I do have id as primary key which is auto incremented but I've to delete Users sometimes. So can't rely on it.
Use the PRIMARY KEY, the id column. Just because values are missing does not invaidate the column,
therefore:
SELECT id, F_Name, L_Name FROM Users Where HouseCode = 'ABC';
This will output the UNIQUE AUTO-INCREMENT value of id with the matching columns.
Whether a column is an uninterrupted chain of numbers is subjective and not part of any absolute SQL record keeping.
If you simply want a continual item lst number, you don't need to record that; but you do need to generate that on data output:
Full Example:
Data in the table:
id | F_Name | L_Name | HousecCode
-------------------------------------------------
1 Mark Dine 123
2 Mary Codd ABC
3 Jason Trex ABC
4 Karen Port 456
5 Jan Hellopei ABC
The result from your SQL would be:
id | F_Name | L_Name
------------------------------------
2 Mary Codd
3 Jason Trex
5 Jan Hellopei
Jason Trex will always be at row number 3 in the MySQL Database, but Jason Trex might be (as here) result number 2.
So to output this you would use a loop structure:
Pseudo Code (PHP):
$counter = 0;
foreach($result as $row) {
$counter++;
print $counter." : ". $row['F_Name']." ".$row['L_Name']."<br>";
}
unset($counter, $row);
Your result would look like:
1 : Mary Codd
2 : Jason Trex
3 : Jan Hellopei
The value of 1,2,3 etc does not need to be stored by MySQL because it is on a per list basis.

SQL - Selecting data that is the same in multiple rows for a particular key

I have a dataset like below:
KEY USER STEP
---------------------
123 Geoff 1
123 Geoff 2
123 John 3
456 Jane 1
456 Jane 2
456 Jane 3
456 Jane 4
What I need to do is select the KEY where the USER is the same in all steps (there can be between 1 to 5 steps in the dataset). So in the example above I need the query to return KEY 456.
Any help much appreciated!
Instead of comparing with min(user) and max(user), you can do this as well:
SELECT tablename.key
FROM tablename
GROUP BY tablename.key HAVING count(DISTINCT d.user) = 1;
count(DISTINCT d.user) should be more descriptive for your use case.
You can do this using GROUP BY and HAVING:
select key
from table t
group by key
having min(user) = max(user);
Note: key and user are both keywords. You may have to use backticks (or hopefully your actual column names are different).

Issues setting up a N-M relationship

Using MySQL I'm trying to set up a 1 to many relationship using data that has already been uploaded into the database. For examples sake, lets say I have a list of names in one table and I want connect them to a lists of places they have been. Obviously 1 person can go to many different places, but i'm having an issue getting this set up.
-----Name-----------ID---------
John Smith 1
Joe Random 2
Seth Guy 3
------------------------------
I have another table that would look like this:
-------city---------ID---------
New York 1
Chicago 2
Orlando 3
LA 4
-------------------------------
I'm looking for something like this:
--------Name--------City----------
John Smith Chicago
John Smith Orlando
John Smith New York
Seth Guy Chicago
Joe Random LA
------------------------------------
I obviously Know that John Smith has been to all 3 locations because the original file I uploaded tells me so, but I want the database to make that connection and place him their accordingly.
As noted in the comments, this is an N-M relationship, not a 1-N relationship. You need an additional "mapping" table to record the visits:
CREATE TABLE visits (
person_id INT,
city_id INT,
CONSTRAINT visits_pk PRIMARY KEY (person_id, city_id)
);
Then, you can query all the visits with a couple of joins:
SELECT person.name, city.name
FROM person
JOIN visits ON person.id = visits.person_id
JOIN city ON visits.city_id = city.id
Introduce a new table that holds the relationship.
Your schema would look something like this:
create table person (id, name)
create table city (id, name)
create table person_to_city (people_id, city_id)
Create a foreign key constraint on people_id and city_id.

How to design one user "likes" another?

I would imagine this is kind of like friends, but doesn't need to be two-way. So like this:
from_user to_user
-------------------
John Mary
Mary John
John Susan
Mary Dave
I was curious if there were any issues with doing it as shown below.
user1 user2 mutuality
--------------------------------
John Mary 2
John Susan 1
Mary Dave 1
The second seems like it would have more complicated queries and checks, but wouldn't it end up saving space? For example, if Susan ends up falling for John one day, you'd check user2 for Susan and user1 for John. If it exists, update the mutuality to 2. If not, insert a new row [Susan, John, 1]. Something like that?
What's the best way of doing this?
I would choose the first method. You will not end up saving enough space with the second method to be an issue. Since each choice (like) is an action, having a separate record to store that action matches the work flow. John likes Mary, add a record. Mary likes John, add another record. Mary no longer likes John, delete that single record. This is easier to maintain (for me). I find keeping things in smaller granular parts keeps it simple.
In terms of design, I would recommend that instead of using string names in the likes table, you should have a users table with each user have a primary key id (unique). This way, users can modify names without breaking the relationships.
The table data would look like this:
Users table
id Name
1 John
2 Mary
3 Susan
4 Dave
Likes table
From To
1 2
2 1
1 3
2 4
The tables would have the following structure
users
-----
id (integer autoincrement)
name (varchar)
likes
-----
id (integer autoincrement)
fromid (integer)
toid (integer)
The sql would look like this to produce the list
SELECT f.name as fromName, t.name as toName
FROM (likes JOIN users AS f ON likes.fromid = f.id)
JOIN users AS t ON likes.toid = t.id;
The second method allows the following anomaly:
user1 user2 mutuality
--------------------------------
John Mary 2
Mary John 1
Do John and Mary like each other mutually (as implied by the first row), or just Mary likes John uni-directionally (as implied by the second row)?
The first method doesn't suffer from such inconsistencies, and data integrity is generally more important than saving some space.
BTW, if you introduce an integer surrogate key and reference it from the junction table (instead of the actual names), the junction table will become much leaner, negating much of the space advantage of the second method.

finding duplicates in MySQL with a null field when some SHOULD have a null field

Need some help from a MySQL expert here. I have a terrible database to work with and I'm trying to fix the structure a bit but this one has me baffled. The table initially had an id, name and 4 sell columns. I converted that to an id, name and single sell column as basically a pivot table. That was fine, next issue was to get rid of duplicates since not every entry had 4 sell entries.
So after the first operation I ended up with something like this:
id name sellid
1 bob 111
1 bob
1 bob
2 mary 112
2 mary 113
2 mary 114
2 mary 115
3 fred
3 fred
3 fred
3 fred
So by doing group by I managed to get it to the point where it looks like this:
id name sellid
1 bob 111
1 bob
2 mary 112
2 mary 113
2 mary 114
2 mary 115
3 fred
Now here is where I hit a wall. Fred is fine, he is supposed to have an entry but no sellid, Mary is also fine she has all 4 sellids full. Bob is the issue. How do I remove the empty sellid for him without affecting Fred?
I'd say what I tried but I am just at a complete loss here so I really haven't tried anything yet.
You are looking for an outer join between your names and other data:
SELECT * FROM
(SELECT DISTINCT id, name FROM my_table) t1 NATURAL LEFT JOIN
(SELECT * FROM my_table WHERE sellid IS NOT NULL) t2
See it on sqlfiddle.
But really, you should normalise your schema further so that you have a table of (personid, name) and a table of (personid, sellid) pairs (from which you essentially perform the above outer join as & when required to obtain the necessary records including NULLs).