2014-01-20 6 views
4

Я хочу выбрать количество пользователей, которые отметили некоторый контент как избранный, а также вернуться, если текущий пользователь «проголосовал» или нет. Моя таблица выглядит следующим образомSELECT CASE, COUNT (*)

CREATE TABLE IF NOT EXISTS `favorites` (
`user` int(11) NOT NULL DEFAULT '0', 
`content` int(11) NOT NULL DEFAULT '0', 
PRIMARY KEY (`user`,`content`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; 

Say У меня есть 3 строки, содержащие

INSERT INTO `favorites` (`user`, `content`) VALUES 
(11, 26977), 
(22, 26977), 
(33, 26977); 

Используя этот

SELECT COUNT(*), CASE 
     WHEN user='22' 
      THEN 1 
      ELSE 0 
    END as has_voted 
FROM favorites WHERE content = '26977' 

я ожидаю получить has_voted=1 и COUNT(*)=3 но

я получаю has_voted=0 и COUNT(*)=3. Почему это? Как это исправить?

ответ

6

Это связано с тем, что вы комбинировали агрегированные и неагрегированные выражения в одном SELECT. Агрегированные выражения работают во многих строках; неагрегированные выражения работают в одной строке. Агрегированные (то есть COUNT(*)) и неагрегированные (то есть CASE) выражения должны появляться в том же SELECT, когда у вас есть GROUP BY, что не имеет смысла в вашей ситуации.

Вы можете исправить свой запрос агрегации второго выражения - то есть добавление SUM вокруг него, как это:

SELECT 
    COUNT(*) AS FavoriteCount 
, SUM(CASE WHEN user=22 THEN 1 ELSE 0 END) as has_voted 
FROM favorites 
WHERE content = 26977 

Теперь оба выражения объединяется, так что вы должны получить ожидаемые результаты.

1

Вам нужна сумма голосов.

SELECT COUNT(*), SUM(CASE 
     WHEN user='22' 
      THEN 1 
      ELSE 0 
    END) as has_voted 
FROM favorites WHERE content = '26977' 
2

Попробуйте это:

SELECT COUNT(*), MAX(USER=22) AS has_voted 
FROM favorites 
WHERE content = 26977; 

Проверить SQL FIDDLE DEMO

ВЫВОД

| COUNT(*) | HAS_VOTED | 
|----------|-----------| 
|  3 |   1 | 
+0

Это хороший пример использования функции MySQL, чтобы получить логические выражения результатов. Очень хорошее решение проблемы. Ваш ответ был бы замечательным, если бы вы не только дали рабочее решение, но и объяснили ошибку дакера. Мой голос, хотя, для лучшего решения, на мой взгляд. –

+0

@ThorstenKettner Вас приветствует ... –

5

Попробуйте это SUM() и без CASE

SELECT 
    COUNT(*), 
    SUM(USER = '22') AS has_voted 
FROM 
    favorites 
WHERE content = '26977' 

See Fiddle Demo

1

Вы неосторожно с помощью функции MySQL здесь: Вы агрегировать свои результаты, чтобы получить только один результат записи, показывающее количество матчей (агрегатная функция COUNT). Но вы также показываете пользователю (или, скорее, выражению, построенному на нем) в вашей результирующей строке (без какой-либо совокупной функции). Итак, вопрос: какой пользователь? Еще один dbms дал бы вам ошибку, попросив вас указать пользователя в группе GROUP BY или агрегированных пользователей. MySQL вместо этого выбирает случайного пользователя.

Что вы хотите сделать здесь, это совокупные пользователи (или, скорее, агрегирование вашего выражения). Используйте SUM, чтобы суммировать все голоса пользователь дал на запрашиваемое содержание:

SELECT 
    COUNT(*), 
    SUM(CASE WHEN user='22' THEN 1 ELSE 0 END) as sum_votes 
FROM favorites 
WHERE content = '26977'; 
1

Вы забыли завернуть CASE заявление в агрегатной функции. В этом случае has_voted будет содержать неожиданные результаты, так как вы на самом деле выполняете «частичную группу».Вот то, что вам нужно сделать:

SELECT COUNT(*), SUM(CASE WHEN USER = 22 THEN 1 ELSE 0 END) AS has_voted 
FROM favorites 
WHERE content = 26977 

Или:

SELECT COUNT(*), COUNT(CASE WHEN USER = 22 THEN 1 ELSE NULL END) AS has_voted 
FROM favorites 
WHERE content = 26977