Laden...

SQL-Befehl: Zeile löschen

Erstellt von webstarg vor 16 Jahren Letzter Beitrag vor 16 Jahren 2.306 Views
W
webstarg Themenstarter:in
558 Beiträge seit 2006
vor 16 Jahren
SQL-Befehl: Zeile löschen

Hallo!

In der Schule üben wir gerade die SQL-Sprache und fügen mit Inserts Daten in die Tabellen ein. Habe ich jedoch keinen Primärschlüssel und drücke ich den Absenden-Knopf aus Versehen doppelt (oder öfter 😉), habe ich diese Insert-Daten doppelt in meiner Tabelle. (Natürlich könnte ich einen Primärschlüssel erstellen; wir sollen einen solchen aber in diesen Beispielen nicht verwenden.) Um doppelte Tupeln zu entfernen, könnte ich diese Zeilen mit Delete löschen und neu eingeben.
Sicher geht das aber auch einfacher (und schneller), nehme ich an.

DELETE FROM [Tabellenname] WHERE [Spaltenname] = [Kriterium] AND FIRST??????

Ich würde also gerne wissen, wie man n mal vorhandene gleiche Zeilen n - 1 mal löscht? Das ist doch möglich oder?

Danke im Voraus
Grüße
webstarg

328 Beiträge seit 2006
vor 16 Jahren

[...] Ich würde also gerne wissen, wie man n mal vorhandene gleiche Zeilen n - 1 mal löscht? Das ist doch möglich oder? [...]

Ohne Primärschlüssel? Nein, das ist nicht möglich.

Robert Wachtel

http://blog.robertsoft.de

21 Beiträge seit 2006
vor 16 Jahren

hi
es ist zwar nicht wirklich performant bei riesigen datenquellen, aber was du machen könntest ist folgendes

  1. erstelle eine neue temptabelle, wo die werte nur einmalig gespeichert sind
    select distinct * into #newTemptable from table

2)die alte tabelle löschen
delete from table

3)die werte von der temptabelle wieder zurückkopieren
insert into table
select * from #newtempTable

viel spaß

84 Beiträge seit 2008
vor 16 Jahren

Warum so kompliziert?
Habs auch das grad mal ausprobiert und hat geklappt:


DELETE TOP (1) [Tabellenname] WHERE [Spaltenname] = [Kriterium]

Vielleicht klappts bei dir ja auch. Gruß!

21 Beiträge seit 2006
vor 16 Jahren

weil bei deiner lösung du jeden doppelten wert zuerst finden müsstest... bei meinem vorschlag wird alles durch die 3 commands gelöst... egal wieviele doppelte die tabelle enthält

84 Beiträge seit 2008
vor 16 Jahren

Stimmt schon, dass der Befehl so oft ausgeführt werden müsste, aber die "1" kann man auch gegen ein "SELECT COUNT(*) ..." oder eine Variable ersetzen:



DELETE TOP (SELECT COUNT(*)-1 FROM [Tabellenname] WHERE [Spaltenname] = [Kriterium])
[Tabellenname]
WHERE [Spaltenname] = [Kriterium]


Nun der große Unterschied zu deiner Lösung ist, dass bei dir die komplette Tabelle von Doppelungen befreit wird. Bei meiner ist das nur für ein bestimmtes Kriterium. 🙂

W
webstarg Themenstarter:in
558 Beiträge seit 2006
vor 16 Jahren

Jou, danke, werd ich ausprobieren

webstarg

W
webstarg Themenstarter:in
558 Beiträge seit 2006
vor 16 Jahren

Nein, es funktioniert leider nicht.

Zunächst zeigt er Syntaxfehler in DELETE-Anweisung an.

Dann habe ich den Befehl etwas umgebaut; dieser lässt den einen Datensatz nicht übrig:

DELETE FROM test WHERE TOP (SELECT COUNT(*)-1 FROM test WHERE a = "a001") and a = "a001";

mfg
webstarg

476 Beiträge seit 2004
vor 16 Jahren

hallo webstarg,

  
DELETE TOP (SELECT COUNT(*)-1 FROM [Tabellenname] WHERE [Spaltenname] = [Kriterium])  
[Tabellenname]  
WHERE [Spaltenname] = [Kriterium]  
  

