Jeg ville forsøge at forenkle dette HELT ved at sætte udløsere på dine andre tabeller, og blot tilføje et par kolonner til din User_Fans-tabel... En for hver respektive count() du forsøger at få... fra Posts, PostLikes, PostComments, PostKommentar Synes godt om.
Når en post tilføjes til hvilken som helst tabel, skal du bare opdatere din user_fans-tabel for at tilføje 1 til antallet... den vil under alle omstændigheder være praktisk talt øjeblikkelig baseret på brugerens nøgle-id. Med hensyn til "LIKES"... Tilsvarende, kun under den betingelse, at noget udløses som et "Like", tilføje 1.. Så vil din forespørgsel være en direkte matematik på den enkelte post og ikke stole på NOGEN joins til at beregne en "vægtet" samlet værdi. Efterhånden som din tabel bliver endnu større, vil forespørgslerne også blive længere, da de har flere data at strømme igennem og samle. Du gennemgår HVER user_fan-post, som i bund og grund forespørger hver post fra alle de andre tabeller.
Når det er sagt, vil jeg omstrukturere som følger, hvis du holder tabellerne som du har dem...
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
VENSTRE JOIN til forespørgsler kører disse forespørgsler EN gang igennem, så samles det hele i stedet for at blive ramt som en underforespørgsel for hver post. Ved at bruge COALESCE(), hvis der ikke er sådanne poster i LEFT JOINed tabelresultaterne, vil du ikke blive ramt af NULL-værdier, der ødelægger beregningerne, så jeg har indstillet dem til 000000 som standard.
AFKLARING AF DINE SPØRGSMÅL
Du kan have en hvilken som helst QUERY som et "SOM AliasResult". "Som" kan også bruges til at forenkle alle lange tabelnavne for lettere læsbarhed. Aliaser kan også bruge den samme tabel, men som et andet alias for at få lignende indhold, men til forskellige formål.
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 ...
Nu er den tredje forespørgsel ovenfor ikke praktisk og kræver den (fuld forespørgsel, der resulterer i alias "PQ" repræsenterer "PreQuery"). Dette kunne gøres, hvis du ønskede at forhåndsbegrænse et bestemt sæt af andre komplekse forhold og ønskede et mindre sæt, FØR du laver ekstra joins til mange andre tabeller for alle endelige resultater.
Da en "FROM" ikke BEHØVER at være en egentlig tabel, men kan være en forespørgsel i sig selv, et hvilket som helst andet sted, der bruges i forespørgslen, skal det vide, hvordan man refererer til dette forespørgselsresultatsæt.
Når du forespørger felter, kan de også være "Som FinalColumnName" for at forenkle resultaterne, hvor end de vil blive brugt.
vælg CONCAT(Bruger.Hilsen, Bruger.Efternavn ) som Høflighedsnavn fra ...
selectOrder.NonTaxable+ Order.Taxable+ (Order.Taxable * Order.SalesTaxRate ) som OrderTotalWithTaxfrom ...
"Som"-kolonnen Navn er IKKE påkrævet at være et samlet, men ses oftest på den måde.
Med hensyn til MySQL-variablerne... Hvis du lavede en lagret procedure, vil mange mennesker på forhånd erklære, at de indstiller deres standardværdier før resten af proceduren. Du kan gøre dem in-line i en forespørgsel ved blot at indstille og give resultatet en "Alias"-reference. Når du udfører disse variabler, vil select simulere altid at returnere en SINGLE RECORD værdi af værdierne. Det er næsten som en enkelt post, der kan opdateres, brugt i forespørgslen. Du behøver ikke anvende nogen specifikke "Join"-betingelser, da det muligvis ikke har nogen betydning for resten af tabellerne i en forespørgsel... Opretter i bund og grund et kartesisk resultat, men en post mod en anden tabel vil aldrig oprette dubletter under alle omstændigheder, så ingen skader nedstrøms.
select
...
from
( select @SomeVar := 0,
@SomeDate := curdate(),
@SomeString := "hello" ) as SQLVars
Hvordan fungerer sqlvars. Tænk på et lineært program... En kommando udføres i den nøjagtige rækkefølge, mens forespørgslen kører. Denne værdi gemmes derefter igen i "SQLVars"-posten, klar til næste gang. Du omtaler det dog ikke som SQLVars.SomeVar eller SQLVars.SomeDate... bare @SomeVar :=someNewValue. Nu, når @var bruges i en forespørgsel, gemmes den også som et "As ColumnName" i resultatsættet. Nogle gange kan dette blot være en pladsholder-beregnet værdi som forberedelse til den næste post. Hver værdi er så direkte tilgængelig for den næste række. Så givet følgende eksempel...
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
Læg mærke til, hvordan værdien af @SomeVar bruges, da hver kolonne bruger den... Så selv på den samme post er den opdaterede værdi umiddelbart tilgængelig for den næste kolonne... Når det er sagt, se nu på at prøve at bygge et simuleret rekordantal / rangering pr. hver 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
"Order By"-sætningen tvinger resultaterne til at blive returneret i rækkefølge først. Så her returneres registreringerne pr. kunde. Første gang igennem er LastID 0 og kunde-id er sige...5. Da det er anderledes, returnerer det 1 som @SeqNo, SÅ bevarer det det kunde-id i @LastID-feltet for den næste post. Nu, næste post for kunde... Sidste ID er det samme, så det tager @SeqNo (nu =1), og tilføjer 1 til 1 og bliver #2 for den samme kunde... Fortsæt på stien.. .
Med hensyn til at blive bedre til at skrive forespørgsler, så tag et kig på MySQL-tagget og se på nogle af de tunge bidragydere. Se på spørgsmålene og nogle af de komplekse svar, og hvordan problemløsning fungerer. For ikke at sige, at der ikke er andre med lavere omdømmescore, der lige er startet og fuldstændig kompetente, men du vil finde ud af, hvem der giver gode svar og hvorfor. Se også deres historie med de udsendte svar. Jo mere du læser og følger, jo mere får du bedre styr på at skrive mere komplekse forespørgsler.