Delete duplicate records in MySql in one single query - mysql

I have this MySQL table:
+------+------+
| id | name |
+------+------+
| 1 | John |
| 1 | John |
| 2 | Jill |
| 2 | Jill |
| 3 | Jack |
| 3 | Jack |
+------+------+
Can anyone please tell me how to delete the duplicate records and keep one record from this table in MySQL in one single query (i.e without creating another table)?

You have basically two options unless you want to do something more precise:
select * from table group by ID
or, alternatively:
select distinct(ID), name from table

Related

Finding out only certain Master items from Details table in a Master-Details table relationship

I've been trying to get this going for hours and haven't figured this out yet.
Say I've got 2 tables - master and details.
master/detail has the following data
master table
+------+-------+
| id | name |
+------+-------+
| 1 | jeff |
| 2 | simon |
| 3 | andy |
| 4 | jerry |
+------+-------+
details table
+----+-----------+---------+
| id | master_id | tag |
+----+-----------+---------+
| 1 | 1 | WINDOWS |
| 2 | 1 | MAC |
| 3 | 2 | MAC |
| 4 | 3 | WINDOWS |
| 5 | 3 | MAC |
| 6 | 3 | LINUX |
| 7 | 4 | MAC |
+----+-----------+---------+
how do I select the master records which has both tags 'WINDOWS', 'MAC'.
So it should only return master_id 1 and 3 which is jeff and andy only.
If I do a
select distinct(master_id) from details where tag in ('WINDOWS', 'MAC')
it gives me all of them.
Sorry for the newbie question but if anyone can help, it'll be much appreciated.
You need simple GROUP BY with HAVING clause :
select master_id
from details
where tag in ('WINDOWS', 'MAC')
group by master_id
having count(*) = 2;
If details table has duplicate tags for master_id then you need count(distinct tag).
YOu could use a join with count having 2 value only for tag
select distinct master_id
from detail
inner join (
select master_id from detail
group by master_id
having count(distinct tag) = 2
) t on t.master_id = detail.master_id and detail.tag in ('WINDOWS', 'MAC')

MYSQL Combine two JOINs that reference the same columns for the results table

I am trying to output the same field twice in my SELECT but with different criteria for that field in the same row.
If I had to write it out in incorrect SQL syntax, but hopefully illustrates my point
SELECT names.FirstName WHERE xyz, names.FirstName WHERE abc FROM names;
I want the First Name column to repeat in the same row, but to SELECT using different criteria
.
The actual example is as follows, I have two tables,
names - unique ID, first name, last name
+----+---------+-------+
| ID | First | Last |
+----+---------+-------+
| 1 | Husband | Hlast |
| 2 | Wife | Wlast |
| 3 | Friend | Flast |
+----+---------+-------+
and another table,
groups - Unique ID , Unique ID of the head of house
+----+-------+
| ID | HOHID |
+----+-------+
| 1 | 1 |
| 2 | 1 |
| 3 | 3 |
+----+-------+
I would like the output to be the listing of each person's First and Last name as well as the First and Last name of their head of house
+----+---------+-------+----------+---------+
| ID | First | Last | HOHFirst | HOHLast |
+----+---------+-------+----------+---------+
| 1 | Husband | Hlast | Husband | Hlast |
| 2 | Wife | Wlast | Husband | Hlast |
| 3 | Friend | Flast | Friend | Flast |
+----+---------+-------+----------+---------+
I can get the head of households First and Last
SELECT names.First, names.Last WHERE names.id=groups.HOHid FROM names, groups;
and separately I can get the individuals first and last
SELECT names.First, names.Last WHERE names.id=groups.id FROM names, groups;
but I can't figure out how to join the two as separate columns as the output would need to be names.First and names.Last twice but with two separate WHERE clauses. I am very new to sql and any help would be appreciated.

MySQL How can I make a better query to connect two tables through my bridge table?

