Как сгруппировать одинаковую информацию из результата запроса sql в php

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

Card 1 expiry date XX-XX-XX
Card 4 expiry date XX-XX-XX
E-mail: [email protected]
Card 2 expiry date YY-YY-YY
Card 3 expiry date YY-YY-YY
E-mail: [email protected]

Вместо того, что я получаю, это электронная почта для каждой карты.

Card 1 expiry date XX-XX-XX
E-mail: [email protected]
Card 4 expiry date XX-XX-XX
E-mail: [email protected]
Card 2 expiry date YY-YY-YY
E-mail: [email protected]
Card 3 expiry date YY-YY-YY
E-mail: [email protected]

Мне это нужно, потому что я буду отправлять электронные письма с информацией, и я не хочу отправлять одно электронное письмо на каждую карту, мне придется сделать одну функцию для отправки всех карт одного и того же клиента в одном электронном письме.

Мой запрос sql следующий:

SELECT Crt.PersonId, Crt.CrtType, Crt.CrtNr, Crt.CrtValidFrom, 
        Crt.CrtValidUntil, Crt.CrtLastTNr, PersonAdd.PersonId AS Expr1, 
        PersonAdd.Email, Crt.CodDate
FROM Crt 
    INNER JOIN PersonAdd ON Crt.PersonId = PersonAdd.PersonId
WHERE (Crt.CrtValidUntil <= CAST(DATEADD(DD, 7, GETDATE()) AS Date))
ORDER BY Crt.CrtNr ASC

И при необходимости я тестирую вывод с помощью этого кода:

while ($rows = $stm->fetch())
    {
        $CPersonUId = isset($rows['PersonId']) ? $rows['PersonId'] : NULL;
        $CType = isset($rows['CrtType']) ? $rows['CrtType'] : NULL;
        $CNr = isset($rows['CrtNr']) ? $rows['CrtNr'] : NULL;
        $CValFrom = isset($rows['CrtValidFrom']) ? $rows['CrtValidFrom'] : NULL;
        $CValUntil = isset($rows['CrtValidUntil']) ? $rows['CrtValidUntil'] : NULL;
        $CLTCCTime = isset($rows['CrtLastTNr']) ? $rows['CrtLastTNr'] : NULL;
        $CLTPEmail = isset($rows['Email']) ? $rows['Email'] : NULL;


        echo "Card nº<b>".$CNr."</b> valid until <b>".$mytime1."</b></br>";
        echo $CLTPEmail."</br>";

    }

И результаты следующие:

Card nº1 valid until 15/11/2018
[email protected]
Card nº2 valid until 15/11/2018
[email protected]

Вместо:

Card nº1 valid until 15/11/2018
Card nº2 valid until 15/11/2018
[email protected]
Group by email
Masivuye Cokile 15.11.2018 12:29

Хорошо, чтобы этот запрос не производил такой вывод, поэтому покажите нам PHP-код, который вы используете для обработки вывода запроса, пожалуйста

RiggsFolly 15.11.2018 12:30

@RiggsFolly добавил код PHP, я редактировал свою тему, потому что подумал, что лучше понять, разместил ли я какой-то код.

Anoushka Iola 15.11.2018 12:33

@MasivuyeCokile Я уже тестировал это, но получил одну ошибку SQL, которую я тестировал, как этот ...GROUP BY PersonAdd.Email ORDER BY Crt.CrtNr ASC, и SQL дает мне следующую ошибку Msg 8120, Level 16, State 1, Line 1 Column 'Crt.PersonId' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.

Anoushka Iola 15.11.2018 12:38
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
4
77
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

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

$last_email = null;

while ($rows = $stm->fetch()) {

    $CPersonUId = isset($rows['PersonId']) ? $rows['PersonId'] : NULL;
    $CType = isset($rows['CrtType']) ? $rows['CrtType'] : NULL;
    $CNr = isset($rows['CrtNr']) ? $rows['CrtNr'] : NULL;
    $CValFrom = isset($rows['CrtValidFrom']) ? $rows['CrtValidFrom'] : NULL;
    $CValUntil = isset($rows['CrtValidUntil']) ? $rows['CrtValidUntil'] : NULL;
    $CLTCCTime = isset($rows['CrtLastTNr']) ? $rows['CrtLastTNr'] : NULL;
    $CLTPEmail = isset($rows['Email']) ? $rows['Email'] : NULL;

    if ( $last_email == null ) {
        $last_email = $CLTPEmail;
    }
    if ( $CLTPEmail != $last_email ) {
        echo $last_email . "</br>";
        $last_email = $CLTPEmail;
    }

    echo "Card nº<b>".$CNr."</b> valid until <b>".$mytime1."</b></br>";

}
// put out the last email 
echo $last_email . "</br>";

