Mysql delete duplicate rows + sort condition - mysql

I'm trying to delete some rows from my Mysql table, when one key is duplicate (here "url") and keep a particular one (here the smallest "key1" and "key2")
Example :
Table t1
Id Url Key1 Key2
1 A.com 10 10
2 B.com 20 25
3 B.com 21 25
4 C.com 35 35
5 C.com 35 37
Desired output is :
Table t1
Id Url Key1 Key2
1 A.com 10 10
3 B.com 21 25
5 C.com 35 37
So the query (if it exists) should look like :
Select rows where Url are duplicate
Then sort by Key1 and remove the row where Key1 is strictly inferior
if Key1 are equal, remove the row where Key2 is inferior
Thanks

You want to keep the rows where key1, key2 are maximal. An easy way to express this is:
delete t1 from table t1
where exists (select 1
from t1 t11
where t11.url = t1.url and
(t11.key1 > t1.key1 or
t11.key1 = t1.key1 and t11.key2 > t1.key2
)
);
Alas, MySQL doesn't allow this construct, because you using the table being deleted. So, you can do something like this:
delete t1
from t1 left join
(select t.*,
(select max(key2)
from t1
where t1.url = t.url and t1.key = t.maxkey1
) as maxkey2
from (select url, max(key1) as maxkey1
from t1
group by url
) t
) t
on t1.url = t.url and t1.key1 = t.maxkey1 and t2.key2 = t.maxkey2
where t.url is null;

I think this might be helpful
DELETE t1
FROM t1 as tb1
join t1 as tb2
WHERE tb1.url= tb2.url
and tb1.id < tb2.id
This way you keep the record with the max value on id column
but if you just want to fetch records
SELECT distinct tb1.*
FROM t1 as tb1
join t1 as tb2
WHERE tb1.url= tb2.url
and tb1.id < tb2.id

Related

SQL select rows with number in sequence

I have 1:N table where every entity may have asigned multiple numbers.
ID Number
1 10
1 13
1 11
1 12
1 16
2 11
2 12
2 13
2 10
Now,I want all IDs which have for example 3 numbers in ascending sequence. I do not specify which numbers I want, I just want the SQL to return me all possible combinations it can find but the numbers has to be in ascending sequence and the sequence must contain exactly 3 numbers. The numbers are allways integers of any value. The numbers in result have to be next to each other (12,13,16)is not valid result.
For 3 numbers in this example it would be :
ID 1 : (10,11,12),(11,12,13)
ID 2 : (11,12,13),(10,11,13)
For 2 numbers in this example it would be:
ID 1 : (10,11),(11,12),(12,13)
ID 2 : (11,12)(12,13)
Is this possible in SQL select? Thanx
A solution whats comes close to your expected output.
Involves using self inner joins incombination with CONCAT_WS, GROUP_CONCAT..
For group of three you use this query
Query
SET SESSION group_concat_max_len = ##max_allowed_packet
SELECT
records.ID
, GROUP_CONCAT(CONCAT('(', records.number, ')'))
FROM (
SELECT
DISTINCT
table11.ID
, CONCAT_WS(
','
, table11.Number
, table12.Number
, table13.Number
) AS number
FROM
Table1 AS table11
INNER JOIN
Table1 AS table12
ON
table11.Number + 1 = table12.Number
INNER JOIN
Table1 table13
ON
table12.Number + 1 = table13.Number
ORDER BY
table11.ID ASC
, table11.Number ASC
) AS records
GROUP BY
records.ID
Result
| ID | GROUP_CONCAT(CONCAT('(', records.number, ')')) |
|----|------------------------------------------------|
| 1 | (11,12,13),(10,11,12) |
| 2 | (11,12,13),(10,11,12) |
see demo http://sqlfiddle.com/#!9/c5dfce/39
Simply use join. This produces a result set with each examples of sequential numbers on a different row:
select id, t1.number, t2.number, t3.number
from t t1 join
t t2
on t2.id = t1.id and t2.number = t1.number + 1 join
t t3
on t3.id = t2.id and t3.number = t2.number + 1;
If you really wanted a list, you would simply do:
select id,
group_concat('(', t1.number, ',', t2.number, ',', t3.number, ')') as groups
from t t1 join
t t2
on t2.id = t1.id and t2.number = t1.number + 1 join
t t3
on t3.id = t2.id and t3.number = t2.number + 1
group by t1.id;

SQL Combining data from 3 tables to from a 4th table based on some conditions

I have 3 tables:-
table1 :-
ReportType | ResourceId
t2 123
t3 5
table2:-
Id | Name | Created
1 A 10
2 B 11
123 C 12
table3:-
Id | Name | Created
4 D 13
5 E 14
6 F 15
table1's ResourceId and table2 and 3's Id column have same values
I want to create a 4th table like this:-
ReportType | ResourceId | Name | Created
t2 123 C 12
t3 5 E 14
such that wherever table1's ReportType is t2 I want the Name and Created value from table2 for the condition table1.ResourceId = table2.Id and wherever table1's ResourceType is t3 I want the Name and Created value from table3 for the condition table1.ResourceId = table3.Id.
PS: This isn't some sort of HomeWork. I have been stuck at this query for the past 1 hour, I have read various answers and tried a few queries of my own before posting the question. Any help would really be appreciated.
Explanation in comments :)
--here we join first and second table, but we filter results to include only ReportType = t2
select t1.ReportType, t1.ResourceId, t2.Name, t2.Created from table1 as t1 join table2 as t2 on t1.ResourceId = t2.id
where t1.ReportType = 't2'
union all
--here we join first and third table, but we filter results to include only ReportType = t3
select t1.ReportType, t1.ResourceId, t3.Name, t3.Created from table1 as t1 join table3 as t3 on t1.ResourceId = t3.id
where t1.ReportType = 't3'
You can use the below query:
select report_type, resourceid,name, created from dbo.t2, dbo.t1
where report_type='t2' and ResourceId=id
UNION
select report_type, resourceid,name, created from dbo.t3, dbo.t1
where report_type='t3' and ResourceId=id;