funktioniert. Schau mal ob du nicht einen Tippfehler gemacht hast.

-yellow

Selbst ein Weg von tausend Meilen beginnt mit einem Schritt (chinesisches Sprichwort).

Mein Blog: Yellow's Blog auf sqlgut.de

W
webstarg Themenstarter:in
558 Beiträge seit 2006
vor 16 Jahren

... bei mir nicht.

(OleDb, Access-Datenbank)

Angewandter Code:

DELETE TOP (SELECT COUNT(*)-1 FROM test2 WHERE a = "d") test2 WHERE a = "d";
Syntaxfehler in DELETE-Anweisung

Mir kommt auch der Syntax nicht ganz logisch vor. Wieso kommt nach DELETE TOP (...) eigentlich kein "FROM"; aber auch mit funktioniert es nicht.

mfg
webstarg

476 Beiträge seit 2004
vor 16 Jahren

hmm webstarg,

ich hab's auf 'nem SQL Server 2005 Express Edition im Management Studio getestet, da hat es funktioniert, sowohl mit als auch ohne die FROM Anweisung.

-yellow

Selbst ein Weg von tausend Meilen beginnt mit einem Schritt (chinesisches Sprichwort).

Mein Blog: Yellow's Blog auf sqlgut.de

84 Beiträge seit 2008
vor 16 Jahren

Achso, in MS Access, wusste ich nicht genau.

Also ich hab grad rumprobiert, hier kann man auf jedenfall das folgende SQL-Statement abgeben:


SELECT TOP 1 * FROM Tabelle1

Also:


SELECT TOP [Zahl] [Spaltenname] FROM [Tabellenname] WHERE [Spaltenname] = [Kriterium]

Hier kenne ich aber nicht die genaue Syntax wenn man das in eine DELETE-Anweisung schreiben will. Vielleicht kannste es damit irgendwie zusammenbasteln.

Edit:
Hab grad was ausprobiert:


DELETE * FROM (SELECT TOP 1 * FROM Tabelle1)

Scheint zu funktionieren, aber wie man jetzt hier die 1 durch ein SELECT ersetzen kann weiß ich leider auch nicht.
Hoffe es hilft ein bisschen weiter...

476 Beiträge seit 2004
vor 16 Jahren

hallo

darum noch mal den Hinweis:

Bitte gebt zu Beginn des Threads an um welche Datenbank oder Datenbankmanagementsystem es sich handelt, SQL ist nicht immer gleich SQL wie man sieht, und so kann schneller ohne Missverständnisse geholfen werden.

-yellow

Selbst ein Weg von tausend Meilen beginnt mit einem Schritt (chinesisches Sprichwort).

Mein Blog: Yellow's Blog auf sqlgut.de

W
webstarg Themenstarter:in
558 Beiträge seit 2006
vor 16 Jahren

@ Matscher:
Danke für den Hilfeversuch: Code 1 und 2 funktionieren; 3 leider nicht: "SQL-Anweisung schließt ein reserviertes Wort oder einen Argumentnamen ein, das/der falsch, mit falscher Zeichensetzung oder überhaupt nicht eingegeben wurde"

@ Yellow:
Ja, sorry. Wollte eigentlich einen Befehl, der von MySQL && Access akzeptiert wird. Getestet habe ich diese halt nur mit Access.

mfg
webstarg

3.430 Beiträge seit 2007
vor 16 Jahren

Hallo webstarg,

du könntest ja auch schon beim Eintragen der Daten kontrollieren, ob diese schon vorhanden sind.

z.B.

SELECT COUNT(*) FROM myTable WHERE name="d";

Wenn schon ein Datensatz mit dem gleichen Namen vorhanden ist, so kannst du dem Benutzer ein MessageBox ausgeben, welche ihn das Meldet.

Ist noch kein Datensatz mit diesem Namen vorhanden, so kannst du Ihn dann einfach eintragen.

EDIT: ups, ich habe erst gerade gesehen, dass ihr die Daten da direkt als Querys einfügt (also ohne Anwendung)

mfg
MichlG

