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

idgbs 136、128、10、1のセットを持つ最初のエントリを除いてidpropertyのすべてのエントリを削除したい。つまり、すべてのGBSに少なくとも1つのプロパティを残し、他のエントリを削除したい。

また、地理的エントリの4レベルの場合もあれば、3レベルの場合もあります。

ロジックとSQLクエリを共有して、一意のGBSごとに1つを除くすべてのエントリを削除してください。

GBS 1、10、128、136は1つの一意であるため、データベースには、これらの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にプロパティを保持したいのですが、ドーフィン島には1つのプロパティしか存在しないはずです。

4

4 に答える 4

3

ふぅ…あなたが今何をしているのか理解できたと思います。私はこれを手放すことができませんでした;-)

質問では、プロパティ1と階層を共有しているため、プロパティ2を削除する必要があることに気づきました。それを理解すると、次のようなアイデアが浮かびました。基本的に、selfの集約バージョンに2回参加します。1つ目は「gbs階層パス」が何であるかを示し、2つ目は同じ階層を持つ以前のプロパティと一致します。階層を共有する「前の」プロパティがないことを検出した行は除外され、その階層を持つ残りの行は削除されます。これをさらに微調整することも可能ですが、ここで共有したいと思います。私はあなたが示したデータでそれをテストしました、そして私はあなたが投稿した結果を得ました。

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」になります)。次に、2番目の結合でその値を使用して、同じパスを持つ他のプロパティを検索できますが、プロパティIDが低い場合に限ります。これにより、同じ「パス」を持つ下位IDプロパティの存在を確認し、そのような「下位パス兄弟」を持つプロパティを表す行を削除できます。

于 2012-07-11T22:48:42.107 に答える
2

よくわかりません。しかし、これを試してください。

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

最も小さい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でdeleteステートメントを実行できるとは思わないので、selectステートメントに表示される削除される行は次のとおりです。http://sqlfiddle.com/#!3/08108/40

編集: Microsoft SQL Server Management StudioにリンクされたMySQLを使用しているため、これが機能しない可能性があります

于 2012-07-11T22:49:08.940 に答える
0

この手法は、テーブルをそれ自体の集約バージョンと結合し、基本的にテーブル内の各行を、そのidgbsの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; 
于 2012-07-11T21:16:45.500 に答える