SQL резултат по определена стойност на колона

djidja83

Registered
Здравейте,
Както вероятно сте разбрали (ако сте видели предишните ми теми) правя дипломна работа по php. Темата е свързана с диети и хранене.
Имам таблица, която има колони id, title, blocks, recipies и eating. В колона eating има само две стойности - основно хранене и междинно хранене. Трябва ми заявка, която да изкара като резултат 2 рецепти със стойност междинно и 3 със стойност основно хранене. Тотално забих.
Моля за помощ - може ли да стане това и как?
Благодаря!
 
Дай малко по-подробна информация. Как са записани данните, от какво зависят точно тези рецепти и т.н.

Аз не следя всичките ти теми и не знам какво си дал(дала?) като информация там.
 
Това е заявката за създаване на таблицата
PHP:
<?php
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "Graduation_thesis";
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
die("За съжаление, MySQL връзката не може да бъде осъществена" . $conn->connect_error);
}
$mysqli = "CREATE TABLE Recipies (
id INT(5) UNSIGNED AUTO_INCREMENT PRIMARY KEY, 
title VARCHAR(90) NOT NULL,
blocks VARCHAR (15) NOT NULL,
recipe TEXT NOT NULL) CHARACTER SET utf8 COLLATE utf8_unicode_ci";
if ($conn->query($mysqli) === TRUE) {
    echo "Таблицата е създадена успешно";
} else {
    echo "Грешка при създаване на таблицата: " . $conn->error;
}
$conn->close();
?>

Въпросната колона е създадена допълнително
PHP:
<?php
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "Graduation_thesis";
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
die("За съжаление, MySQL връзката не може да бъде осъществена" . $conn->connect_error);
}
$mysqli ="ALTER TABLE `Recipies` ADD `eating` VARCHAR(90) NOT NULL AFTER `recipe`";
if ($conn->query($mysqli) === TRUE) {
    echo "Колоната е добавена успешно";
} else {
    echo "Грешка при добавяне на колоната: " . $conn->error;
}
$conn->close();
?>

Таблицата няма външни ключове. ид, заглавие на рецептата, брой блокове в рецептата (това са хранителни блокове, които съдържат определено количество мазнини, въглехидрати и протеини) - стойността на тази колона е примерно "3 блока", "5 блока" и т.н., следващата колона е самата рецепта, а последната колона съдържа информация за това дали една рецепта е подходяща за основно или за междинно хранене в зависимост от броя блокове, които съдържа.
Идеята е потребителят да може да генерира дневно и седмично меню, като при дневното трябва да излязат две рецепти за междинно и три за основно хранене, а за седмичното съответно 7 х 5 като отново 2 са междинно, а три основно.

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

Ето търсачката
PHP:
<?php
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "Graduation_thesis";
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
die("За съжаление, MySQL връзката не може да бъде осъществена" . $conn->connect_error);
}
mysqli_set_charset($conn, 'utf8');
$search = $_POST['search'];
$sql = "SELECT * FROM Recipies WHERE blocks LIKE '%$search%'"; 
$result = mysqli_query ($conn, $sql);
if (!$result) {
    die("Select failed");
}
if (mysqli_num_rows ($result)> 0) {
while ($row = mysqli_fetch_assoc ($result)) {
$id = $row['id'];
$title = $row['title'];
$blocks = $row['blocks'];
echo ('<a href="rec.php?id=' . $id . '">' . $title . ' - ' . $blocks . '<br></a>');
}}
$conn->close();
?>
 
Гледай да използваш повече числови стойности в базата данни. Много по-бързо се работи с тях.

Например колоната blocks. При положение, че знаем, че говорим за хранителни блокове, не е нужно да пише вътре "5 блока", "3 блока" и т.н.
Можеш да я направиш от тип INT и да записваш само числото, след което е нужно само да направиш един селект с наличните хранителни блокове и да се избира по тях, вместо да пише потребителя "искам рецепти с 5 блока".

1. Безсмислено е, поне от моя гледна точка
2. LIKE е по-бавен като операция

За eating също. Можеш да използваш отделна таблица, където да запишеш всички видове хранения и в тази таблица, просто да използваш ID и след това JOIN.

Например:

Таблица Eatings
[sql]
CREATE TABLE Eatings (
`id` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`title` VARCHAR(100) NOT NULL
)
[/sql]

Таблица Recipies
[sql]
CREATE TABLE Recipies (
`id` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`title` VARCHAR(90) NOT NULL,
`blocks` TINYINT (5) NOT NULL,
`recipe` TEXT NOT NULL,
`eating_id` INT(11) NOT NULL,
)
[/sql]

Можеш да си добавиш и foreign keys, ако искаш.

