Autor Beitrag
Csharp-programmierer
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 696
Erhaltene Danke: 10

Windows 8.1
C# (VS 2013)
BeitragVerfasst: So 30.10.16 20:34 
Hallo Forum,

in der C# Applikation ist es jetzt möglich, Freundschaftsanfragen zu versenden. Wird eine Freundschaftsanfrage versendet, wird in einer Tabelle `Freundschaftsanfragen` ein Datensatz angelegt, der in etwa so aussieht. Wenn der Benutzer, an den die FA gesendet wurde, sich einloggt, kann er diese Anfrage annehmen oder ablehnen. Nimmt er diese an, dann wird der Datensatz aus der Tabelle `Freundschaftsanfragen` gelöscht. Nun wird aber ein neuer Datensatz in die Tabelle `Freundesliste` eingetragen. Diese Tabelle sieht ungefähr so aus:

ID | One | Two |
--------------------------------
1 | User1 | User2 |
--------------------------------

Soo das funktioniert schon mal. Wenn sich jetzt User 1 einloggt, muss User2 als Freund dastehen. Aber wenn User2 sich einloggt, muss User1 als Freund auftauchen.
Wie kann man diese SQL Abfrage verallgemeinern, dass die alle Freunde von dem jeweiligen eingeloggten Benutzer ausgibt?

Mit freundlichen Grüßen :)

_________________
"Wer keinen Sinn im Leben sieht, ist nicht nur unglücklich, sondern kaum lebensfähig" - Albert Einstein
Frühlingsrolle
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2105
Erhaltene Danke: 385

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: So 30.10.16 21:08 
Guten Abend Csharp-programmierer,

so kann es nur funktionieren, wenn auch nur immer eine Person mit NUR einer Person befreundet bleibt. Wenn ein neuer Freund hinzukommt, müsste jedes Mal eine Spalte erstellt werden. Wenn jede Person unterschiedlich viele Freunde hat, werden daraus unterschiedlich viele Spalten. Das ist nicht besonders handlich.
Das wäre so ein Fall für die Anwendung eines Fremdschlüssels.

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
Csharp-programmierer Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 696
Erhaltene Danke: 10

Windows 8.1
C# (VS 2013)
BeitragVerfasst: So 30.10.16 21:31 
Oder man erzeugt pro Freundschaft 2 Datensätze. Beispielsweise so:

ID | UserEingeloggt | UserAnderer |
-------------------------------------------------------
1 | Cshrp-programmierer | User2 |
-------------------------------------------------------
2 | User2 | Csharp-programmierer |
-------------------------------------------------------

Dann könnte man diese Abfrage durchführen:
ausblenden SQL-Anweisung
1:
SELECT * FROM `Freundschaften` WHERE `UserEingeloggt`=VALUE					


