Бих се опитал да опростя това НАПЪЛНО, като поставя тригери в другите ви таблици и просто добавя няколко колони към вашата таблица User_Fans... По една за всеки съответен count(), който се опитвате да получите... от публикации, публикации, харесвания, коментари, PostCommentLikes.
Когато се добави запис към която и да е таблица, просто актуализирайте вашата таблица user_fans, за да добавите 1 към броя... това ще бъде практически мигновено въз основа на идентификатора на ключа на потребителя. Що се отнася до "Харесванията"... Подобно, само при условие, че нещо се задейства като "Харесвам", добавете 1.. Тогава вашата заявка ще бъде директна математика за единичния запис и няма да разчита на НИКАКВИ присъединявания, за да изчисли "претеглена" обща стойност. Тъй като вашата таблица става още по-голяма, заявките също ще стават по-дълги, тъй като имат повече данни за изливане и обобщаване. Преминавате през ВСЕКИ запис на user_fan, който по същество прави заявка за всеки запис от всички останали таблици.
Като се има предвид всичко това, запазвайки таблиците такива, каквито ги имате, бих преструктурирал както следва...
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
LEFT JOIN към предварителни заявки изпълнява тези заявки ВЕДНЪЖ, след което цялото нещо се присъединява, вместо да бъде ударено като подзаявка за всеки запис. С помощта на COALESCE(), ако няма такива записи в резултатите от таблицата LEFT JOINed, няма да получите NULL стойности, които да объркат изчисленията, така че ги поставих по подразбиране на 000000.
ИЗЯСНЯВАНЕ НА ВАШИТЕ ВЪПРОСИ
Можете да имате произволна QUERY като "AS AliasResult". "As" може също да се използва за опростяване на всякакви дълги имена на таблици за по-лесна четливост. Псевдонимите също могат да използват същата таблица, но като различен псевдоним, за да получите подобно съдържание, но с различна цел.
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 ...
Сега, третата заявка по-горе не е практична да изисква (пълна заявка, която води до псевдоним "PQ", представляващ "PreQuery"). Това може да се направи, ако искате предварително да ограничите определен набор от други сложни условия и искате по-малък набор, ПРЕДИ да извършите допълнително свързване към много други таблици за всички крайни резултати.
Тъй като "FROM" не ТРЯБВА да бъде действителна таблица, но може да бъде заявка сама по себе си, на всяко друго място, използвано в заявката, то трябва да знае как да препраща към този набор от резултати от предварителна заявка.
Освен това, когато се правят заявки за полета, те също могат да бъдат „Като FinalColumnName“, за да се опростят резултатите, където и да се използват.
selectCONCAT( User.Salutation, User.LastName ) като CourtesyNamefrom ...
selectOrder.NonTaxable+ Order.Taxable+ ( Order.Taxable * Order.SalesTaxRate ) като OrderTotalWithTaxfrom ...
Името на колоната „Като“ НЕ е задължително да бъде обобщено, но най-често се разглежда по този начин.
Сега, по отношение на променливите на MySQL... Ако правите съхранена процедура, много хора ще ги декларират предварително, като задават техните стойности по подразбиране преди останалата част от процедурата. Можете да ги направите на линия в заявка, като просто зададете и дадете на този резултат препратка към „псевдоним“. Когато правите тези променливи, изборът ще симулира винаги връщането на стойността на ЕДИН ЗАПИС от стойностите. Това е почти като единичен запис с възможност за актуализиране, използван в заявката. Не е необходимо да прилагате никакви специфични условия за присъединяване, тъй като може да няма никакво отношение към останалите таблици в заявката... По същество създава декартов резултат, но един запис срещу всяка друга таблица никога няма да създаде все пак се дублират, така че няма повреди надолу по веригата.
select
...
from
( select @SomeVar := 0,
@SomeDate := curdate(),
@SomeString := "hello" ) as SQLVars
Сега, как работят sqlvars. Помислете за линейна програма... Една команда се изпълнява в точната последователност, докато се изпълнява заявката. След това тази стойност се съхранява отново в записа "SQLVars", готов за следващия път. Въпреки това, вие не го посочвате като SQLVars.SomeVar или SQLVars.SomeDate... просто @SomeVar :=someNewValue. Сега, когато @var се използва в заявка, той също се съхранява като "Като ColumnName" в набора от резултати. Понякога това може да бъде само задържаща място, изчислена стойност при подготовката на следващия запис. След това всяка стойност е директно достъпна за следващия ред. И така, като се има предвид следната извадка...
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
Забележете как стойността на @SomeVar се използва, тъй като всяка колона я използва... Така че дори в същия запис, актуализираната стойност е незабавно достъпна за следващата колона... Въпреки това, сега погледнете как се опитвате да изградите симулиран брой записи / класиране за всеки клиент...
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
Клаузата "Поръчай по" принуждава резултатите да се връщат последователно първо. И така, тук записите на клиент се връщат. За първи път LastID е 0, а клиентският идентификатор е да кажем...5. Тъй като е различен, той връща 1 като @SeqNo, ТОГАВА запазва този клиентски идентификатор в полето @LastID за следващия запис. Сега следващият запис за клиента... Последният идентификатор е същият, така че приема @SeqNo (сега =1) и добавя 1 към 1 и става #2 за същия клиент... Продължете по пътя.. .
Що се отнася до подобряването на писането на заявки, погледнете маркера MySQL и вижте някои от най-големите участници. Разгледайте въпросите и някои от сложните отговори и как работи решаването на проблеми. Да не кажа, че няма други с по-ниски резултати за репутация, които тепърва започват и са напълно компетентни, но ще откриете кой дава добри отговори и защо. Вижте и тяхната история на публикуваните отговори. Колкото повече четете и следвате, толкова повече ще се справите с писането на по-сложни заявки.