myCSharp.de - DIE C# und .NET Community
Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 
 | Suche | FAQ

» Hauptmenü
myCSharp.de
» Startseite
» Forum
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Suche
   » Plugin für Firefox
   » Plugin für IE
   » Gadget für Windows
» Regeln
» Wie poste ich richtig?
» Datenschutzerklärung
» wbb-FAQ

Mitglieder
» Liste / Suche
» Stadt / Anleitung dazu
» Wer ist wo online?

Angebote
» ASP.NET Webspace
» Bücher
» Zeitschriften
   » dot.net magazin
» Accessoires

Ressourcen
» .NET-Glossar
» guide to C#
» openbook: Visual C#
» openbook: OO
» .NET BlogBook
» MSDN Webcasts
» Search.Net

Team
» Kontakt
» Übersicht
» Wir über uns
» Bankverbindung
» Impressum

» Unsere MiniCity
MiniCity
» myCSharp.de Diskussionsforum
Du befindest Dich hier: Community-Index » Diskussionsforum » Entwicklung » Datentechnologien » Letzte belegte / nächste freie ID ermitteln
Letzter Beitrag | Erster ungelesener Beitrag Druckvorschau | An Freund senden | Thema zu Favoriten hinzufügen

Antwort erstellen
Zum Ende der Seite springen  

Letzte belegte / nächste freie ID ermitteln

 
Autor
Beitrag « Vorheriges Thema | Nächstes Thema »
rebbi rebbi ist männlich
myCSharp.de-Mitglied

Dabei seit: 19.08.2008
Beiträge: 49
Entwicklungsumgebung: Visual C#


rebbi ist offline

Letzte belegte / nächste freie ID ermitteln

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

[EDIT=herbivore]Abgeteilt von  Zahl erhöhen (Sonderformat?)[EDIT]

Grüß Euch,

das nächste Problem, bei dem ich häng:


Ich muss meine ID (String, bestehend aus DateTime und Counter, also im Format yymmddxxxx) bei jedem neuen Eintrag erhöhen, AutoIncrement geht natürlich aufgrund des String-Typs nicht.


Wie les ich jetzt aus der Datenbank immer den letzten Wert aus?

Bisher hab ich das per DataTable geregelt, aber auf die Dauer ist die Performance zu schlecht, wenn ich jedesmal nur zum auslesen der letzten ID die komplette DataTable lokal speichern muss ...


Hab schon

- "SELECT LAST(Identnumber) FROM table1"
- "SELECT MAX (Identnumber) FROM table1"

probiert. Funktionierten nicht.

- cmd.LastInsertedID gibt mir 0 zurück, was beim erstmaligen Start meiner Anwendung auch logisch ist. Nun soll mein Programm zwar im Dauerbetrieb laufen, aber wenns doch mal neugestartet werden muss wären die folgenden IDs ja wieder falsch.

- "SELECT COUNT(*) FROM table1" bringt auch nix, da ich dann zwar die Anzahl der Datensätze habe, aber in der Where-Klausel eben die ID angeben müsste, die ich ja suche. großes Grinsen



Mein allerletzter Ansatz wäre, eine extra AutoIncrement-Spalte in die Datenbank mit aufzunehmen und dann über diese die Daten anzusteuern ... ist aber bisschen umständlich, desweiteren hätte ich dann in einer Tabelle 2 Primary Keys ("meine" ID sowie die AI-ID). Das ist sicher auch nicht das allerbeste, soferns überhaupt geht.


Weiß einer Rat? smile


mfG Andi

Dieser Beitrag wurde 3 mal editiert, zum letzten Mal von rebbi am 15.10.2008 14:57.

30.09.2008 10:12 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Programmierhans
myCSharp.de-Poweruser/ Experte

images/avatars/avatar-1651.gif


Dabei seit: 05.04.2005
Beiträge: 4.155
Entwicklungsumgebung: VS / Mono (IOS/LINUX)
Herkunft: Zentralschweiz


Programmierhans ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

SELECT TOP1 FROM.... ORDER BY ... DESC wäre wohl geschickter als die ganze Tabelle auszulesen...
30.09.2008 10:15 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
rebbi rebbi ist männlich
myCSharp.de-Mitglied

Dabei seit: 19.08.2008
Beiträge: 49
Entwicklungsumgebung: Visual C#

Themenstarter Thema begonnen von rebbi