Select records where ID is in the other table and status = 1

I need to get all the records where table1.user is in table2.userid and table2.country = 8 and table2.status = 1
This is the sample data in my database
table1
id user
-- ----
1 12
2 23
3 34
4 32
5 85
6 38
table2
id userid country_id status
-- ---- ----- ----
1 12 5 1
2 12 8 1
3 85 8 1
4 38 8 0
5 38 7 1
6 23 8 1
7 23 4 1
in this case I should only get the id #3 in table2
Inner join will do the job taking only record with match in the two tables.
SELECT *
FROM table1 t1
INNER JOIN table2 t2 on t1.user = t2.userid
WHERE t2.country=8 and t2.status=1
You mean
"get all the records where table1.user is in table2.userid
with table2.country = 8 and table2.status = 1 ?"
If so, then:
Select * from table1 t1
Where Exists(Select * from table2
Where userId = t1.user
and country = 8
and status = 1)
Well to accomplish that is quite simple, you just need to make use of an inner join. An SQL JOIN clause is used to combine rows from two or more tables, based on a common field between them.
In your case, the INNER JOIN will return all rows from table2 where the join condition is met.
For a more detailed explanation and examples just visit this link: http://www.w3schools.com/sql/sql_join.asp
based on your response to Adam's approach "
I tried this but it didn't work, yes it gets the records but the id #2 in table2 is also included. what I need to get is the id #3 in table2. Thanks :) ". I changed my SQL query to:
SELECT
*
FROM
table1
INNER JOIN
table2
ON
table1.user = table2.userid
WHERE
table2.userid = 85
I assumed you only want the data of that particular userid in table2

Mixing 3 sql queries in 1

I have 3 tables as follows
Table1
Id Name
1 abcd
2 bcd
3 dabc
Table2
Id2 Name2
2 xyz
3 def
4 mno
Table3
Id Id2 Value
1 4 1
2 3 1
3 4 1
Now,
From table1 : I have to select all Id where Name is %abc%
From table2: I have to select Id2 where Name2 is "mno"
From Table3: I have to change value to 0 from 1 where Id's value are from Table1 and Id2 is from Table2.
Table 1:
select Id from Table1 where Name like '%abc%'
Table2 :
select Id2 from Table2 where Name2 = "mno"
Table 3:
update Table3 set Value = 0 where Id in() and Id2=
But, I dont know how to make it 1 single query. Can anyone please guide me up ?
Refer to: prior stack article
You've not explained how T1 relates to T2, So I have assumed a cross join.
Whenever you have a record in T1 with name like '%abc%' (1,3) in your data..
and whenever you have a record in T2 with a name equal to 'mno' 4 then you want the value in table 3 to be 0
so the select we generate should produce
1,4
3,4
and when we inner join this back to table 3 it only selects
Id Id2 Value
1 4 1
3 4 1
Now we generate an update based on this select as outlined in the link provided above...
UPDATE table3
INNER JOIN (
SSELECT t1.ID t1ID, t2.id t2ID
FROM table1 t1
CROSS JOIN table2
WHERE t1.name like '%abc%'
and t2.name like = 'mno') B
on B.t1ID = t3.Id
and B.t2ID = T3.ID2
SET value = 0
Giving us a result of
Id Id2 Value
1 4 0
2 3 1
3 4 0
if we select * from table3
update t3
set t3.Value = 0
from Table3 t3
inner join Table1 t1
on t3.Id = t1.Id
inner join Table2 t2
on t3.Id2 = t2.Id2
where t1.Name like '%abc%' and t2.Name2 = 'mno'
OR
update Table3
set value = 0
where Id in (select Id from Table1 where Name like '%abc%')
and Id2 in (select Id2 from Table2 where Name2 = 'mno')
You should think about UPDATE ... WHERE EXISTS as follows:
update Table3 set Value = 0
WHERE EXISTS (SELECT 1 FROM Table1 where Name LIKE '%abc%' AND Table1.Id=Table3.Id )
AND EXISTS (SELECT 1 FROM Table2 where Name2 = "mno" AND Table2.Id2=Table3.Id2)

Return items present in one MySQL table that are not present in the other with 2 columns to consider

I want to return all the postcodes in table1 that are active and that dont have any items in table2 that share the same coordinates (lat,lng).
I.e. in the below return :
AB11AC
I know there are several method where you are just checking one column, but not sure how to adapt for 2 columns. Should I just concatenate the 2 columns together in the query or is there a more efficient method? My tables each have around 2 million entries.
table1:
postcode lat lng active
-------------------------
AB11AA 55 1 Y
AB11AB 56 1 Y
AB11AC 57 1 Y
table2:
postcode lat lng active
--------------------------
AB11AA 55 1 Y
AB11AD 56 1 Y
AB11AE 59 1 Y
You can use a LEFT JOIN:
select *
from table1 t1
left join table2 t2
on t1.lat = t2.lat
and t1.lng = t2.lng
where t1.active = 'Y'
and t2.postcode is null
See SQL Fiddle with Demo
Or you can use a NOT EXISTS in the WHERE clause:
select *
from table1 t1
where t1.active = 'Y'
and not exists (select *
from table2 t2
where t1.lat = t2.lat
and t1.lng = t2.lng)
See SQL Fiddle with Demo