История на поръчките

@Relevation, не знам как стои въпроса с поддръжката, от няколко години работя с PostgreSQL, а исках да покажа възможно решение и видях, че в нея вече има такива функции (между другото WITH ... AS ... също се въвежда с 8 версия). Иначе вероятно масово се ползва 5.1.73 като най-зряла и надеждна. А примера ми цели именно да го откаже от подобни гимнастики и да го насочи в "правия път" (нормализация) ;). Подобни структури не трябва да се използват в общи случаи, а само когато други фактори, неподлежащи на промяна, го налагат. Но тук търсим конкретно решение на конкретен проблем.
Относно логиката в PHP - да, сортиране и следене за промяна е ОК и кода ти го демонстрира много добре, същият подход се използва за групиране и калкулиране на sub(totals) в Excel.
Отидохме много offtopic, @teroristd ако имаш желание да научиш повече за това как се подхожда при създаване на структурата на данните в релационна БД можеш да ми пишеш съобщение, ще ти пратя материали за четене.
 
PHP:
$lastId = $result[0]['order_id']-1;
foreach ( $result as $row ) {
	if ($row['order_id'] > $lastId ) {
		echo "Поръчка #" . ($lastId+1) . PHP_EOL;
		$lastId = $row['order_id'];
	} else if ( $row['order_id'] < $lastId ) {
		echo "Поръчка #" . ($lastId-1) . PHP_EOL;
		$lastId = $row['order_id'];
	}
	echo "\t Предмет: " . $row['product'] . PHP_EOL;
}

Малко промяна, за да работи във възходящ и низходящ ред.
 
Revelation каза:
ttta каза:
Превръщаш данни в стринг след това го сплитваш отново към данните от които си го съставил.

Другият вариант, който аз предпочитам е, да си извлека всички ордери за конкретния потребител и при въртенето на цикъла да ги разделям.

PHP:
$sth = $dbh->query("SELECT * FROM orders WHERE email='ivan@abv.bg' ORDER BY order_id");
$result = $sth->fetchAll(PDO::FETCH_ASSOC);

echo "<pre>";
$i = 1;
$lastId = 0;
foreach ( $result as $row ) {
	if ($row['order_id'] > $lastId ) {
		echo "Поръчка #" . $i . PHP_EOL;
		$lastId = $row['order_id'];
		$i++;
	}
	echo "\t Предмет: " . $row['product'] . PHP_EOL;
}
echo "</pre>";

Резултат:
PHP:
Поръчка #1
	 Предмет: дънки
	 Предмет: блуза
Поръчка #2
	 Предмет: яке

Благодаря за отговорите. За сега ще се съсредоточа върху решението на @Revelation, което работи както се очаква.

Искам да направя същото нещо и в администраторската част, но с тази разлика че трябва да се изведат поръчките на всички потребители. Един вид потребител Иван - поръчките, потребител Петкан - поръчките.

Как ще стане?
 
Най-лесно може да стане, като си извеждаш списък с потребителите. И при избиране на определен потребител да вадиш данните само за него по същия начин.
Не мисля, че е добра идея да вадиш абсолютно всички поръчки, на всички потребители, на един път.


П.П.

Иначе идеята е подобна:

PHP:
$lastId = $result[0]['order_id']-1;
$lastUser = "";
foreach ( $result as $row ) {
	if ( $row['name'] != $lastUser ) {
		printf("%s\n", $row['name']);
		$lastUser = $row['name'];
	}
	if ($row['order_id'] > $lastId ) {
		printf("\tПоръчка #%d\n", ($lastId+1));
		$lastId = $row['order_id'];
	} else if ( $row['order_id'] < $lastId ) {
		printf("\tПоръчка #%d\n", ($lastId-1));
		$lastId = $row['order_id'];
	}
	printf("\t\tПредмет: %s\n", $row['product']);
}
Като махаш WHERE клаузата от заявката.

И ето защо не е хубаво да пазиш имената на потребителите, а ID от друга таблица. С числа се работи по-лесно и в бъдеще промените стават доста по-удобни и по-лесни.

Резултат:
PHP:
Иван
	Поръчка #1
		 Предмет: дънки
		 Предмет: блуза
	Поръчка #2
		 Предмет: яке
	Поръчка #3
		 Предмет: жилетка
Петкан
	Поръчка #4
		 Предмет: блуза
		 Предмет: риза
 
Revelation каза:
Най-лесно може да стане, като си извеждаш списък с потребителите. И при избиране на определен потребител да вадиш данните само за него по същия начин.
Не мисля, че е добра идея да вадиш абсолютно всички поръчки, на всички потребители, на един път.

