2009-07-23 12 views
2

Vor vielen Jahren wurde ich während eines Telefoninterviews gebeten, doppelte Zeilen in einer Datenbank zu löschen. mehrere Lösungen Nachdem er die Arbeit zu tun, wurde mir gesagt, schließlich die Beschränkungen sind:Löschen doppelter Zeilen in einer Datenbank ohne Rowid oder Erstellen einer temporären Tabelle

  • Angenommen Tabelle eine VARCHAR-Spalte hat
  • Kann nicht verwenden Rowid
  • nicht nur vorübergehend verwenden können Tabellen

Der Interviewer verweigert um mir die Antwort zu geben. Seitdem bin ich ratlos.

Nachdem ich einige Kollegen über die Jahre gefragt habe, bin ich überzeugt, dass es keine Lösung gibt. Liege ich falsch?!

+4

Ugh. Vertrau mir. Du willst diesen Job sowieso nicht. Eine Frage, bei der man sich die Hände hinter den Rücken bindet, soll eher zeigen, wie schlau der Interviewer den Kandidaten nicht testet. – JohnFx

+0

Danke, JohnFx, für die Unterstützung ... macht mich glücklicher Ich habe diesen Job nicht verfolgt. –

+1

Das letzte, was Sie wollen, ist ein Chef, der keine Lösung will, er/sie will IHRE Lösung. Es ist ein Anfänger Manager Fehler und sehr narzisstisch zu versuchen, Klone von sich einzustellen. – JohnFx

Antwort

0

Ich würde eine eindeutige Anzahl von festen Größe in der VARCHAR-Spalte für die duplizierten Zeilen, dann analysieren Sie die Anzahl und löschen Sie alle bis auf die minimale Zeile. Vielleicht ist das seine VARCHAR-Einschränkung. Aber das stinkt, weil es annimmt, dass Ihre eindeutige Nummer passt. Lahme Frage. Du wolltest sowieso nicht dort arbeiten. ;-)

+0

$ chars = Array ('L', 'O'); while (1 = 1) {echo $ chars [0]; echo $ chars [1];} echo $ chars [0]; –

1

Dies ist ein völlig aufgebockt Weg, es zu tun, aber die assanine Anforderungen gegeben, hier eine praktikable Lösung ist SQL 2005 unter der Annahme oder später:

DELETE from MyTable 
    WHERE ROW_NUMBER() over(PARTITION BY [MyField] order by MyField)>1 
+0

Interessant - klingt wie row_number() ist nur sehr ähnlich wie rowid –

+0

@ vh row_number() ist Oracle ROWNUM ähnlicher als Oracles ROWID, aber viel flexibler. Oracle hat auch ROW_NUMBER(). Es ist Teil der analytischen Funktionen. Oh, und das wird in SQL Server 2005/2008 nicht funktionieren, da ROW_NUMBER() in der WHERE-Klausel nicht zulässig ist. –

+0

Ack! Du hast recht. Ich schwöre, das hat gestern funktioniert, als ich es getestet habe, aber leider funktioniert es heute Morgen nicht. Entschuldige die falsche Hoffnung. Auch habe ich gerade die NoRowID-Einschränkung bemerkt, so dass dies wahrscheinlich den Geist der Begriffe verletzt. Ich sage, Sie sollten nur den Interviewer in Frage stellen, wie er eine Abfrage schreiben würde, um dies ohne Tastatur oder Maus zu tun. Es ist ungefähr so ​​unsinnig. – JohnFx

2

Und wenn Sie eine Antwort haben, Würde sich plötzlich eine neue Beschränkung ergeben? Da Sie ROWID erwähnen, nehme ich an, dass Sie Oracle verwendet haben. Die Lösungen sind für SQL Server.

von SQLServerCentral.com Inspired http://www.sqlservercentral.com/scripts/T-SQL/62866/

while(1=1) begin 
    delete top (1) 
    from MyTable 
    where VarcharColumn in 
    (select VarcharColumn 
    from MyTable 
    group by VarcharColumn 
    having count(*) > 1) 

    if @@rowcount = 0 
     exit 
end 

Löscht zu einem Zeitpunkt eine Zeile. Wenn die vorletzte Reihe einer Reihe von Duplikaten verschwindet, befindet sich die verbleibende Reihe nicht mehr in der Unterauswahl beim nächsten Durchgang durch die Schleife. (BIG Yuck!)

