3

我有以下数据库结构:

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 是唯一的,因此数据库应该只包含这些 GBS 的 1 个属性 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

4 回答 4

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”)。然后,我们可以在第二个连接中使用该值来查找具有相同路径的其他属性,但前提是它们的属性 ID 较低。这使我们能够检查是否存在具有相同“路径”的低 ID 属性,并删除表示具有此类“低阶路径兄弟”的属性的任何行。

于 2012-07-11T22:48:42.107 回答
2

I'm really not sure. But try this.

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

if you want to keep the row with the lowest id.

于 2012-07-11T21:41:44.647 回答
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,所以这可能不适合你

于 2012-07-11T22:49:08.940 回答
0

这种技术将表与自身的聚合版本连接起来,基本上将表中的每一行与哪个 idproperty 的 idgbs 最低的知识相匹配,如果它不共享该 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; 
于 2012-07-11T21:16:45.500 回答