Не удается выполнить конкретный запрос SQL в моей базе данных - PullRequest
1 голос
/ 03 мая 2019

У меня есть база данных для приложения чата.

CREATE TABLE Users (uid int PRIMARY KEY, name text, phone text );

CREATE TABLE Messages (recipient int REFERENCES Users(uid), sender int 
REFERENCES Users(uid), time timestamp NOT NULL, message text NOT NULL, 
PRIMARY KEY (recipient, sender, time));

http://www.sqlfiddle.com/#!9/bd36d1

Я хочу определить для каждого из 5 пользователей, отправивших наибольшее количество сообщений, среднюю длину сообщений, отправленных этим пользователем.

Я написал следующий запрос:

SELECT avg(strlen(message))
FROM Messages
WHERE sender IN
                (SELECT *
                 FROM (SELECT sender, COUNT(sender) AS NumberOfMessages
                       FROM Messages
                       GROUP BY sender) AS MessagesPerSender
                 ORDER BY NumberOfMessages DESC
                 LIMIT 5)

Для начала, правильный ли это запрос? Это дает мне желаемый результат? Проблема в том, что я не могу его запустить, потому что я получаю сообщение об ошибке:

"Эта версия MySQL еще не поддерживает подзапрос LIMIT & IN / ALL / ANY / SOME"

Ответы [ 3 ]

2 голосов
/ 03 мая 2019

Неправильный подход для MySQL это может сделать

select sender,avg(length(message)),count(*)
from   messages
group by sender
order by avg(length(message)) desc limit 5;

+--------+----------------------+----------+
| sender | avg(length(message)) | count(*) |
+--------+----------------------+----------+
|      1 |               9.0000 |        1 |
|      9 |               5.5000 |        2 |
|      2 |               5.0000 |        1 |
+--------+----------------------+----------+
3 rows in set (0.00 sec)

Обратите внимание, что это может не соответствовать ничьей так, как вы хотите.

2 голосов
/ 03 мая 2019

В вашем коде было 2 ошибки:

  1. Прежде всего, вы не можете использовать strlen в MYSQL.Это диалект Microsoft SQL Server Вместо этого вам нужно использовать length.

  2. Во-вторых, в подзапросе, который вы использовали, вы использовали два столбца вместо одного.Это приведет к сбою запроса, потому что оператор равенства должен быть равен значению только в одном столбце.

Итак, вот ваш запрос:

select u.name, avg(length(m.message)), count(*)
from Messages m
inner join Users u on m.sender = u.uid
group by u.name
order by avg(length(m.message)) desc limit 5;

Я улучшил ответ П. Сэлмона, поскольку предоставил вам имя отправителя, а не его ID.

Надеюсь, это поможет:)

1 голос
/ 03 мая 2019

Чтобы узнать, я изменил DMBS с MySQL на Postgres, который поддерживает внутренний лимит. Ваш запрос имеет правильный синтаксис, кроме функции strlen(), правильный - length().

Однако ваш запрос не выполняется по простой причине: вы делаете where sender in (subquery), хотя ваш подзапрос возвращает два поля. Оператор in работает только с запросами одного поля. Кроме того, ваш подзапрос состоит из двух запросов, которые можно упростить до одного. Следующий запрос работает на Postgres 9.6 и должен работать на любой версии MySQL с поддержкой внутреннего лимита:

SELECT avg(length(message))
FROM Messages
WHERE sender IN (
    SELECT sender
    FROM Messages
    GROUP BY sender
    ORDER BY COUNT(sender) DESC
    LIMIT 5
)

При работе с образцами данных выдается следующий результат:

+----------+
|   avg    |
+----------+
|   6.25   |
+----------+

Рабочая скрипта SQL (Postgres 9.6): http://www.sqlfiddle.com/#!17/bd36d/6/0

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...