Siehe auch http://www.sqlservercentral.com/articles/T-SQL/63578/ für Inspiration. Dort schlägt RBarry Young einen Weg vor, der modifiziert werden könnte, um die deduplizierten Daten in der gleichen Tabelle zu speichern, alle ursprünglichen Zeilen zu löschen und dann die gespeicherten deduplizierten Daten wieder in das richtige Format zu konvertieren. Er hatte drei Spalten, also nicht genau analog zu dem, was Sie tun.

Und dann könnte es mit einem Cursor möglich sein. Nicht sicher und habe keine Zeit, nachzusehen. Aber erstellen Sie einen Cursor, um alles aus der Tabelle in der Reihenfolge auszuwählen, und dann eine Variable, um zu verfolgen, wie die letzte Zeile aussah. Wenn die aktuelle Zeile identisch ist, lösche, sonst setze die Variable auf die aktuelle Zeile.

+0

Du hast Recht ... großer Yuck zu dieser While-Schleife. Sie haben auch Recht, dass eine neue Einschränkung angezeigt wurde, als ich die Verwendung eines PL/SQL-Verfahrens vorschlug. Er wollte es nur mit einer DELETE-Anweisung machen. –

+0

Hey, das bin ich! Und zu guter Letzt, die Technik, die ich in meinem Artikel * verwendet habe, wird auch an einer einzigen VARCHAR-Spalte arbeiten, solange sie noch nicht überall ausgereizt ist. Oh, und das ist ohne Schleifen oder Cursor (die es leicht machen) und * auch * SQL 2000 kompatibel, also keine Row_Number() -Funktion entweder. Und ja, es ist * verdammt * hart, aber es kann getan werden. – RBarryYoung

0

Angenommen, Sie implementieren die DELETE-Anweisung für eine SQL-Engine. Wie löschst du zwei Zeilen aus einer Tabelle, die genau identisch sind? Du brauchst etwas, um das eine vom anderen zu unterscheiden! Sie können tatsächlich löschen nicht vollständig doppelte Zeilen unter den folgenden Bedingungen (alle Spalten gleich sind) (als zur Verfügung gestellt)

  1. Keine Verwendung von ROWID oder ROWNUM
  2. keine temporäre Tabelle
  3. Keine prozeduralen Code

Es kann jedoch auch getan werden, wenn eine der Bedingungen entspannt ist.Hier sind unter Verwendung von Lösungen, die mindestens eine der drei Bedingungen

Tabelle sei angenommen, ist definiert als unterhalb

Erstellen Tabelle T1 (
spalte1 vacrchar2 (100),
Col2 Nummer (5),
col3 Nummer (2)
);

Doppelte Zeilen Identifizierung:

Select Sp1, Sp2, col3
von t1
Gruppe von Sp1, Sp2, col3
mit COUNT (*)> 1

Duplizieren Zeilen können auch identifiziert werden mit dieser: wählen Sie c1, c2, c3, row_number() über (Partition von (c1, c2, c3) Reihenfolge von c1, c2, c3) rn
von t1

HINWEIS: Die analytische Funktion row_number() kann nicht in einer DELETE-Anweisung verwendet werden, wie von JohnFx zumindest in Oracle 10g vorgeschlagen.

  • Lösung mit ROWID

von t1 streichen row_id>
(select min (t1_inner.row_id) von t1 t1_innner
wo t1_inner.c1 = t1.c1 und t1_inner.c2 = t1.c2 und t1_inner.c3 = t1.c3))

  • Lösung mit Temptabelle

Tabelle t1_dups erstellen, wie (012.350.952 hier // Schreibabfrage die doppelten Zeilen als liste oben //
)

löschen von t1
wo t1.c1, t1.c2, t1.c3 in (select * from t1.dups zu finden)
INSERT INTO t1 (
select c1, c2, c3 aus t1_dups)

  • Lösung prozeduralen Code

Dies wird einen Ansatz ähnlich dem Fall verwenden, in dem wir eine temporäre Tabelle verwenden.

0
create table temp as 
select c1,c2 
from table 
group by c1,c2 
having(count(*)>1 or count(*)=1); 

Legen Sie jetzt die Basistabelle ab. Benennen Sie die temporäre Tabelle in Basistabelle um.

Verwandte Themen