rebbi ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Bin selbst drauf gekommen, funktioniert wunderbar:

C#-Code:
string strSelectLastID = "SELECT COUNT(*) FROM table1";
            MySqlCommand cmdSelect = new MySqlCommand(strSelectLastID, conn);
            conn.Open();
            int a = Convert.ToInt32(cmdSelect.ExecuteScalar())-1;
            string strSelectLastID2 = "SELECT Identnumber FROM table1 LIMIT " + a + ",1";
            MySqlCommand cmdSelect2 = new MySqlCommand(strSelectLastID2, conn);
            string erg = Convert.ToString(cmdSelect2.ExecuteScalar());
            string strSQL = "INSERT INTO table1 (Identnumber, Timestamp, Type, PRG_NR, PRG_RUNTIME, MIXINGRATIO, BOOTH_TEMPERATURE," +
                " BOOTH_HUMIDITY, ERROR) Values (?id, ?ts, ?type, ?nr, ?runtime, ?ratio, ?temp, ?humidity, ?error)";
            MySqlCommand cmd = new MySqlCommand(strSQL, conn);
            string datetime = DateTime.Now.ToString("yyMMdd");
            string ergChanged = erg.Substring(6, 4);
            string id = datetime + (int.Parse(ergChanged) + 1).ToString(@"0000");
            conn.Close();

Zuerst hol ich die Gesamtanzahl der Datensätze und zieh eins ab. Mit Hilfe des LIMIT-Befehls kann ich dann den letzten Eintrag auswählen.
Ein simpler Befehl, den ich aber nicht kannte bzw. durch Zufall nach ewigem Suchen in einem Flashforum gefunden hatte ... smile
30.09.2008 10:16 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
haarrrgh haarrrgh ist männlich
myCSharp.de-Mitglied

images/avatars/avatar-3254.jpg


Dabei seit: 03.06.2008
Beiträge: 208
Entwicklungsumgebung: Access 2003 / VS 2010 Prof.
Herkunft: Raum Köln


haarrrgh ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Sowohl für solche "Sonder"-IDs wie in Deinem Beispiel als auch für fortlaufende Zahlen für die sich ein normaler Autoincrement trotzdem nicht eignet (in meinem Fall: Aufträge mit verschiedenen Nummernkreisen die jeweils in sich fortlaufend sein müssen, aber alle zusammen in einer Tabelle stehen weil sie identisch aufgebaut sind) benutze ich immer eine separate "Zählertabelle":

2 Spalten, eine für den Typ (Primärschlüssel) und eine für die ID.
Dazu eine Funktion die den Typ übergeben bekommt (damit man mehrere verschiedene Zähler in der gleichen Tabelle speichern kann) und dann folgendes macht:
  • den einen Datensatz mit diesem Typ suchen
  • ID in der Tabelle um 1 erhöhen
  • diese gerade veränderte ID lesen & zurückgeben
Das ist auf jeden Fall nochmal eine ganze Ecke schneller als Deine Lösung weil diese Zählertabelle im besten Fall nur einen einzigen, maximal einige wenige Datensätze enthält (im Gegensatz zu der stetig steigenden Anzahl Datensätze in Deiner eigentlichen Datentabelle).

Außerdem (aber das ist nur ein netter Nebeneffekt, der erste Vorteil ist der gravierendere) sparst Du Dir den Aufwand, die fortlaufende Nummer erstmal aus dem ganzen Schlüssel extrahieren zu müssen.
01.10.2008 00:42 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
kleines_eichhoernchen kleines_eichhoernchen ist männlich
myCSharp.de-Poweruser/ Experte

images/avatars/avatar-2079.jpg