Я получаю тот же результат, что и раньше, но теперь с одним предупреждением: Warning: Use of undefined constant CLTPEmail - assumed 'CLTPEmail' (this will throw an Error in a future version of PHP) in...

Anoushka Iola 15.11.2018 12:52

Да, посмотрите еще раз на строку if ( $CLTPEmail != $last_email ) {. Я пропустил $ из CLTPEmail в исходной редакции. Я исправил это сейчас

RiggsFolly 15.11.2018 12:53

Получил, но как-то не показывает почту сейчас

Anoushka Iola 15.11.2018 12:57

Хммм, дай посмотреть, должно быть, пошутил :)

RiggsFolly 15.11.2018 12:58

Ах, посмотрите f ( $CLTPEmail != $last_email ) { echo $last_email . "</br>"; $last_email = $CLTPEmail; }, я отправлял неправильное электронное письмо

RiggsFolly 15.11.2018 13:01

Все еще не работает, но я считаю, что проблема здесь в if ( $CLTPEmail != $last_email ), потому что при первом запуске CLTPEmail не отличается от last_email, поэтому он пропустит его и не будет повторять электронное письмо.

Anoushka Iola 15.11.2018 13:05

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

RiggsFolly 15.11.2018 13:06

Но электронная почта вообще не появляется

Anoushka Iola 15.11.2018 13:11

Сколько результатов вы получаете? А на сколько писем? О, я также забыл отправить последнее электронное письмо, поэтому, если вы тестируете это только с одним электронным письмом, редактирование должно исправить это

RiggsFolly 15.11.2018 13:15

Я тестировал только одно письмо, это было то, что вы сделали: D, спасибо!

Anoushka Iola 15.11.2018 13:22

Если вы действительно хотите сохранить свой запрос, вам придется использовать php для управления результатом и объединения его внутри объекта или массива PHP.

Я обычно использую массив ассоциаций php, чтобы сделать что-то подобное

$data = [];
while ($rows = $stm->fetch())
{
   if (isset($data[$rows['PersonId']]) {
     //use personId as the array key
     $data[$rows['PersonId']] = ['email' => $rows['Email'], 'cardList'=> [] ];
   }
   //add cardNr to CardList property wich also an array
   $data[$rows['personId']] ['cardList'] [] = $rows['CrtNr'];
}

//check using print_r
print_r($data);

Но на самом деле вы можете использовать запрос для получения аналогичного результата, используя GROUP BY и некоторую GROUP CONCAT для объединения значения из нескольких полей, в группе сервера SQL concat аналогичен STRING_AGG.

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

SELECT Crt.PersonId, Crt.Email,
STRING_AGG(CONCAT(CrtNr.,'#',CrtValidFrom,'#',CrtValidUntil ), ',') as card_info
FROM Crt 
INNER JOIN PersonAdd ON Crt.PersonId = PersonAdd.PersonId
WHERE (Crt.CrtValidUntil <= CAST(DATEADD(DD, 7, GETDATE()) AS Date))
GROUP BY Crt.Email
ORDER BY Crt.CrtNr ASC

STRING_AGG аналогична функции GROUP CONCAT в Mysql https://database.guide/the-sql-server-equivalent-to-group_concat/

Я не против изменить свой запрос, я просто не знаю, что в нем изменить, чтобы он заработал

Anoushka Iola 15.11.2018 12:50

Я добавляю пример грубого запроса, который показывает использование GROUP BY и STRING_AGG

kifni41 15.11.2018 12:59

Не могу заставить его работать, после поиска ошибок, которые я получаю в SQL, некоторые люди говорят, что это может быть из-за версии SQL, которую я использую, это 2008 R2

Anoushka Iola 15.11.2018 13:14

Другие вопросы по теме