Това няма да ми свърши работа, защото поръчките трябва да бъдат изпълнени. В смисъл ако има 1000 потребители не може да се преглеждат всеки ден един по един за да се види дали са направили поръчка.
 
teroristd каза:
Revelation каза:
Най-лесно може да стане, като си извеждаш списък с потребителите. И при избиране на определен потребител да вадиш данните само за него по същия начин.
Не мисля, че е добра идея да вадиш абсолютно всички поръчки, на всички потребители, на един път.

Това няма да ми свърши работа, защото поръчките трябва да бъдат изпълнени. В смисъл ако има 1000 потребители не може да се преглеждат всеки ден един по един за да се види дали са направили поръчка.

Промених си мнението с решението, което търсиш.
 
Наново промених кода, заради крайния резултат(нулиране на брояча на поръчките за определен потребител).

PHP:
$lastId = $result[0]['order_id']-1;
$lastUser = "";
$i = 1;
foreach ( $result as $row ) {
	if ( $row['name'] != $lastUser ) {
		printf("%s\n", $row['name']);
		$lastUser = $row['name'];
		$i = 1;
	}
	if ($row['order_id'] > $lastId ) {
		printf("\tПоръчка #%d\n", $i++);
		$lastId = $row['order_id'];
	} else if ( $row['order_id'] < $lastId ) {
		printf("\tПоръчка #%d\n", $i++);
		$lastId = $row['order_id'];
	}
	printf("\t\tПредмет: %s\n", $row['product']);
}

Резултат:
PHP:
Иван
	Поръчка #1
		Предмет: дънки
		Предмет: блуза
	Поръчка #2
		Предмет: яке
	Поръчка #3
		Предмет: жилетка
Петкан
	Поръчка #1
		Предмет: блуза
		Предмет: риза
 
А каква е заявката, че при мен нещо не излиза номера на поръчката на Петкан. А ако добавя втора поръчка на Иван излиза така.

Резултат:
PHP:
Иван
	Поръчка #1
		Предмет: дънки
Петкан
		Предмет: блуза
Иван
	Поръчка #2
		Предмет: яке
 
teroristd каза:
А каква е заявката, че при мен нещо не излиза номера на поръчката на Петкан. А ако добавя втора поръчка на Иван излиза така.

Резултат:
PHP:
Иван
	Поръчка #1
		Предмет: дънки
Петкан
		Предмет: блуза
Иван
	Поръчка #2
		Предмет: яке
Еми.. просто сортирай по човек?

ORDER BY user_id примерно?
 
http://prikachi.com/images/899/9167899Z.png

При мен си е добре. Не знам ти какво точно правиш.

Нещо в базата да не се различава? Макар че аз я направих по твоята структура.
 
Ето я моята таблица.

http://prikachi.com/images.php?images/949/9167949N.jpg

Мисля че разбрах, къде се чупи. При мен order_id не е като при теб. Фактически аз имам order_id 1 за Иван и order_id 1 за Петкан. Аз броя за всеки юзър отделно поръчките. Докато при теб за Петкан идва order_id 4 въпреки че му е първа поръчка.

Но всъщност по-големия проблем е че не мога да пресметна общата цена на отделната поръчка. По-принцип я смятам така, като counter ми е бройката, и си работи коректно.

PHP:
$total_price=0;
$total_price += ($value['price'] * $value['counter']);
echo $total_price;

Обаче в нашия случай смята цената за всички поръчки.
 
Това, че order_id се повтаря при различните юзъри, не би трябвало да е проблем при сортирането по име на потребител? Ако първо сортираш по email примерно, и след това по order_id, то тогава поръчките на всеки потребител ще са заедно, и output-а ще излиза правилно.

Относно другия проблем - ако изпълняваш онези три реда за всеки запис в orders, как ще смята общата цена на всички поръчки като трите реда са вътрешни за всяка итерация (т.е. всяка обработка на отделна поръчка - това няма достъп до останалите поръчки, => не може да сметне и общата стойност?)
 
anonimen каза:
Това, че order_id се повтаря при различните юзъри, не би трябвало да е проблем при сортирането по име на потребител? Ако първо сортираш по email примерно, и след това по order_id, то тогава поръчките на всеки потребител ще са заедно, и output-а ще излиза правилно.

Пробвал съм по email и по order_id, и по всякакви начини не става. Така или иначе го направих както @Revelation и си работи.

anonimen каза:
Относно другия проблем - ако изпълняваш онези три реда за всеки запис в orders, как ще смята общата цена на всички поръчки като трите реда са вътрешни за всяка итерация (т.е. всяка обработка на отделна поръчка - това няма достъп до останалите поръчки, => не може да сметне и общата стойност?)

