Вот фрагмент таблиц:
USER
| USER_UID | FIRSTNAME | LASTNAME |
abc123 bob smith
def456 rob smithies
ghi789 john clark
СОБЫТИЕ
| GUID | NAME |
ev1 event1
ev2 event2
ev3 event3
USER_EVENT
| USER_EVENT_ID | USER_UID | EVENT_UID |
1 abc123 ev1
2 def456 ev2
3 ghi789 ev3
EVENT_VOTE
| EVENT_VOTE_ID | USER_UID | EVENT_UID |
1 def456 ev1 (user2 voted for user1 event)
У меня есть следующий запрос, который возвращает событие с количеством голосов и ранга на основе этого:
SELECT t.*, @curRank := @curRank + 1 AS rank
FROM ( SELECT e.guid,
e.name,
( SELECT COUNT(ev.event_vote_id)
FROM event_vote ev
WHERE ev.event_uid = e.guid
) AS votes
FROM event e
) AS t
CROSS JOIN (SELECT @curRank := 0) r
ORDER BY votes DESC
Я также хочу вернуть 1 или 0, если пользователь не имеет права голоса или нет.
Пользователь не имеет права голоса, если:
пользователь является владельцем события.
пользователь уже проголосовал за это событие (пользователи uid и event uid находятся в event_vote).
Следующий код после ... голосов AS дал мне правильный ответ, если пользователь уже голосовал, но не был, если им принадлежало это событие.
,(
SELECT COUNT(*)
FROM event_vote ev
WHERE ev.event_uid = e.guid
AND ev.user_uid = '{$user_uid}'
) AS ineligible
Ожидаемый результат (с точки зрения пользователя 2s при просмотре всех событий)
guid: ev1
name: event1
votes: 1
rank: 1
ineligible: 1 (already voted).
guid: ev2
name: event2
votes: 0
rank: 2
ineligible: 1 (user owns this event)
guid: ev3
name: event3
votes: 0
rank: 3
ineligible: 0 (user doesn't own this event and has yet to vote).
Вы можете использовать этот запрос в case when
выражение даёт 1 или null
. Это агрегируется как count(distinct...)
который дает 1 только тогда, когда в агрегированных значениях по крайней мере один 1, а 0 - в противном случае:
SELECT t.*,
@curRank := @curRank + 1 AS rank
FROM (
SELECT u.user_uid,
e.guid,
e.name,
count(ev.user_uid) votes,
count(distinct
case when u.user_uid in (ev.user_uid, ue.user_uid)
then 1
end) ineligible
FROM user u
CROSS JOIN event e
INNER JOIN user_event ue
ON ue.event_uid = e.guid
LEFT JOIN event_vote ev
ON ev.event_uid = e.guid
GROUP BY u.user_uid,
e.guid
ORDER BY votes desc,
e.guid,
u.user_uid
) as t
CROSS JOIN (SELECT @curRank := 0) r
WHERE t.user_uid = 'def456'
ORDER BY votes desc,
guid,
user_uid
Посмотрите, как это работает на rextester.com.
Имейте в виду, что, когда вы используете такие переменные, вы должны вынудить порядок во внутреннем запросе. Если вы делаете это только во внешнем запросе, это происходит слишком поздно, как только переменные выражения уже были оценены. Это может часто работать, поскольку оптимизатор может учитывать внешний order by
, но он не гарантируется.
вам нужно будет проверить, существует ли User_UID для проголосованного события в таблице User_Event. Если это так, то избиратель является владельцем.
что-то вроде: (PSEUDO Я не рядом с компилятором)
IF EXISTS (Begin
select User_Event_Id
from User_event
where User_UId = @user_uid
(@user_uid the user trying to vote)
and where Event_Id = @Event
(@Event = event of the id, the user is trying to vote for)
End)
Begin
if(--Check if user has voted for event (code you already wrote)
--User is eligible
else
--User not eligible
End
ELSE
--User not eligible
Но, может быть, лучше просто потратить время, чтобы объединить эти два запроса без результата для операторов if.
the user has already voted for that event
... можете ли вы указать, где это происходит в ваших данных?