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: :eek:

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
 

Горе