Dabei seit: 07.11.2006
Beiträge: 3.971
Entwicklungsumgebung: Visual Studio 2005 (C#)
Herkunft: Ursprünglich Vogtland, jetzt Much


kleines_eichhoernchen ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo Rebbi,
eventuell wäre auch  Nächste Id herausfinden was fü dich
01.10.2008 08:06 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
haarrrgh haarrrgh ist männlich
myCSharp.de-Mitglied

images/avatars/avatar-3254.jpg


Dabei seit: 03.06.2008
Beiträge: 208
Entwicklungsumgebung: Access 2003 / VS 2010 Prof.
Herkunft: Raum Köln


haarrrgh ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Das ist ja genau das, was ich gesagt habe...nur halt mit fertigem Codebeispiel großes Grinsen
01.10.2008 08:36 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
rebbi rebbi ist männlich
myCSharp.de-Mitglied

Dabei seit: 19.08.2008
Beiträge: 49
Entwicklungsumgebung: Visual C#

Themenstarter Thema begonnen von rebbi

rebbi ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hey, die Antworten hier hab ich garnicht mehr bemerkt. Danke! Daumen hoch


Werd mir deine/eure Lösung jetzt mal anschauen, seit heute hab ich nämlich ein neues Problem:

Zitat:
verwendetes Datenbanksystem: <MySQL>

Folgendes Codestück liest mir meine letzte vergebene ID (yymmddxxxx) aus und ermittelt so die ID, die ich als nächstes in die Datenbank schreiben muss:

C#-Code:
public string getActualID()
        {
            try
            {
                MySqlConnection conn = new MySqlConnection("DATA SOURCE=" + Infos.databaseIP + ";DATABASE= " +
                    Infos.database + ";UID=" + Infos.uid + ";PASSWORD=" + Infos.password + "; pooling = false;");
                string counter;
                string strSelectCount = "SELECT COUNT(*) FROM " + Infos.tablename1 + ""; // Holen der Gesamtzahl der Einträge
                MySqlCommand cmdSelectCount = new MySqlCommand(strSelectCount, conn);
                conn.Open();
                int a = Convert.ToInt32(cmdSelectCount.ExecuteScalar()) -1;  // Auswählen des letzten Eintrags
                string strSelectLastID = "SELECT " + Infos.id + " FROM " + Infos.tablename1 + " LIMIT " + a + ",1";
                MySqlCommand cmdSelectLastID = new MySqlCommand(strSelectLastID, conn);
                string lastID = Convert.ToString(cmdSelectLastID.ExecuteScalar()); // Holen des letzten Eintrags
                conn.Close();
                string datetime = DateTime.Now.ToString("yyMMdd");
                int date = int.Parse(lastID.Substring(4, 2)); // Datum des letzten Eintrages
                int today = DateTime.Now.Day;
                if (!date.Equals(today))
                {
                    counter = 0.ToString(@"0000");
                    DateHasChanged.Invoke();
                }
                else
                {
                    counter = lastID.Substring(6, 4);
                }
                string id = datetime + (int.Parse(counter) + 1).ToString(@"0000");
                return id;
            }
            catch
            {
                MessageBox.Show(get_text("Error! SQL-Server may be down! Please restart SQL-Server and the Watchdog!"));
                Thread.CurrentThread.Abort();
                return "-1";
            }
        }

Das hat bisher auch super hingehauen. Jetzt auf einmal liest er aber die letzte ID nicht mehr richtig aus.

Er liest 1mal oder 2mal die ID richtig aus und vergibt so die neue richtig. Dann aber "ignoriert" er auf einmal den letzten Eintrag und bekommt bei

C#-Code:
string lastID = Convert.ToString(cmdSelectLastID.ExecuteScalar());

auf einmal den vorletzten Eintrag raus. Und ich hab keine Ahnung wieso verwundert


Hab eigentlich nicht viel geändert. Nur z.B. n Foreign Key hinzugefügt oder 1-2 neue Methoden eingebaut, was aber alles eigentlich nix mit dieser Methode zu tun hat und auch nur lesend auf die Datenbank zugreift.


Hat vielleicht von euch einer den Blick und findet das Problem? *_*

Einer ne Idee? smile
15.10.2008 11:59 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
rebbi rebbi ist männlich
myCSharp.de-Mitglied

Dabei seit: 19.08.2008
Beiträge: 49
Entwicklungsumgebung: Visual C#

Themenstarter Thema begonnen von rebbi

rebbi ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Habs gelöst und poste das für nachfolgende User wieder hier. Die neue Lösung müsste normalerweise auch das Problem umgehen, welches haarrrgh angesprochen hat (hätte wohl auf die Dauer wirklich zu langen Ladezeiten geführt).


Hab einfach die Routine

C#-Code:
string strSelectCount = "SELECT COUNT(*) FROM " + Infos.tablename1 + ""; // Holen der Gesamtzahl der Einträge
                MySqlCommand cmdSelectCount = new MySqlCommand(strSelectCount, conn);
                conn.Open();
                int a = Convert.ToInt32(cmdSelectCount.ExecuteScalar()) -1;  // Auswählen des letzten Eintrags
                string strSelectLastID = "SELECT " + Infos.id + " FROM " + Infos.tablename1 + " LIMIT " + a + ",1";
                MySqlCommand cmdSelectLastID = new MySqlCommand(strSelectLastID, conn);
                string lastID = Convert.ToString(cmdSelectLastID.ExecuteScalar()); // Holen des letzten Eintrags
                conn.Close();

durch

C#-Code:
string strSelectCount = "SELECT MAX(" + Infos.id + ") FROM " + Infos.tablename1 + "";
MySqlCommand cmdSelectCount = new MySqlCommand(strSelectCount, conn);
conn.Open();
string lastID = Convert.ToString(cmdSelectCount.ExecuteScalar()); // Holen des letzten Eintrags
conn.Close();

ersetzt.

Zu zeiten meines Eröffnungspost in diesem Thread ging MAenttäuscht id) noch nicht - jetzt tuts.

