`numrows`/`rowcount` sollte auch überflüssig sein, denn `result` hat ja eine Länge, die man abfragen kann.
Allerdings nicht sollte, denn die ``while``-Schleife ist auch fehl am Platz. Man kann über das/die Ergebnisse auch direkt iterieren, ohne Index.
Namen durchnummerieren ist ein "code smell". Man sollte nicht den Typ als Namen nehmen, wenn es passendere Bezeichner gibt, die den Inhalt oder die Bedeutung besser wiederspiegeln. Hier zum Beispiel `names` und `urls`. `zahl` ist auch übel.
Man braucht auch nicht für jede Abfrage da einen neuen `Cursor`. Letztendlich reicht Einer der beide Daten auf einmal abfragt -- wie /me ja schon anmerkte -- und eine ``for``-Schleife über das Ergebnis.
Was das angesproche Problem angeht: `url` wird aufgelöst, wenn der Code *ausgeführt* wird, und zu *dem* Zeitpunkt ist die Schleife bereits durchgelaufen und `url` eben an den letzten Wert gebunden, den man da mal zugewiesen hatte.
Du suchst `functools.partial()` um Dir eine Funktion aus `open()` und dem Argument zu basteln.
Mit all den Hinweisen kann man Deinen Quelltext auf das hier eindampfen (ungetestet):
Code: Alles auswählen
cursor = mysql.cursor()
cursor.execute('SELECT name, url FROM eventkalender')
for name, url in cursor.fetchall():
Button(root, text=name, command=partial(open, url)).pack()
Der Code sieht verdammt nach '*'-Importen aus. Das sollte man auch lassen.