I have these tables:
words:
+----+------+
| ID | DATA |
+----+------+
| 1 | jo |
| 2 | yes |
| 3 | jupp |
| 4 | yeah |
| 5 | jepp |
| 6 | joah |
| 7 | ne |
| 8 | nee |
| 9 | no |
| 10 | nope |
| 11 | nah |
+----+------+
statements:
+----+------+
| ID | DATA |
+----+------+
| 1 | ja |
| 2 | nein |
+----+------+
and a bridge table that connects the words from table "words" with the DATA from table "statements":
bridge:
+--------------+---------+
| ID_statement | ID_word |
+--------------+---------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 1 | 4 |
| 1 | 6 |
| 2 | 8 |
| 2 | 9 |
+--------------+---------+
I wanted to get a SELECT QUERY to get all words associated with the statement "ja".
this query does the job, but seems more complicated than it should be:
SELECT words.DATA FROM words
JOIN bridge ON words.ID = bridge.ID_word
JOIN statements ON statements.ID = bridge.ID_statement
WHERE statements.ID = (
SELECT ID FROM statements WHERE statements.DATA = "ja"
);
Intuition tells me that I am doing that far to comlicated, but I can't figure out where the complication lies.
awkward.
I like to name the primary keys the same as the columns that reference them. So in your example, in the words table, you'd name the primary key ID_word. In the statements table, you'd name the primary key ID_statement.
The advantage is that you can make your SQL join a little more concise with the USING(...) syntax. This syntax assumes there's a column by that name in both tables of a join, and you want the join to match where the column is equal to the same column in the other table.
SELECT words.DATA FROM words
JOIN bridge USING (ID_word)
JOIN statements USING (ID_statement)
WHERE statements.DATA = 'ja';
Also you don't need to run a subquery in your example. The rows in statement matching the IDs from the rows in statement where DATA='ja' are the same set as the rows in statement where DATA='ja'.
how would one describe the relationship here? one-to-many?
The relationship modeled by a bridge table is a many-to-many relationship. The specific data in your example doesn't show it, but it's possible that many different statements could reference the same word. What you do show is that each statement can reference many words.

mysql select with group by returning rows with a preference order

I have the following mysql query result:
+----+------------+-------------+
| id | title | lang |
+----+------------+--------------
| 1 | ola1 | 1 |
| 1 | hello1 | 2 |
| 1 | bonjour1 | 3 |
| 2 | ola2 | 1 |
| 2 | bonjour2 | 3 |
| 3 | hello3 | 2 |
| 4 | bonjour4 | 3 |
+----+------------+-------------+
What I want is a group_by query by id and that gives me for each id the title with a order of preference for lang field. Example:
Result for lang preference order 1, 2, 3:
+----+------------+-------------+
| id | title | lang |
+----+------------+--------------
| 1 | ola1 | 1 |
| 2 | ola2 | 1 |
| 3 | hello3 | 2 |
| 4 | bonjour4 | 3 |
+----+------------+-------------+
Result for lang preference order 3, 2, 1:
+----+------------+-------------+
| id | title | lang |
+----+------------+--------------
| 1 | bonjour1 | 3 |
| 2 | bonjour2 | 3 |
| 3 | hello3 | 2 |
| 4 | bonjour4 | 3 |
+----+------------+-------------+
Thanks!
It is either not possible, or, not with in my SQL skills to execute that in one query. I always end up using a temporary template and two SQL commands for these problems:
(assuming that your table is called Table1 and the temporary table should be called tempTable)
SELECT Table1.id, Min(Table1.lang) AS Min_Of_lang INTO tempTable FROM Table1 GROUP BY Table1.id ORDER BY Table1.id;
SELECT Table1.* FROM tempTable INNER JOIN Table1 ON (tempTable.MinOflang = Table1.lang) AND (tempTable.id = Table1.id);
The first command creates a new table (that overrides the current table if it exists). The second command uses the first table to produce the desired result set.
To change from your first desired results table to the second, use Max instead of min in the first query.
Somebody else may well have a more elegant solution than mine. Also, an extra SQL statement could be added to delete the temporary table.
This is a feature that is not defined in MySQL. The displayed value in a non-aggregated column is undetermined. read more here (MySQL Documentation).
(Standard SQL doesn't allow to include non-aggregated columns when using GROUP BY, I guess this is one of the reasons).
From your description of the what you want to do, you should simple SELECT all rows with the lang you are looking for
SELECT * FROM your_table WHERE lang = 1

MySQL copy column from different tables, insert at top of table

I'm trying to merge a couple tables together to consolidate the data, but when I try to insert a column from one table to the other, the query I'm using inserts the records after the last currently existing record in the table. There are a ton of questions about duplicating columns, but they all seem to be starting with an empty table.
INSERT INTO newTable( newColumn ) SELECT oldColumn FROM oldTable
How do I modify this query to insert the rows at the beginning of the table instead of the end?
Visual representation of what is happening (left) vs. what I want to happen (right):
+--------+--------+------------+ +--------+--------+------------+
| ID | Column | newColumn | | ID | Column | newColumn |
+--------+--------+------------+ +--------+--------+------------+
| 1 | 12345 | | | 1 | 12345 | 12345 |
| 2 | 12345 | | | 2 | 12345 | 12345 |
| 3 | 12345 | | | 3 | 12345 | 12345 |
| 4 | | 12345 | +--------+--------+------------+
| 5 | | 12345 |
| 6 | | 12345 |
+--------+--------+------------+
As mentioned in the comments you need an UPDATE statement not an INSERT statement:
UPDATE newTable
JOIN oldTable
ON newTable.id = oldTable.id
SET newcolumn = oldcolumn;
A tested example may be seen here: http://sqlfiddle.com/#!2/77724/1