Поиск записи SQL - PullRequest
       8

Поиск записи SQL

0 голосов
/ 10 декабря 2018

Добрый день, сообщество,

Мне нужна помощь для извлечения записи из таблицы MySQL, как показано ниже.Обратите внимание на мои целевые результаты:

Table and result

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

public function usersTopRecruits(){
    $tempUID = array();
    $mainAssocArr = array();
    for ($i=0; $i < User::count(); $i++) { 
        if($i == 0){
            $offset = 0;
        }
        else{           
            $offset = $this->take * $i;
        }

        $users = User::take($this->take)->offset($offset)->get();

        foreach ($users as $value) {
            $refCnts = User::where('referral', $value->aff_id)->count();

            if($refCnts > 0){
                $tempUID['userAffID'] = $value->aff_id;
                $tempUID['userrecruits'] = $refCnts;
                $mainAssocArr[] = $tempUID;
            }
        }
    }//End of For loop

    //Here, i tried to sort by highest recruits

    foreach ($mainAssocArr as $key => $row) {
        $desc[$key]  = $row['userrecruits'];
        $asc[$key] = $row['userAffID'];
    }

    array_multisort($desc, SORT_DESC, $asc, SORT_ASC, $mainAssocArr);

    return $mainAssocArr;
}

Текущий месяц:

public function userTopRecruitsCurrMonth(){
    $tempUID = array();
    $mainAssocArr = array();
    for ($i=0; $i < User::count(); $i++) { 
        if($i == 0){
            $offset = 0;
        }
        else{           
            $offset = $this->take * $i;
        }

        $users = User::take($this->take)->offset($offset)->get();

        foreach ($users as $value) {
            $refCnts = User::where('referral', $value->aff_id)->where('signup_date', '>=', 'startDateOfCurrentMonth')->count();

            if($refCnts > 0){
                $tempUID['userAffID'] = $value->aff_id;
                $tempUID['userRecruits'] = $refCnts;
                $mainAssocArr[] = $tempUID;
            }
        }
    }//End of For loop


    foreach ($mainAssocArr as $key => $row) {
        $volume[$key]  = $row['userRecruits'];
        $edition[$key] = $row['userAffID'];
    }

    array_multisort($volume, SORT_DESC, $edition, SORT_ASC, $mainAssocArr);

    return $mainAssocArr;
}

Буду признателен за любую помощь или предложение.

ПРИМЕЧАНИЕ. Я использую модель Eloquent, но НЕ использую "Laravel "

Ответы [ 2 ]

0 голосов
/ 11 декабря 2018

Я бы использовал такой запрос:

SELECT
    *
FROM
    users AS u0 
JOIN
(
    SELECT
        u1.REFERRAL AS agg,
        COUNT(u1.REFERRAL) AS total
    FROM 
        users AS u1
    GROUP BY
        u1.REFERRAL
    ORDER BY total DESC
) AS u2
ON
    u2.agg = u0.AFF_ID

Подзапрос позволяет вам, снова объединяясь с таблицей, извлекать данные о реальных пользователях, с которыми группируется AFF_ID.Это даст вам такие вещи, как их FIRST_NAME и т. Д. Где, если вы не присоединитесь снова, вы не получите этот материал.

Он также создает меньшую временную (в памяти) таблицу, чем если бы вы делали это натот же уровень (возможно, мне придется копаться в этом с объяснением больше).

Попробуйте сами

Если вы хотите сделать это всего за один месяц, мы можем изменить подзапрос, чтобы подсчитывать только пользователей, добавленных в этом месяце:

SELECT
    *
FROM
    users AS u0 
JOIN
(
    SELECT
        u1.REFERRAL AS agg,
        COUNT(u1.REFERRAL) AS total
    FROM 
        users AS u1
    WHERE 
        YEAR(u1.sigmup_date) = YEAR(NOW())
      AND
        MONTH(u1.sigmup_date) = MONTH(NOW())
    GROUP BY
        u1.REFERRAL
    ORDER BY total DESC
) AS u2
ON
    u2.agg = u0.AFF_ID

Наконец, вам, возможно, придется использовать LEFT JOIN, если вы хотите, чтобы пользователи не ссылались ни на кого.

Например

И если вы добавите что-то вроде

WHERE
  u2.agg IS NULL

В конце внешнего запроса вы можете найти всех пользователей без рефералов,

Например

Любая оптимизация в стороне, лучше (для меня) это сделать как подзапрос.

Последний, есливам не нравится NULL для всего, что вы можете использовать COALESCE(), чтобы исправить это следующим образом:

SELECT
  u0.*, COALESCE(u2.total,0) AS total
FROM
  users AS u0 
LEFT JOIN
(
  SELECT
      u1.REFERRAL AS agg,
      COUNT(u1.REFERRAL) AS total
  FROM 
      users AS u1
  GROUP BY
      u1.REFERRAL
  ORDER BY total DESC
) AS u2
ON
  u2.agg = u0.AFF_ID

DBFiddle

А теперь это 0's

Я считаю COALESCE очень полезным и чем меньше работы, которую вы должны выполнять в коде, тем проще будет.Если вы можете отформатировать данные так, как вы хотите, из БД, то обычно лучше манипулировать ими позже.Может быть разница между использованием чего-то вроде fetchAll и необходимостью зацикливать его и изменять его в PHP, прежде чем вы сможете его использовать.

Cheers!

0 голосов
/ 10 декабря 2018

Из вашего комментария я понимаю, что предоставление вам SQL-запросов может помочь.

Этот простой агрегированный запрос вернет REFERRAL с большинством вхождений (все время), самый высокий сверху.

SELECT referral, COUNT(*) 
FROM table
GROUP BY referral
ORDER BY COUNT(*) DESC

Если вы ищете те же результаты для текущего месяца, просто добавьте предложение WHERE:

SELECT referral, COUNT(*) 
FROM table
WHERE YEAR(sigmup_date) = YEAR(NOW()) AND MONTH(sigmup_date) = MONTH(NOW()) 
GROUP BY referral
ORDER BY COUNT(*) DESC
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...