84 Beiträge seit 2008
vor 16 Jahren

Ähm... also auch der dritte Code sollte stimmen, weiß ja nicht. Kann das mal jemand anderes ausprobieren?

Ich hab das jetzt mit Access 2003 und 2007 ausprobiert. Klappt.

Wie gesagt, ich weiß nicht wie man statt eine Zahl eine SQL-Kommando bei Access einfügt. Falls du das jetzt ausprobiert haben solltest...

W
webstarg Themenstarter:in
558 Beiträge seit 2006
vor 16 Jahren

Ich hab das jetzt mit Access 2003 und 2007 ausprobiert. Klappt.

Hm. Komisch. Ich verwende eine selbstgeschriebene Anwendung, die mit OleDb auf die Datenbank zugreift.

mfg
webstarg

84 Beiträge seit 2008
vor 16 Jahren

Also, hab das ganze mal in ein miniprogramm eingebaut:

Hab da mal ne kleine Klasse zusammengebastelt.
Mit der das möglich ist, wichtig für dich ist hier die Funktion "DeleteTop":



using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.OleDb;

namespace TestOle {
	class AccessConnection {
		private OleDbConnection cn;
		private OleDbCommand cmd;

		public AccessConnection(string mdbFile) {
			this.cmd = new OleDbCommand();
			this.cn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + mdbFile + ";");
			this.cn.Open();
			this.cmd.Connection = this.cn;
		}
		
		public void CreateTable(string tableName, string[] columns) {
			try {
				this.cmd.CommandText = "CREATE TABLE " + tableName + "(";
				
				for(int i=0; i<columns.Length; i++) {
					this.cmd.CommandText += columns[i];
					if (i + 1 < columns.Length)
						this.cmd.CommandText += ", ";
				}

				this.cmd.CommandText += ");";
				this.cmd.ExecuteNonQuery();
			} catch (Exception err) {
				Console.WriteLine(err.Message);
			}
		}

		public void InsertInto(string tableName, string values, int multi) {
			for (int i = 0; i < multi; i++)
				this.InsertInto(tableName, values);
		}

		public void InsertInto(string tableName, string values) {
			try {
				this.cmd.CommandText = "INSERT INTO " + tableName + " VALUES(" + values + ")";
				this.cmd.ExecuteNonQuery();
			} catch (Exception err) {
				Console.WriteLine(err.Message);
			}
		}

		public int Count(string table, string filterExpr) {
			try {
				OleDbDataReader reader = null;

				this.cmd.CommandText = "SELECT COUNT(*) FROM " + table + " WHERE " + filterExpr;

				reader = this.cmd.ExecuteReader();

				reader.Read();
				int result = reader.GetInt32(0);
				reader.Close();
				return result;
			} catch (Exception err) {
				Console.WriteLine(err.Message);
				return -1;
			}
		}

		public void DeleteTop(string tableName, string filterExpr, int num) {
			try {
				this.cmd.CommandText = "DELETE * FROM (SELECT TOP " + num + " * FROM " + tableName + " WHERE " + filterExpr + ")";

				this.cmd.ExecuteNonQuery();
			} catch (Exception err) {
				Console.WriteLine(err.Message);
			}
		}
	}
}


Das ganze dann mit folgendermaßen aufrufen:


	AccessConnection access = new AccessConnection("C:\\Temp\\testDb.mdb");

	string[] list = new string[2];
	list[0] = "NPID INT NOT NULL";
	list[1] = "NDesc CHAR(150) NOT NULL";

	access.CreateTable("NoPrimary", list);

	access.InsertInto("NoPrimary", "1, 'Eins'", 10);
	access.InsertInto("NoPrimary", "2, 'Zwei'", 5);

	int sum1 = access.Count("NoPrimary", "NPID = 1");
	int sum2 = access.Count("NoPrimary", "NPID = 2");

	access.DeleteTop("NoPrimary", "NPID = 1", sum1 - 1);
	access.DeleteTop("NoPrimary", "NPID = 2", sum2 - 1);

Müsste klappen, wie gesagt, schau dir mal die Funktion DeleteTop an. Sollte eigentlich funktionieren.