I have a table with 3 columns: id, date and name. What I am looking for is to delete the records that have a duplicate name. The rule should be to keep the record that has the oldest date. For instance in the example below, there is 3 records with the name Paul. So I would like to keep the one that has the oldest date (id=1) and remove all the others (id = 4 and 6). I know how to make insert, update, etc queries, but here I do not see how to make the trick work.
id, date, name
1, 2012-03-10, Paul
2, 2012-03-10, James
4, 2012-03-12, Paul
5, 2012-03-11, Ricardo
6, 2012-03-13, Paul
mysql_query(?);
The best suggestion I can give you is create a unique index on name and avoid all the trouble.
Follow the steps as Peter Kiss said from 2 to 3. Then do this
ALTER Table tablename ADD UNIQUE INDEX name (name)
Then Follow 4 Insert everything from the temporary table to the original.
All the new duplicate rows, will be omitted
Select all the records what you want to keep
Insert them to a temporary table
Delete everything from the original table
Insert everything from the temporary table to the original
Like Matt, but without the join:
DELETE FROM `table` WHERE `id` NOT IN (
SELECT `id` FROM (
SELECT `id` FROM `table` GROUP BY `name` ORDER BY `date`
) as A
)
Without the first SELECT you will get "You can't specify target table 'table' for update in FROM clause"
Something like this would work:
DELETE FROM tablename WHERE id NOT IN (
SELECT tablename.id FROM (
SELECT MIN(date) as dateCol, name FROM tablename GROUP BY name /*select the minimum date and name, for each name*/
) as MyInnerQuery
INNER JOIN tablename on MyInnerQuery.dateCol = tablename.date
and MyInnerQuery.name = tablename.name /*select the id joined on the minimum date and the name*/
) /*Delete everything which isn't in the list of ids which are the minimum date fore each name*/
DELETE t
FROM tableX AS t
LEFT JOIN
( SELECT name
, MIN(date) AS first_date
FROM tableX
GROUP BY name
) AS grp
ON grp.name = t.name
AND grp.first_date = t.date
WHERE
grp.name IS NULL
DELETE FROM thetable tt
WHERE EXISTS (
SELECT *
FROM thetable tx
WHERE tx.thename = tt.thename
AND tx.thedate > tt. thedate
);
(note that "date" is a reserver word (type) in SQL, "and" name is a reserved word in some SQL implementations)
Related
i have a table
users
id collection_id
1 xwkoss
2 cw2333
3 oipopp
And i run query:
SELECT * FROM USERS WHERE collection_id in ('xwkoss','cw2333', 'abcdeef')
that query work fine and return 2 values existing on table, but i need know, which value doesn't exist on table records example: 'abcdeef', based on search parameters
thanks
Create a table on-the-fly and check with NOT EXISTS:
SELECT user_code
FROM
(
SELECT 'xwkoss' AS user_code
UNION ALL
SELECT 'cw2333' AS user_code
UNION ALL
SELECT 'abcdeef' AS user_code
) codes
WHERE NOT EXISTS
(
SELECT NULL
FROM users
WHERE users.user_code = codes.user_code
)
ORDER BY user_code;
I'm creating a date/unique ID table to streamline some of the other queries we need to run as a team. Basically I have a set of value ('A','B','C',...etc)
and need add a date to each value so the result would look something like:
I have a table a all my dates and all my IDs, can I join them and end a result like the below:
Date ID
1/1/2018 A
1/1/2018 B
1/1/2018 C
1/1/2018 ..etc
1/2/2018 A
1/2/2018 B
1/2/2018 C
1/2/2018 ..etc
I know I can create table in excel or something and insert it, but as more values are added I'd like to be able to rerun the script to generate the values.
Is this possible?
Edit - cross join worked perfectly
select date, id from cal (cross join distinct id from source) t1
You can use the following query to get the expected result:
-- query to get the result in case the columns in the same table.
SELECT t_dates.Date, t_ids.ID FROM (
SELECT DISTINCT Date FROM table_name
) t_dates, (
SELECT DISTINCT ID FROM table_name
) t_ids
ORDER BY t_dates.Date ASC, t_ids.ID ASC
-- query to get the result in case the columns are in different tables.
-- this is also possible with the same table.
SELECT DISTINCT t_dates.Date, t_ids.ID
FROM table_name1 t_dates, table_name2 t_ids
ORDER BY t_dates.Date ASC, t_ids.ID ASC
You can also create a view:
-- creating the view
CREATE VIEW table_id AS
SELECT t_dates.Date, t_ids.ID FROM (
SELECT DISTINCT Date FROM table_name
) t_dates, (
SELECT DISTINCT ID FROM table_name
) t_ids
-- using the view
SELECT * FROM table_id
Lets say I have a MySQL table that has the following entries:
1
2
3
2
5
6
7
6
6
8
When I do an "SELECT * ..." I get back all the entries. But I want to get back only these entries, that exist only once within the table. Means the rows with the values 2 (exists two times) and 6 (exists three times) have to be dropped completely out of my result.
I found a keyword DISTINCT but as far as I understood it only avoids entries are shown twice, it does not filters them completely.
I think it can be done somehow with COUNT, but all I tried was not really successful. So what is the correct SQL statement here?
Edit: to clarify that, the result I want to get back is
1
3
5
7
8
You can use COUNT() in combination with a GROUP BY and a HAVING clause like this:
SELECT yourCol
FROM yourTable
GROUP BY yourCol
HAVING COUNT(*) < 2
Example fiddle.
You want to mix GROUP BY and COUNT().
Assuming the column is called 'id' and the table is called 'table', the following statement will work:
SELECT * FROM `table` GROUP BY id HAVING COUNT(id) = 1
This will filter out duplicate results entirely (e.g. it'll take out your 2's and 6's)
Three ways. One with GROUP BY and HAVING:
SELECT columnX
FROM tableX
GROUP BY columnX
HAVING COUNT(*) = 1 ;
one with a correlated NOT EXISTS subquery:
SELECT columnX
FROM tableX AS t
WHERE NOT EXISTS
( SELECT *
FROM tableX AS t2
WHERE t2.columnX = t.columnX
AND t2.pk <> t.pk -- pk is the primary key of the table
) ;
and an improvement on the first way (if you have a primary key pk column and an index on (columnX, pk):
SELECT columnX
FROM tableX
GROUP BY columnX
HAVING MIN(pk) = MAX(pk) ;
select id from foo group by id having count(*) < 2;
I have a table name Data with fields
Surmane, Name, Timestamp, PaidMoney, ChangAmmount, Address, Store
I want to have as result of a query the last record (DESC Timestamp Limit 1) of each person (group by Surname, Name) with the PaidMoney,ChangeAmmount, Address, Store
For example the result must be
Jones, Jim, 1290596796, 220.00, 0.25, 5th Avenue 120, Some Store1
Kojak, Ian, 1290596890, 1000.00, 50.25, Derek Avenue 1020, Some Store2
For each combination of Surname, Name must present the last record.
I try to do this with:
select `Surname`,
`Name`,
max(date_format(from_unixtime(`Timestamp`),'%Y/%m/%d - %T')) AS `dateTime`,
`PaidMoney`,
`ChangAmmount`,
`Address`,
`Store`
from `Data`
group by `Surname`, `Name`;
No good cause this doesn't show correct data.....
Please Help...
Thank you...
select t1.surname,
t1.name,
from_unixtime(t1.timestamp,'%Y/%m/%d - %T') as datetime,
t1.PaidMoney,
t1.ChangAmmount,
t1.Address,
t1.Store
from table as t1
inner join (select concat_ws(' ',name,surname) as n,max(timestamp) as timestamp
from table
group by name,surname) as t2
on t1.timestamp = t2.timestamp and concat_ws(' ',t1.name,surname) = t2.n
Your table contains redundant datas of names and surnames.
It would be better if you put these datas in another table and refer to them using people id.
Moreover without an id, the use of concat will slow down the join performance, even if you would have an index.
edit.
create view my_view as
select * from table t1
where timestamp = (select max(timestamp) from table as t2
where concat_ws(' ',t1.name,t1.surname) = concat_ws(' ',t2.name,t2.surname))
You should add order by timestamp DESC to your query and change the max(...) part to timestamp.
You could do a subquery (ie. a nested SELECT) to get the max(date stuff) for each person, but that wouldn't be very efficient, according this page, which suggests another way that might be helpful:
http://dev.mysql.com/doc/refman/4.1/en/example-maximum-column-group-row.html
insert into tblcustomermachine
(
select * from
((select vch_CustomerID from tblcustomer where tblcustomer.vch_CustomerID='Cust00001' )
union all
(select Rate from tblmachine)) as t );
that table contains 18 cols and this resultset also contains 18 rows yet it shows " Column count doesn't match value count at row 1" . why?
It looks like your table tblcustomermachine has more then the 1 column.
Like Simone answered, update your insert to INSERT INTO tblcustomermachine(col_1) SELECT ...
You may skip the column names during INSERT, however the SELECT needs to return the same amount of columns that the table holds.
AFAIK, you have to declare field name:
insert into tblcustomermachine (col_1, col_2, col_3, ... col_18) (
select t.field1, t.field2, t.field3, ... t.field18 from (
(select vch_CustomerID from tblcustomer where tblcustomer.vch_CustomerID='Cust00001')
union all (select Rate from tblmachine))
as t
);