Честно казано не те разбрах какво имаш предвид. Ето какво имам. Къде трябва да ги сложа за да смята правилно?
PHP:
$i = 1;
        $lastId = 0;
        $lastUser = '';
        
        foreach ($result as $row)
        {
            if ($row['first_name'] != $lastUser)
            {
                echo $row['first_name'] . '<br>';
                $lastUser = $row['first_name'];
                $i = 1;
            }
            if ($row['order_id'] > $lastId)
            {
                echo '<br> <a href="">Поръчка № ' . $i . '</a> <br>';
                $lastId = $row['order_id'];
                $i++;
            }
            echo '<br><img src="http://localhost/market/uploads/' . $row['image'] . '" width="120"/><br>';
        }
 
$i = 1;
$lastId = 0;
$lastUser = '';

$price = 0;

foreach ($result as $row)
{
if ($row['first_name'] != $lastUser)
{
echo $row['first_name'] . '<br>';
$lastUser = $row['first_name'];
$i = 1;
echo $price; // цената на предишната поръчка. Print & reset - започва нов юзър
$price = 0;
}
if ($row['order_id'] > $lastId)
{
echo $price; // това е цената на предишната поръча
$price = 0; // нулираме - започва нова поръчка
echo '<br> <a href="">Поръчка № ' . $i . '</a> <br>';
$lastId = $row['order_id'];
$i++;
}
echo '<br><img src="http://localhost/market/uploads/' . $row['image'] . '" width="120"/><br>';
$price += $row['price']; // или както ти те казваше колоната
}
 
Не се получава така.

Резултат:
PHP:
Иван
        Цена: 0
        Цена: 0
	Поръчка #1
		Предмет: дънки
                Предмет: блуза
        Цена: 41.2 // цената е точна
	Поръчка #2
		Предмет: яке
Петкан
        Цена: 0
        Цена: 35 // това е цената за поръчка 2 на Иван, а неговата я няма
        Поръчка #1
		Предмет: блуза
 
Да, защото проверките минават още при първата итерация, когато още нямаш поръчки. Тук:

PHP:
$i = 1;
$lastId = 0;
$lastUser = ''; // тази ст-ст е различна от $row[first_name] при първата итерация, затова по-надолу:

$price = 0;

foreach ($result as $row)
{
if ($row['first_name'] != $lastUser) // при първата итерация това минава
Можеш да сложиш проверки при принтването на цената

PHP:
if(!empty($lastUser) echo 'Цена';
за да не излизат нулите.

Също, след края на цикъла не се принтват, защото не се triggerва промяна в името на юзера - просто цикълът излиза и няма кой да принте. Можеш ръчно да добавиш echo 'цена' след цикъла.

Като цяло това почва да става малко грозно... И всъщност тук си проличава къде дизайнът не е добър - почва да се повтаря код и да се правят допълнителни проверки по странни места, за да се "поправи", но всъщност така само се замазва положението. Ако впоследствие добавиш още таблици и детайли по поръчките, тези неща ще продължават да се натрупват и ще/може да стане каша. Така че ти препоръчвам отрано да премислиш дали наистина искаш да продължаваш така.
 
anonimen каза:
Да, защото проверките минават още при първата итерация, когато още нямаш поръчки. Тук:

PHP:
$i = 1;
$lastId = 0;
$lastUser = ''; // тази ст-ст е различна от $row[first_name] при първата итерация, затова по-надолу:

$price = 0;

foreach ($result as $row)
{
if ($row['first_name'] != $lastUser) // при първата итерация това минава
Можеш да сложиш проверки при принтването на цената

PHP:
if(!empty($lastUser) echo 'Цена';
за да не излизат нулите.

Също, след края на цикъла не се принтват, защото не се triggerва промяна в името на юзера - просто цикълът излиза и няма кой да принте. Можеш ръчно да добавиш echo 'цена' след цикъла.

Като цяло това почва да става малко грозно... И всъщност тук си проличава къде дизайнът не е добър - почва да се повтаря код и да се правят допълнителни проверки по странни места, за да се "поправи", но всъщност така само се замазва положението. Ако впоследствие добавиш още таблици и детайли по поръчките, тези неща ще продължават да се натрупват и ще/може да стане каша. Така че ти препоръчвам отрано да премислиш дали наистина искаш да продължаваш така.

Мазалото ще става огромно. Да не говорим, че ако по този начин продължава да генерира view. Кода ще е нечетим, заявките ще се усложняват и накрая ще реши да го пренапише отначало, защото за да го поправи ще му отнеме повече време.

@teroristd не знам дали @raiden ти е изпратил това, за което говореше, но ако е - прочети.
Аз ти дадох прост пример за 3 таблици. Върни се в началото и виж. Но със сигурност ще трябва да прочетеш повече за базата данни.
 

Горе