И следователно заявката ще изглежда нещо такова:

[sql]
SELECT r.id, r.title, r.blocks, r.recipe, e.title as `eating`
FROM Recipies r
LEFT JOIN Eatings e
ON r.eating_id = e.id
WHERE r.blocks = 5
[/sql]

Иначе по кода ти не виждам по кое се разбира, че потребителя иска дневна или седмична, за да изкараш само 5 рецепти или 7х5.
 
Все още не съм започнала да пиша въпросната заявка, за това няма как да се види какво се опитвам да направя. Не се сетих как да изкарва 3 основни и 2 междинни хранения. Между другото, това може би може да стане и по броя блокове, тъй като междинните хранения съдържат 1 или два блока, а основните 3 и повече.
Кодът който съм дала е на търсачка, чрез която може да се търси по брой блокове в рецепта.
 
А и между другото, не е ли възможно да получа резултатът, който искам с така създадената таблица, тъй като както казах, пиша дипломна работа за този проект и трябва да се връщам назад да променям и нея.
Благодаря!
 
Можеш разбира се.

Между другото, това може би може да стане и по броя блокове, тъй като междинните хранения съдържат 1 или два блока, а основните 3 и повече.

Добре де, но ако това е така и примерно искам рецепти с 5 блока, как ще ми изкара 2 рецепти за междинно хранене? Или това трябва да е примерно да изкара налични рецепти ДО 5 блока?

Задавам ти въпросите, за да може по-точно да ти се отговори на проблема.
 
Има си търсачка по продукти или брой блокове - по желание на потребителя евентуално.
Тук ми трябва само това - има опции създай дневно меню и създай седмично меню. При избора на първото трябва да излязат 3 рецепти с 3 и повече блока или да са основно хранене (от колона eating) и две с 1 или два блока - междинно хранене от колона eating.
При избор на седмично меню трябва да излизат седем групи с по пет рецепти на същия принцип.
Това няма да е търсачка, а ще трябва да генерира менюта без намесата на потребителя.
Не зная дали обяснявам правилно - надявам се да ме разбирате. :)
 
Най-удобно ще ти е да изкарваш всички рецепти тогава и според какво меню иска започваш да въртиш цикъл, като изкарваш по колкото е нужно за всяка рецепта и буташ в един масив.

По-късно, ако ми остане време и код може да ти дам.

Hint: За да знаеш колко си избрала вече от определен вид хранене, ползвай флагове.

PHP:
$inbetween_flag = 0;
$main_flag = 0;

while( mysqli_fetch_assoc($result) && ($inbetween_flag != 2 && $main_flag != 3) ) {
      // Рецепта за междинно хранене
      if ( $inbetween_flag < 2 ) {
            // пъхаш рецептата в масив
            $inbetween_flag++;
      }

      // Рецепта за основно хранене
      if ( $main_flag < 3 ) {
            // пъхаш рецептата в масив
            $main_flag++;
      }
}

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


Така е когато не знаеш какво правиш :cry: :o

PHP:
$inbetween_flag = 0;
$main_flag = 0;
$a="основно";
$b="междинно";
$sql = "SELECT * FROM Recipies WHERE eating REGEXP '$a|$b' order by RAND()"; 
$result = mysqli_query ($conn, $sql);
if (!$result) {
    die("Select failed");
	}
while( mysqli_fetch_assoc($result) && ($inbetween_flag != 2 && $main_flag != 3) ) {
      if ( $inbetween_flag < 2 ) {
            $inbetween_flag++;
      }

      if ( $main_flag < 3 ) {
            $main_flag++;
      }

{
$row = mysqli_fetch_assoc($result);
$id = $row['id'];
$title = $row['title'];
$blocks = $row['blocks'];
$eating = $row['eating'];


echo ('<a href="rec.php?id=' . $id . '">' . $title . ' - ' . $blocks . ' - ' . $eating . '<br></a>');
	}}
$conn->close();
?>
 
Я си оправи малко къдравите скоби, че нещо не разбирам къде какво отваряш, какво затваряш... :D :D
 
Revelation каза:
Я си оправи малко къдравите скоби, че нещо не разбирам къде какво отваряш, какво затваряш... :D :D

Намерих едни излишни ... :D
Не зная дали са само те.
 
Има още излишни и код излишен(направо грешен).

Сега ще ти го надраскам набързо. Няма да го тествам, че не ми се правят тестови данни в момента.

Междувременно, тествай заявката дали ти връща резултатите, които очакваш и пиши.
 
Много ти благодаря - махах, слагах, променях - никакъв ефект. Само това ми остана от целия проект. Ще тествам и ще пиша.
Благодаря!
 