Funktioniert (bisher) reibungslos.
15.10.2008 12:58 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
haarrrgh haarrrgh ist männlich
myCSharp.de-Mitglied

images/avatars/avatar-3254.jpg


Dabei seit: 03.06.2008
Beiträge: 208
Entwicklungsumgebung: Access 2003 / VS 2010 Prof.
Herkunft: Raum Köln


haarrrgh ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Naja, das umgeht aber nicht wirklich das Problem das ich angesprochen habe.

Du hast ja im Prinzip nur Count() durch Max() ersetzt.
Du mußt aber trotzdem jedes Mal erst einen Zugriff auf Deine Tabelle mit den Echtdaten machen (die in 1 oder 2 Jahren ggf. ganz schön groß sein wird) und Du mußt trotzdem noch den String auseinanderhacken um die eigentliche ID daraus zu bekommen.

Mit meinem Lösungsvorschlag hättest Du das beides nicht, sondern Du mußt nur einen Lese- und Schreibzugriff auf eine winzige Tabelle machen (die aus 2 Spalten und im Idealfall nur einer einzigen Zeile besteht) und hast dann direkt die richtige ID, ohne sie vorher aus einem String extrahieren zu müssen.
15.10.2008 13:40 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
rebbi rebbi ist männlich
myCSharp.de-Mitglied

Dabei seit: 19.08.2008
Beiträge: 49
Entwicklungsumgebung: Visual C#

Themenstarter Thema begonnen von rebbi

rebbi ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Mhh.

Das heißt, dass ich in 1-2 Jahren sehr lange für meinen MAX-Zugriff brauch?

Dachte bei MAX wertet er nur den letzten Wert aus, anstatt die ganze Tabelle zu durchlaufen. Hab ich mich da getäuscht?

mfG Andi
15.10.2008 14:10 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
haarrrgh haarrrgh ist männlich
myCSharp.de-Mitglied

images/avatars/avatar-3254.jpg


Dabei seit: 03.06.2008
Beiträge: 208
Entwicklungsumgebung: Access 2003 / VS 2010 Prof.
Herkunft: Raum Köln


haarrrgh ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Wenn die Spalte indiziert ist, dann holt er sich den letzten Wert aus dem Index und durchläuft NICHT die ganze Tabelle. Das wäre also kein Problem.

Das dauert dann auch nicht "sehr lange", sondern trotzdem nur Sekundenbruchteile (habe gerade bei mir einen Test gemacht: MSSQL 2005, 7.5 Mio Datensätze und trotzdem rasend schnell, eben durch den Index).


Wenn viele Benutzer gleichzeitig in Deine Tabelle schreiben könnte es höchstens passieren daß 2 sich gleichzeitig den gleichen Max-Wert holen, die gleiche neue ID ermitteln und der, der erst als zweiter versucht zu schreiben eine Schlüsselverletzung bekommt.

Wenn Du aber nur ein paar Benutzer hast und/oder nicht so oft in die Tabelle geschrieben wird, dann wird Deine Lösung so wie sie jetzt ist genausogut und ohne Geschwindigkeitsprobleme funktionieren.
15.10.2008 15:21 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Baumstruktur | Brettstruktur       | Top 
myCSharp.de | Forum Der Startbeitrag ist älter als 5 Jahre.
Der letzte Beitrag ist älter als 5 Jahre.
Antwort erstellen


© Copyright 2003-2014 myCSharp.de-Team. Alle Rechte vorbehalten. 23.07.2014 23:49