Webmaster общности: Predpriemach.com | SearchEngines.bg

    MySQL релация – Създаване на система с категории

    Автор: adrian

    Тъй като много често има теми във форума за това как се правят категории реших да напиша урок.
    В този урок ще ви покажа как да създадете таблица за категории и след това как се свързва с новини.
    Ще използвам примерна система за новини, но може да се направи за всякакъв род сайтове, които се нуждаят от категории.
    Например сайтове за филми, уроци, online магазини, игри и т.н.
    Важно е да се схване принципа на връзката между две таблици в базата данни от типа „едно към много“.

    Отношение „едно към много“ между две таблици съществува тогава, когато един запис от първата таблица, наречена родителска, може да бъде свързан с много записи от втората таблица, наречена дъщерна, но запис от дъщерната таблица може да бъде свързан само с един запис от родителската таблица.

    Както се вижда от картинката няколко новини могат да бъдат от една една и съща категория.
    Връзката между 2-те таблици са полетата catid от таблицата на новините и полето id от таблицата
    на категориите.
    С една заявка вие може да определите кои новини към коя категория спадат.

    Ето и стъпките за създаването на примерна система за новини с категории.

    config.php

    <?php
    $host = "localhost";
    $username = "root";
    $password = "";
    $database = "wt";
    ?>

    I стъпка – създаване на таблиците
    Първо ще създадем таблицата за категориите. Тя ще съдържа само две полета id и name:

    CREATE TABLE IF NOT EXISTS `categories` (
    `id` tinyint(3) unsigned NOT NULL auto_increment,
    `name` varchar(15) NOT NULL,
    PRIMARY KEY (`id`)
    )

    Тук няма какво толкова да се обяснява.
    Създава се едно поле id tinyint unsigned. tinyint, защото едва ли ще имаме повече от 255 категории, а unsigned, защото категориите ни ще са само положителни числа.
    Повече за mysql int типът можете да видите тук
    Второто поле е varchar(15), защото в примера 15 е достатъчно дълго, за да побере имената на категориите в примера.

    Сега да предположим, че имаме една таблица за новини. В примера новините няма да имат текст, а само заглавие и id:

    CREATE TABLE IF NOT EXISTS `news` (
    `id` int(10) unsigned NOT NULL auto_increment,
    `title` varchar(50) NOT NULL,
    PRIMARY KEY (`id`)
    )

    II стъпка – свързване на двете таблици
    Лесно е да се забележи, че тези две таблици не са свързани по никакъв начин. Точно затова трябва в таблицата news да създадем едно поле, в което ще записваме в коя категория е дадената новина. Това ще стане като добавим следния код:

    ALTER TABLE news ADD catid tinyint unsigned NOT NULL

    или ако сега създаваме таблицата с новини можем да я създадем директно с връзката към категориите:

    CREATE TABLE IF NOT EXISTS `news` (
    `id` int(10) unsigned NOT NULL auto_increment,
    `title` varchar(50) NOT NULL,
    `catid` tinyint(3) unsigned NOT NULL,
    PRIMARY KEY (`id`)
    )

    III стъпка – напълваме с малко информация таблиците
    Създаваме 7 категории:

    INSERT INTO `categories` (`id`, `name`) VALUES
    (1, 'Категория 1'),
    (2, 'Категория 2'),
    (3, 'Категория 3'),
    (4, 'Категория 4'),
    (5, 'Категория 5'),
    (6, 'Категория 6'),
    (7, 'Категория 7');

    и вкарваме по няколко заглавия във всички без последната (за сега оставете поне една категория празна, за да видим една особенност в заявката за изкарването на новините – във видео урока).

    INSERT INTO `news` (`id`, `title`, `catid`) VALUES
    (1, 'Новина 1, категория 1', 1),
    (2, 'Новина 2, категория 1', 1),
    (3, 'Новина 3, категория 1', 1),
    (4, 'Новина 1, категория 2', 2),
    (5, 'Новина 2, категория 2', 2),
    (6, 'Новина 1, категория 3', 3),
    (7, 'Новина 1, категория 4', 4),
    (8, 'Новина 2, категория 4', 4),
    (9, 'Новина 3, категория 4', 4),
    (10, 'Новина 4, категория 4', 4),
    (11, 'Новина 1, категория 5', 5),
    (12, 'Новина 2, категория 5', 5),
    (13, 'Новина 3, категория 5', 5),
    (14, 'Новина 4, категория 5', 5),
    (15, 'Новина 5, категория 5', 5),
    (16, 'Новина 1, категория 6', 6),
    (17, 'Новина 2, категория 6', 6),
    (18, 'Новина 3, категория 6', 6),
    (19, 'Новина 4, категория 6', 6),
    (20, 'Новина 5, категория 6', 6),
    (21, 'Новина 6, категория 6', 6),
    (22, 'Новина 7, категория 6', 6),
    (23, 'Новина 8, категория 6', 6);

    IV стъпка – Създаване на менюто с категориите
    След като сме създали и напълнили таблиците вече сме свършили повече от половината работа. Остава единствено да направим кодовете, които да ни групират новините по категории (те вече са групирани, остава само да ги изкарваме правилно):

    <?php
    include("config.php"); //Инклудваме config файла, който съдържа хоста, потребителското име, паролата и базата данни
    
    $connect = mysql_connect($host, $username, $password)
    or die("Не може да свърже с базата данни"); //Правим връзка със сървъра и при неуспех изкарваме грешка
    mysql_select_db($database, $connect)
    or die("Не може да селектира базата данни"); //Селектираме базата данни и при неуспех отново изкарваме грешка
    mysql_query("SET CHARACTER SET cp1251"); //Това съм го сложил защото при създаването на базата данни използвах колация cp1251_bulgarian_ci
    $result = mysql_query("SELECT c.id, c.name, count(n.id) as count FROM categories as c LEFT OUTER JOIN news as n ON c.id = n.catid GROUP BY c.id")
    or die("Не може да изпълни заявката"); //Правим заявката, към базата данни. Нея ще я обясня под кода
    while($row = mysql_fetch_array($result)) {
    echo '<a href="news.php?category='.$row['id'].'">'.$row['name'].' ('.$row['count'].')</a><br />'; //изкарваме линк към страницата с новини от категориите
    }
    ?>

    SELECT c.id, c.name, count(n.id) as count – взимаме само нужните полета, а не цялото съдържание на таблицата. Нужни са ни id на категорията, името на категорията и броя на новините в дадена категория. Префиксите c. и n. се използват за по-кратко записване. Ако го нямаше categories as c и news as n, трябваше да се изписват с цялото име на таблицата, което е твърде много писане.
    FROM categories as c LEFT OUTER JOIN news as n ON c.id = n.catid – Повече за LEFT OUTER JOIN. Налага се да използваме LEFT OUTER JOIN, защото искаме да изкараме броя на новините. Благодарение на LEFT OUTER JOIN тук изкарваме всички записи от лявата таблица (categories) и смятаме броя на новините в категориите. ON c.id = n.catid – ето заради това ни трябваше да свържем двете таблици по някакъв начин.
    Но заявката до тук не е достатъчна (пробвайте я без GROUP BY), защото без GROUP BY ще излезе само първия резултат като се сметне, че всички новини принадлежат на него и в моя промер ще изкара: Категория 1 (23)
    GROUP BY c.id – Повече за GROUP BY. Накратко тук GROUP BY играе ключова роля за това да можем да изкараме правилния резултат. GROUP BY се използва със събирателните функции като sum, count и т.н, за да може да разграничи сумирането или броенете (както е в нашия случай) по даден критерии. В примера се групират по id на категорията, но може и по име. Така за всяка отделна категория се смята по отделно колко новини има в нея.

    Ако не искаме да изкарваме броя на новините в дадената категория си спестяваме главоболията по разбирането на горната заявка и кодът може да стане чисто и проста така:

    <?php
    include("config.php");
    
    $connect = mysql_connect($host, $username, $password)
    or die("Не може да свърже с базата данни");
    mysql_select_db($database, $connect)
    or die("Не може да селектира базата данни");
    mysql_query("SET CHARACTER SET cp1251");
    $result = mysql_query("SELECT id, name FROM categories")
    or die("Не може да изпълни заявката");
    while($row = mysql_fetch_array($result)) {
    echo '<a href="news.php?category='.$row['id'].'">'.$row['name'].'</a><br />';
    }
    ?>

    V стъпка – преглеждане на новините само от избраната категория
    Както виждате сега линковете от менюто водят към news.php?category=число. Това е така, за да можем да преглеждаме заглавията на новините от всяка категория поотделно:

    <?php
    include("config.php"); //Инклудваме config файла, който съдържа хоста, потребителското име, паролата и базата данни
    $connect = mysql_connect($host, $username, $password)
    or die("Не може да свърже с базата данни"); //Правим връзка със сървъра и при неуспех изкарваме грешка
    mysql_select_db($database, $connect)
    or die("Не може да селектира базата данни"); //Селектираме базата данни и при неуспех отново изкарваме грешка
    mysql_query("SET CHARACTER SET cp1251"); //Това съм го сложил защото при създаването на базата данни използвах колация cp1251_bulgarian_ci
    $category = 1; //Присвояваме на $category 1, така винаги $category ще има някаква валидна стойност
    if(isset($_GET['category']) and is_numeric($_GET['category'])) { // Правим проверка дали имаме подадена $_GET променлива category и дали тя е число
    $category = intval($_GET['category']); //Ако проверката е върнала true заменяме стойността на $category с числената стойност на $_GET['category']. Тук се използва intval, за да превърне всяка стойност, минала проверката в цяло число. Махнете intval() и пробвайте да извикате скрипта с news.php?category=4.5, за да видите за какво се използва.
    }
    $result = mysql_query("SELECT c.name, n.title FROM news as n LEFT OUTER JOIN categories as c ON n.catid = c.id WHERE n.catid = '".$category."'")
    or die("Не може да изпълни заявката"); //тук пак използваме LEFT OUTER JOIN, защото изкарваме категорията на новината до нейното заглавие.
    if(mysql_num_rows($result) > 0) { //Ако има повече от 0 резултати
    while($row = mysql_fetch_array($result)) {
    echo $row['title']. " в категория: ". $row['name']."<br />"; //изкарваме името на новината и името на категоията, в която се намира дадената новина
    }
    } else { //Ако е 0
    echo "Няма резултати в тази категория."; //изкарваме, че няма резултати в тази категория
    }
    ?>

    Тук пак се налага да използваме LEFT OUTER JOIN, защото искаме да изкараме името на категорията. В реални ситуации това едва ли би било така, затова можем да преправим скрита така:

    <?php
    include("config.php");
    $connect = mysql_connect($host, $username, $password)
    or die("Не може да свърже с базата данни");
    mysql_select_db($database, $connect)
    or die("Не може да селектира базата данни");
    mysql_query("SET CHARACTER SET cp1251");
    $category = 1;
    if(isset($_GET['category']) and is_numeric($_GET['category'])) {
    $category = intval($_GET['category']);
    }
    $result = mysql_query("SELECT title FROM news WHERE catid = '".$category."'")
    or die("Не може да изпълни заявката");
    if(mysql_num_rows($result) > 0) {
    while($row = mysql_fetch_array($result)) {
    echo $row['title']."<br />";
    }
    } else {
    echo "Няма резултати в тази категория.";
    }
    ?>

    Примерен код видео урока има във файловете за сваляне.

    Файлове за сваляне

    Оставете коментар