Aber dann würde ja mein 80 GB Webspace Speicher sicher irgendwann überlasten :(

_________________
"Wer keinen Sinn im Leben sieht, ist nicht nur unglücklich, sondern kaum lebensfähig" - Albert Einstein
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Chefentwickler
Beiträge: 20285
Erhaltene Danke: 2078

Win 10
C# (VS 2017)
BeitragVerfasst: So 30.10.16 21:50 
user profile iconCsharp-programmierer hat folgendes geschrieben Zum zitierten Posting springen:
Aber dann würde ja mein 80 GB Webspace Speicher sicher irgendwann überlasten :(
Auf Grund welcher Abschätzung der benötigten Datenmengen vermutest Du das?

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
Csharp-programmierer Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 696
Erhaltene Danke: 10

Windows 8.1
C# (VS 2013)
BeitragVerfasst: So 30.10.16 21:53 
Naja...
Sagen wir mal 1000 User sind befreundet, dann sind in der Datenbank 2000 Datensätze. Ist bestimmt schon relativ viel

_________________
"Wer keinen Sinn im Leben sieht, ist nicht nur unglücklich, sondern kaum lebensfähig" - Albert Einstein
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Chefentwickler
Beiträge: 20285
Erhaltene Danke: 2078

Win 10
C# (VS 2017)
BeitragVerfasst: So 30.10.16 22:20 
Wie kommst Du da drauf, dass das viel ist?

Du speicherst (höchstens) drei Zahlen. Eine ID für den Datensatz, eine ID für den ersten Benutuzer, eine ID für den zweiten Benutzer. Drei Zahlen mit je 32 Bit = 4 Byte. Sind also 12 Byte pro Datensatz. Sagen wir, es gibt noch einen gigantisch unrealistischen Overhead und es sind pro Datensatz 1 KB (also das 85-fache der eigentlichen Daten!). Bei 2000 Datensätzen wärst Du also bei 2 MB. Wo genau siehst Du die Grenze von 80 GB erreicht?

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
Frühlingsrolle
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2105
Erhaltene Danke: 385

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: So 30.10.16 23:22 
Das kannst du gern so machen, oder du erstellst für jeden Namen eine eigene Tabelle, in der dessen Freunde aufgelistet werden.

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Chefentwickler
Beiträge: 20285
Erhaltene Danke: 2078

Win 10
C# (VS 2017)
BeitragVerfasst: So 30.10.16 23:27 
user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
[...]oder du erstellst für jeden Namen eine eigene Tabelle, in der dessen Freunde aufgelistet werden.
Was wäre der Vorteil davon?

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
Frühlingsrolle
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2105
Erhaltene Danke: 385

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: So 30.10.16 23:29 
Übersichtlichkeit.

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Chefentwickler
Beiträge: 20285
Erhaltene Danke: 2078

Win 10
C# (VS 2017)
BeitragVerfasst: So 30.10.16 23:36 
Du meinst, wenn ich dann bei 1000 Nutzern 1000 Tabellen habe?

Und wie frage ich dann z.B. ab, wer alles Benutzer X "gefreundet" hat?

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1177
Erhaltene Danke: 157

Windows 10 x64 Home Premium
C# (VS 2015 Enterprise)
BeitragVerfasst: So 30.10.16 23:45 
In der heutigen Zeit ist der Datenspeicher die billigste Resource, um die würde ich mir als letztes Gedanken machen ^^
Klar, solltest Du einige Grundregeln beachten, aber solange Du nicht zig Daten an zig verschiedenen Stellen redundant hältst, sollten deine 80GB eigentlich locker und mit links ausreichen.
Kommt natürlich drauf an, was Du noch so für Daten sammelst


Und was die Freundschaften angeht:

Variante 1:
Wie Du schon gesagt hast:
Für jede neue Freundschaft bekommt jeder User einen Freundschaft-Eintrag.
Das hätte den Vorteil, dass pro Person eigene Daten pro Freundschaft gespeichert werden können.
Einen Vorteil in der Abfrage sehe ich nicht.

Variante 2:
Jede Freundschaft zwischen zwei Personen ist "eindeutig"
Pro Freundschaft gibts dann genau einen Datensatz.
Gemeinsame Daten pro Freundschaft sind dann leichter zu verwalten, eine Person kann aber keine eigenen Daten für eine Freundschaft haben.

In SQL ungefähr so:
ausblenden SQL-Anweisung
1:
2:
3:
SELECT *
FROM Freundschaften
WHERE User1Id = @userId OR User2Id = @userId



Die wichtigste Frage bleibt also:
Was genau willst Du machen?
Braucht eine Freundschaft pro Person eigene Daten?
Oder soll jede Freundschaft eigene Daten gemeinsam für beide Beteiligten haben?
Je nachdem, was Du brauchst, musst Du die Variante wählen.

Die Komplexität der SQL-Abfrage, der Umfang der Daten oder Performance sind bei einem so kleinen Rahmen eher drittrangig.

Aber mach bitte nicht so Spielereien wie pro Freund eine neue Spalte oder pro Person eine neue Freundes-Tabelle.
Potentielle Probleme dabei:

  • ORMs kann man sich damit eigentlich sparen, es gibt ja keine statische Klassenstruktur mehr, in die gängige ORMs das mappen können. Oder ich weiß von kenem ORM, was das im laufenden Betrieb kann.
  • Die SQL-Abfragen lassen sich nicht mehr über einfache Parameter zusammenbauen, einfache WHERE-Klauseln reichen nicht mehr, andere Dinge wie Group By dürften schwierig werden, etc.
  • Eine Freundschafts-Anfrage braucht auf einmal DDL-Rechte auf dem Server, was ich für fragwürdig halte
  • Mittelfristig dürfte das auch ein Performance-Problem darstellen, wenn Du nicht nur tausende Daten (was echt wenig ist), sondern tausende Tabellen hast. Und tausende Tabellen, das IST viel :D

Hab ich was vergessen?
Frühlingsrolle
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2105
Erhaltene Danke: 385

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Mo 31.10.16 00:11 
1000 Benutzer / 1000 Tabellen, oder 1 Tabelle und ein vielfaches an Datensatzen, also mehr als 1000!
Gut, herauszufinden, wer alles Benutzer X als Freund hat, wäre etwas umständlicher aber dennoch möglich.

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 3897
Erhaltene Danke: 794

Win7
C++, C# (VS 2015/17)
BeitragVerfasst: Mo 31.10.16 09:27 
Also das mit den eigene Tabellen paßt nun wirklich nicht zu einer normalisierten Datenbank.

Ich würde die Abfrage ähnlich wie Palladin007 machen, nur daraus zwei machen und diese beiden vereinen:
ausblenden SQL-Anweisung
1:
2:
3:
4:
5:
6:
7:
8:
9:
SELECT User2Id
FROM Freundschaften
WHERE User1Id = @userId

UNION

SELECT User1Id
FROM Freundschaften
WHERE User2Id = @userId
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1177
Erhaltene Danke: 157

Windows 10 x64 Home Premium
C# (VS 2015 Enterprise)
BeitragVerfasst: Mo 31.10.16 10:10 
Zitat:
1000 Benutzer / 1000 Tabellen, oder 1 Tabelle und ein vielfaches an Datensatzen, also mehr als 1000!


Wenn 1000 Benutzer 1000 Freunde haben, dann brauchst Du 1000 Tabellen mit 1000 Datensätzen.
1000 Tabellen tun weh in der Performance

Alles in einer Tabelle würde bedeuten, dass für jede Person und für jede Freundschaft zwei Datensätze angelegt werden.
Sprich: 1000 * 1000 * 2 = 2000000 Datensätze
Das wäre in der Tat viel, allerdings hast Du die Datenmenge bei 1000 Tabellen auch plus die Daten, die der Server braucht um die Tabellen zu verwalten.
Und bei 1000 Tabellen kann der Server nicht über alle Daten indizieren.

Und DAS, der letzte Punkt, der sollte eigentlich ein KO-Kriterium sein ;)
Wenn Du 2 Millionen Datensätze in einer Tabelle hast, kann der Server auf alle Datensätze indizieren, was einen deutlichen Performance-Vorteil bedeuten kann.
Wenn Du diese 2 Millionen Datensätze auf 1000 Tabellen auf teilst, dann indiziert der Server über 1000 Datensätze pro Tabelle, was witzlos wäre.
Csharp-programmierer Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 696
Erhaltene Danke: 10

Windows 8.1
C# (VS 2013)
BeitragVerfasst: Mo 31.10.16 11:55 
Jetzt habe ich gestern Abend noch bin tief in die Nacht an dem PHP Script rumgewerkelt, dass die Usernames in IDs verwandelt werden. Jetzt haut alles so hin, dass die C# Anwendung die Usernames zur PHP Datei schickt und diese demnach die zugehörige ID raussucht und in die Datenbank schreibt. Im Moment läuft es noch so, dass der doppelte Datensatz eingetragen wird.

Was soll noch passieren?
Die eine Datenbank soll lediglich alle Freundschaften speichern. Heute versuche ich noch einen PHP Script zu basteln, der dann die ganzen Freunde, samt anderen Daten ausgibt...

Im Moment habe ich ja noch den doppelten Datensatz für eine Freundschaft.

ausblenden SQL-Anweisung
1:
2:
3:
4:
5:
6:
7:
8:
9:
SELECT User2Id
FROM Freundschaften
WHERE User1Id = @userId

UNION

SELECT User1Id
FROM Freundschaften
WHERE User2Id = @userId


Und mit diesem SQL Befehl bekommt man dann alle Freundschaften anhand eines Datensatzes?

_________________
"Wer keinen Sinn im Leben sieht, ist nicht nur unglücklich, sondern kaum lebensfähig" - Albert Einstein
Frühlingsrolle
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2105
Erhaltene Danke: 385

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Mo 31.10.16 13:44 
Ihr habt schon recht, aber alles doppelt hinzuschreiben, stimmt mich auch nicht gerade zufrieden.

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
jfheins
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 853
Erhaltene Danke: 139

Win7
VS 2013, VS2015
BeitragVerfasst: Mo 31.10.16 14:04 
Was meinst du damit? Die Abfrage?
Das liegt halt daran, dass die Freundschaft kommutativ ist. Man kann auch ein System implementieren, bei dem man Leute einseitig de-frienden kann. Dann hätte die Reihenfolge wieder eine Bedeutung.

Aber so ist es egal, und bevor du einfach die doppelte Menge an Daten in die DB kippst, ist es doch einfach eine Abfrage wie "... WHERE User1Id = @userId OR User2Id = @userId" abzusetzen.

Für diesen Beitrag haben gedankt: FinnO
Frühlingsrolle
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2105
Erhaltene Danke: 385

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Mo 31.10.16 18:06 
Nicht die Abfragen, das Anlegen von x-fachen Datensätzen für ein und das selbe Kriterium. Macht jetzt nicht wirklich Sinn, aber würde jemand wollen, manuell einen solchen Eintrag zu suchen, zu bearbeiten oder sogar in jeglicher Beziehung zu entfernen, dann wäre er ohne SQL ganz schön überfordert.
Da wäre es mir lieber, ich würde eine komplette Tabelle bearbeiten/löschen, als alle Zeilen durchgehen zu müssen. Darauf wollte ich hinaus.

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
Csharp-programmierer Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 696
Erhaltene Danke: 10

Windows 8.1
C# (VS 2013)
BeitragVerfasst: Mo 31.10.16 20:08 
Ich habe es jetzt so gemacht, dass pro Freundschaft nur ein Datensatz angelegt wird. Ich habe folgenden Code zusammengestellt:

ausblenden PHP-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
$CurrentUser = mysqli_real_escape_string($conn$_POST["currUsr"]);
    $sqlQuery = "SELECT `To_ID` FROM `MainlysoftFreundesliste` WHERE `To_ID`='$CurrentUser' OR `From_ID`='$CurrentUser'";
    $result = mysqli_query($conn$sqlQuery);
    if($result)
    {
      $newQuery = "SELECT `name`, `vorname`, `language`, `gender` FROM `MainlysoftBenutzer` WHERE `ID`='$CurrentUser'";
      if ($result->num_rows > 0) {
          while($row = $result->fetch_assoc()) {
            echo $row["name"]. ";" . $row["vorname"]. ";" .$row["language"]. ";" .$row["gender"]. "";
          }
      } else {
        echo "0 results";
      }  
    }
    else
    {
      echo "Error in SQL statement";
    }


Jetzt wird mir ja nur "To_ID" rausgesucht. Aber wenn ich jetzt auch "Von_ID" raussuchen lass, weiß ich ja nicht, welcher von den beiden Usern sich eingeloggt hat. Verseht ihr den logischen Fehler?

_________________
"Wer keinen Sinn im Leben sieht, ist nicht nur unglücklich, sondern kaum lebensfähig" - Albert Einstein
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4348
Erhaltene Danke: 878


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mo 31.10.16 20:21 
Zitat:
Jetzt wird mir ja nur "To_ID" rausgesucht. Aber wenn ich jetzt auch "Von_ID" raussuchen lass, weiß ich ja nicht, welcher von den beiden Usern sich eingeloggt hat. Verseht ihr den logischen Fehler?


Nein. Warum solltest du, weil das SQL änderst, ~vergessen~ wer in $CurrentUser steht?