MySQL删除除了一个

时间:2012-07-11 21:03:46

标签: mysql sql

我有以下数据库结构:

id   idproperty    idgbs
 1    1             136
 2    1             128       
 3    1             10
 4    1             1
 5    2             136
 6    2             128
 7    2             10
 8    2             1
 9    3             561
10    3             560
11    3             10
12    3             1
13    4             561
14    4             560
15    4             10
16    4             1
17    5             234
18    5             120
19    5             1
20    6             234
21    6             120
22    6             1

以下是详细信息:

该表引用idproperty具有不同的地理位置。例如:

idgbs

  1 refers to United States
 10 refers to Alabama with parentid 1 (United States)
128 refers to Alabama Gulf Coast with parentid 10 (Alabama)
136 Dauphin Island with parentid 128 (Alabama Gulf Coast)

所以,结构是:

United States > Alabama > Alabama Gulf Coast > Dauphin Island

我想删除idproperty的所有条目除了第一个带有idgbs 136,128,10,1的集合,即在所有GBS中保留至少1个属性并删除其他属性。

此外,有时它是4级地理条目,有时它是3级。

请分享逻辑& SQL查询删除除每个唯一GBS中的条目之外的所有条目。

GBS 1,10,128,136是一个唯一的,因此数据库应该只包含1个带有这些GBS的属性ID。

查询后,表格如下所示:

id   idproperty    idgbs
 1    1             136
 2    1             128       
 3    1             10
 4    1             1
 9    3             561
10    3             560
11    3             10
12    3             1
17    5             234
18    5             120
19    5             1

改述这个问题:

我想在每个根级别GBS中保留属性,即在多芬岛应该只有一个属性。

4 个答案:

答案 0 :(得分:3)

哇...我想我明白你现在的样子。我不能让这一个去; - )

我必须意识到,在这个问题中,你想要删除属性2,因为它与属性1共享一个层次结构。一旦我意识到这一点,我得到了以下想法。基本上,我们加入self的聚合版本两次:第一个告诉我们“gbs层次结构路径”是什么,第二个匹配任何之前的属性与相同层次结构。发现没有共享其层次结构的“先前”属性的行将被删除,其余的具有该层次结构将被删除。这可能会进一步调整,但我现在想分享这个。我已经使用您显示的数据对其进行了测试,并且我得到了您发布的结果。

DELETE 
  each_row.*
FROM property_gbs AS each_row

JOIN ( SELECT 
         idproperty, 
         GROUP_CONCAT(idgbs ORDER BY idgbs DESC SEPARATOR "/") AS idgbs_path 
       FROM property_gbs 
       GROUP BY idproperty
     ) AS mypath 
     USING(idproperty)

LEFT JOIN ( SELECT 
              idproperty, 
              GROUP_CONCAT(idgbs ORDER BY idgbs DESC SEPARATOR "/") AS idgbs_path 
            FROM property_gbs  
            GROUP BY idproperty
          ) AS previous_property 
      ON mypath.idgbs_path = previous_property.idgbs_path 
  AND previous_property.idproperty < each_row.idproperty

WHERE previous_property.idproperty

请注意,最后一行不是拼写错误,我们只是检查是否存在具有相同路径的先前属性。如果有,则删除当前评估的行。

干杯!

请注意以澄清

这里的想法是将每一行与它的层次结构相关联,即使它是一个代表层次结构中间某处的行(例如问题中的行:{2,1,128})。第一次加入聚合时,每一行现在“知道”它的路径是什么(因此该行将获得“136/128/10/1”)。然后,我们可以在第二个连接中使用该值来查找具有相同路径的其他属性,但前提是它们具有LOWER属性id。这允许我们检查是否存在具有相同“路径”的低ID属性,并删除代表具有这样的“低阶路径 - 兄弟”属性的任何行。

答案 1 :(得分:2)

我真的不确定。但试试这个。

DELETE a1 FROM table a1, table a2 
WHERE a1.id > a2.id 
AND a1.idgbs = a2.idgbs 
AND a1.idgbs <> 1

如果你想让行保持最低的id。

答案 2 :(得分:2)

这个很难@dang,但我很享受这个挑战。

;With [CTE] as (Select id ,idproperty ,idgbs ,Row_Number() Over(Partition By idgbs order by idproperty Asc) as RN From [TableGBS])
,[CTE2] as (Select * From [CTE] Where RN > 1)
,[CTE3] as (Select idproperty ,count(*) as [Count] From [CTE2] Group by idproperty)
Delete from [TableGBS] Where id in (Select a.id From [CTE] as a Left Join [CTE3] as b on a.idproperty = b.idproperty Where RN > 1 And [Count] > 2);

因为我不认为你可以在sqlfiddle中执行删除语句,所以它将删除的行显示在select语句中:http://sqlfiddle.com/#!3/08108/40

编辑:我使用链接到Microsoft SQL Server Management Studio的MySQL,因此这可能不适合您

答案 3 :(得分:0)

这种技术将表与其自身的聚合版本连接起来,基本上将表中的每一行与idproperty最低的知识相匹配,如果它不共享该idproperty,则删除该行(即行具有最低idproperty,当连接到自身时,将不会被删除,但具有该idgbs的其余行将会被删除。

DELETE 
  each_row.*
FROM table AS each_row
  JOIN (select MIN(idproperty), idgbs FROM table GROUP BY idgbs) as lowest_id
  USING(idgbs)
WHERE each_row.idproperty != lowest_id.idproperty;