PHP:
<?php

// connection

$main_string = "основно";
$inbetween_string = "междинно";
$sql = "SELECT * FROM Recipies WHERE eating REGEXP '$a|$b' ORDER BY RAND()"; 
$result = mysqli_query($conn, $sql);

// Взимаме всички върнати рецепти
$recipies = mysqli_fetch_assoc($result);

// Декларираме празен масив, където ще слагаме 
// рецептите за междинно хранене
$inbetween_recipies = [];

// Декларираме празен масив, където ще слагаме
// рецептите за основно хранене
$main_recipies = [];

// Въртим цикъла докато не съберем 2 рецепти за междинно и 3 рецепти за основно
while( ((count($inbetween_recipies) < 2) && (count($main_recipies) < 3)) ) {

	// Взимаме случайна рецепта (ако искаш да е случайна естествено)
	$recipe = array_rand($recipies);

	// Ако рецептата е за междинно хранене и не сме взели нужния брой
	// то добавяме към масива за рецепти за междинно хранене
	if ( $recipe['eating'] == $inbetween_string && count($inbetween_recipies) < 2 ) {
		$inbetween_recipies[] = $recipe;
	}

	// Ако рецептата е за основно хранене и не сме взели нужния брой
	// то добавяме към масива за рецепти за основно хранене
	if ( $recipe['eating'] == $main_string && count($main_recipies) < 3 ) {
		$main_recipies[] = $recipe;
	}
}

// Когато приключи цикъла е нужно да комбинираме двата масива
$collected_recipies = array_merge($main_recipies, $inbetween_recipies);

// Принтираме линкове към рецептите
foreach( $collected_recipies as $k => $recipe ) {
	printf('<a href="rec.php?id=%d"> %s - %s - %s</a><br />', $recipe['id'], $recipe['title'], $recipe['blocks'], $recipe['eating']);
}

Не съм тествал кода, може и да има грешки.

Малко промених логиката. Де факто въртя цикъла докато взема нужните рецепти, като взимам random рецепти.
Не съм правил проверка дали вече рецептата е взета, така че може да стане така че има повтарящи, но ако това сработи, лесно ще ти добавя и проверката.
 
Можеш да вземеш 3 основни и 2 междинни с 1 UNION заявка, но понеже можеш да имаш сортиране и лимит само веднъж в 1 заявка ще трябва да направиш UNION от две заявки - първата взима 3 случайни основни, втората взима 2 случайни междинни
PHP:
$sql = "SELECT * FROМ 
(SELECT * FROM Recipies 
WHERE eating = 'основно' 
order by RAND() LIMIT 3) r1 
UNION 
SELECT * FROM 
(SELECT * FROM Recipies 
WHERE eating = 'междинно' 
order by RAND() LIMIT 2) r2"; 
$result = mysqli_query($conn, $sql);
if (!$result) {
    die("Select failed");
	}
while($row = mysqli_fetch_assoc($result)) {
$id = $row['id'];
$title = $row['title'];
$blocks = $row['blocks'];
$eating = $row['eating'];


echo ('<a href="rec.php?id=' . $id . '">' . $title . ' - ' . $blocks . ' - ' . $eating . '<br></a>');
	}
$conn->close();
?>
 
raiden каза:
Можеш да вземеш 3 основни и 2 междинни с 1 UNION заявка, но понеже можеш да имаш сортиране и лимит само веднъж в 1 заявка ще трябва да направиш UNION от две заявки - първата взима 3 случайни основни, втората взима 2 случайни междинни

Само по този начин не се сетих да направя вложените селекти, да го ... :D :D

П.П. Сигурен ли си, че заявката в това си състояние ще работи?
 
Сега ми излиза това

Warning: Illegal string offset 'eating' in C:\xampp\htdocs\menu1.php on line 61

Warning: Illegal string offset 'eating' in C:\xampp\htdocs\menu1.php on line 67


Имаше и друга грешка, но нея я оправих - не съм съвсем боса :D .
 
Revelation каза:
raiden каза:
Можеш да вземеш 3 основни и 2 междинни с 1 UNION заявка, но понеже можеш да имаш сортиране и лимит само веднъж в 1 заявка ще трябва да направиш UNION от две заявки - първата взима 3 случайни основни, втората взима 2 случайни междинни

Само по този начин не се сетих да направя вложените селекти, да го ... :D :D
:D :D
Страшен loop иначе, само трябва да оправиш вътрешния иф за междинните да е < 1 иначе ако вземе 2 междинни преди 3 основни и попадне на междинно ще го добави :?:
Edit: https://www.db-fiddle.com/f/ahkhotu2VKj254qbKnjq79/0
 

Back
Горе