Ich würde versuchen, dies VOLLSTÄNDIG zu vereinfachen, indem ich Trigger in Ihre anderen Tabellen einfüge und Ihrer User_Fans-Tabelle nur ein paar Spalten hinzufüge ... Eine für jede entsprechende Anzahl(), die Sie erhalten möchten ... von Posts, PostLikes, PostComments, PostCommentLikes.
Wenn ein Datensatz zu welcher Tabelle hinzugefügt wird, aktualisieren Sie einfach Ihre user_fans-Tabelle, um 1 zur Zählung hinzuzufügen ... es wird sowieso praktisch sofort basierend auf der Schlüssel-ID des Benutzers sein. Wie für die "LIKES" ... Ähnlich, nur unter der Bedingung, dass etwas als "Like" ausgelöst wird, fügen Sie 1 hinzu „gewichteter“ Gesamtwert. Wenn Ihre Tabelle noch größer wird, werden auch die Abfragen länger, da sie mehr Daten zu verarbeiten und zu aggregieren haben. Sie gehen JEDEN user_fan-Datensatz durch, der im Wesentlichen jeden Datensatz aus allen anderen Tabellen abfragt.
Abgesehen davon würde ich, wenn Sie die Tabellen so belassen, wie Sie sie haben, wie folgt umstrukturieren ...
SELECT
uf.user_name,
uf.user_id,
@pc := coalesce( PostSummary.PostCount, 000000 ) as PostCount,
@pl := coalesce( PostLikes.LikesCount, 000000 ) as PostLikes,
@cc := coalesce( CommentSummary.CommentsCount, 000000 ) as PostComments,
@cl := coalesce( CommentLikes.LikesCount, 000000 ) as CommentLikes,
@pc + @cc AS sum_post,
@pl + @cl AS sum_like,
@pCalc := (@pc + @cc) * 10 AS post_cal,
@lCalc := (@pl + @cl) * 5 AS like_cal,
@pCalc + @lCalc AS `total`
FROM
( select @pc := 0,
@pl := 0,
@cc := 0,
@cl := 0,
@pCalc := 0
@lCalc := 0 ) sqlvars,
user_fans uf
LEFT JOIN ( select user_id, COUNT(*) as PostCount
from post
group by user_id ) as PostSummary
ON uf.user_id = PostSummary.User_ID
LEFT JOIN ( select user_id, COUNT(*) as LikesCount
from post_likes
group by user_id ) as PostLikes
ON uf.user_id = PostLikes.User_ID
LEFT JOIN ( select user_id, COUNT(*) as CommentsCount
from post_comment
group by user_id ) as CommentSummary
ON uf.user_id = CommentSummary.User_ID
LEFT JOIN ( select user_id, COUNT(*) as LikesCount
from post_comment_likes
group by user_id ) as CommentLikes
ON uf.user_id = CommentLikes.User_ID
ORDER BY
`total` DESC
LIMIT 20
My variables are abbreviated as
"@pc" = PostCount
"@pl" = PostLikes
"@cc" = CommentCount
"@cl" = CommentLike
"@pCalc" = weighted calc of post and comment count * 10 weighted value
"@lCalc" = weighted calc of post and comment likes * 5 weighted value
Der LEFT JOIN zu Vorabfragen führt diese Abfragen EINMAL durch, dann wird das Ganze verbunden, anstatt als Unterabfrage für jeden Datensatz getroffen zu werden. Durch die Verwendung von COALESCE() werden Sie, wenn es keine solchen Einträge in den LEFT JOINed-Tabellenergebnissen gibt, nicht von NULL-Werten getroffen, die die Berechnungen durcheinander bringen, also habe ich sie auf 000000 voreingestellt.
KLÄRUNG IHRER FRAGEN
Sie können jede QUERY als "AS AliasResult" haben. Das "As" kann auch verwendet werden, um lange Tabellennamen für eine einfachere Lesbarkeit zu vereinfachen. Aliasse können auch dieselbe Tabelle verwenden, aber als einen anderen Alias, um ähnlichen Inhalt zu erhalten, aber für einen anderen Zweck.
select
MyAlias.SomeField
from
MySuperLongTableNameInDatabase MyAlias ...
select
c.LastName,
o.OrderAmount
from
customers c
join orders o
on c.customerID = o.customerID ...
select
PQ.SomeKey
from
( select ST.SomeKey
from SomeTable ST
where ST.SomeDate between X and Y ) as PQ
JOIN SomeOtherTable SOT
on PQ.SomeKey = SOT.SomeKey ...
Nun, die dritte obige Abfrage ist nicht praktikabel und erfordert die ( vollständige Abfrage, die zum Alias "PQ" führt, der "PreQuery" darstellt). Dies könnte getan werden, wenn Sie einen bestimmten Satz anderer komplexer Bedingungen im Voraus einschränken und einen kleineren Satz wünschen, BEVOR Sie zusätzliche Verknüpfungen mit vielen anderen Tabellen für alle Endergebnisse vornehmen.
Da ein "FROM" keine tatsächliche Tabelle sein MUSS, sondern eine eigene Abfrage sein kann, muss es wissen, wie es auf diese Vorabfrage-Ergebnismenge verweisen kann.
Wenn Felder abgefragt werden, können sie auch "As FinalColumnName" sein, um die Ergebnisse dort zu vereinfachen, wo sie auch verwendet werden.
selectCONCAT( User.Salutation, User.LastName ) as CourtesyNamefrom ...
selectOrder.NonTaxable+ Order.Taxable+ ( Order.Taxable * Order.SalesTaxRate ) as OrderTotalWithTaxfrom ...
Der „As“-Spaltenname muss NICHT zwingend ein Aggregat sein, wird aber meistens so gesehen.
Nun zu den MySQL-Variablen ... Wenn Sie eine gespeicherte Prozedur ausführen, werden viele Leute vorab erklären, dass sie ihre Standardwerte vor dem Rest der Prozedur festlegen. Sie können sie inline in einer Abfrage ausführen, indem Sie diesem Ergebnis einfach eine "Alias"-Referenz setzen und zuweisen. Wenn Sie diese Variablen ausführen, simuliert die Auswahl immer einen EINZELNEN RECORD-Wert der Werte. Es ist fast wie ein aktualisierbarer einzelner Datensatz, der in der Abfrage verwendet wird. Sie müssen keine spezifischen "Join"-Bedingungen anwenden, da dies möglicherweise keinen Einfluss auf den Rest der Tabellen in einer Abfrage hat ... Erstellt im Wesentlichen ein kartesisches Ergebnis, aber ein Datensatz gegen eine andere Tabelle wird niemals erstellt sowieso Duplikate, also kein Schaden nachgelagert.
select
...
from
( select @SomeVar := 0,
@SomeDate := curdate(),
@SomeString := "hello" ) as SQLVars
Nun, wie die sqlvars funktionieren. Stellen Sie sich ein lineares Programm vor ... Ein Befehl wird in der exakten Reihenfolge ausgeführt, in der die Abfrage ausgeführt wird. Dieser Wert wird dann wieder im "SQLVars"-Datensatz gespeichert, bereit für den nächsten Durchlauf. Sie referenzieren es jedoch nicht als SQLVars.SomeVar oder SQLVars.SomeDate ... nur @SomeVar :=someNewValue. Wenn die @var jetzt in einer Abfrage verwendet wird, wird sie auch als „As ColumnName“ in der Ergebnismenge gespeichert. Manchmal kann dies nur ein berechneter Platzhalterwert zur Vorbereitung des nächsten Datensatzes sein. Jeder Wert steht dann direkt für die nächste Zeile zur Verfügung. Also, gegeben das folgende Beispiel...
select
@SomeVar := SomeVar * 2 as FirstVal,
@SomeVar := SomeVar * 2 as SecondVal,
@SomeVar := SomeVar * 2 as ThirdVal
from
( select @SomeVar := 1 ) sqlvars,
AnotherTable
limit 3
Will result in 3 records with the values of
FirstVal SecondVal ThirdVal
2 4 8
16 32 64
128 256 512
Beachten Sie, wie der Wert von @SomeVar verwendet wird, wenn jede Spalte ihn verwendet ... Der aktualisierte Wert ist also selbst für denselben Datensatz sofort für die nächste Spalte verfügbar ... Sehen Sie sich nun an, wie Sie versuchen, eine simulierte Datensatzanzahl zu erstellen / Ranking pro Kunde...
select
o.CustomerID,
o.OrderID
@SeqNo := if( @LastID = o.CustomerID, @SeqNo +1, 1 ) as CustomerSequence,
@LastID := o.CustomerID as PlaceHolderToSaveForNextRecordCompare
from
orders o,
( select @SeqNo := 0, @LastID := 0 ) sqlvars
order by
o.CustomerID
Die "Order By"-Klausel erzwingt, dass die Ergebnisse zuerst der Reihe nach zurückgegeben werden. Hier werden also die Datensätze pro Kunde zurückgegeben. Beim ersten Mal ist LastID 0 und die Kunden-ID ist sagen wir ... 5. Da es anders ist, gibt es 1 als @SeqNo zurück, DANN behält es diese Kunden-ID im @LastID-Feld für den nächsten Datensatz bei. Nun, nächster Datensatz für den Kunden ... Die letzte ID ist dieselbe, also nimmt sie die @SeqNo (jetzt =1) und addiert 1 zu 1 und wird #2 für denselben Kunden ... Weiter auf dem Pfad. .
Um beim Schreiben von Abfragen besser zu werden, werfen Sie einen Blick auf das MySQL-Tag und sehen Sie sich einige der großen Mitwirkenden an. Schauen Sie sich die Fragen und einige der komplexen Antworten an und wie das Lösen von Problemen funktioniert. Um nicht zu sagen, dass es nicht andere mit niedrigeren Reputationswerten gibt, die gerade erst anfangen und vollkommen kompetent sind, aber Sie werden feststellen, wer gute Antworten gibt und warum. Sehen Sie sich auch den Verlauf der geposteten Antworten an. Je mehr Sie lesen und befolgen, desto besser können Sie komplexere Abfragen schreiben.