آموزش برنامه نویسی PHP-جلسه بیست و ششم

آموزش برنامه نویسی PHP-جلسه بیست و ششم

در این قسمت از آموزش PHP و MySQL با دستور WHERE آشنا می‌شویم و یاد می‌گیریم چگونه اطلاعات دیتابیس را بر اساس شرایط مشخص فیلتر کنیم. همچنین نحوه استفاده از عملگرهای AND، OR، LIKE، IN و BETWEEN و اجرای کوئری‌های شرطی با PDO و MySQLi را همراه با مثال‌های کاربردی بررسی خواهیم کرد.

با استفاده از WHERE می‌توانیم کاربران خاصی را پیدا کنیم، محصولات یک دسته‌بندی مشخص را نمایش دهیم، سفارش‌های پرداخت‌شده را دریافت کنیم، اطلاعات را بر اساس قیمت یا تاریخ فیلتر کنیم و جستجوهای پیشرفته‌تری در پایگاه داده انجام دهیم.

در این آموزش، ابتدا ساختار دستور WHERE را بررسی می‌کنیم و سپس با عملگرهای مقایسه‌ای، AND، OR، NOT، LIKE، IN، BETWEEN، IS NULL و سایر روش‌های فیلتر کردن اطلاعات آشنا می‌شویم. در ادامه نیز مثال‌های عملی با PHP، PDO و MySQLi ارائه خواهیم کرد.

Table of contents [Show] [Hide]

۱. دستور WHERE در MySQL چیست؟

دستور WHERE برای مشخص کردن شرط و فیلتر کردن رکوردهای یک جدول استفاده می‌شود. این دستور معمولاً همراه با SELECT، UPDATE و DELETE به کار می‌رود.

به کمک WHERE می‌توانیم تعیین کنیم که فقط رکوردهایی انتخاب شوند که یک یا چند شرط مشخص را داشته باشند.

ساختار کلی WHERE در دستور SELECT به شکل زیر است:

SELECT column1, column2, ...
FROM table_name
WHERE condition;

در این ساختار:

  • SELECT: ستون‌هایی را که قصد دریافت آن‌ها را داریم مشخص می‌کند.
  • FROM: نام جدول موردنظر را تعیین می‌کند.
  • WHERE: شرط فیلتر کردن رکوردها را مشخص می‌کند.
  • condition: عبارتی است که باید برای انتخاب رکوردها بررسی شود.

برای مثال، فرض کنید جدولی به نام users داریم و می‌خواهیم فقط اطلاعات کاربری با شناسه ۱ را دریافت کنیم:

SELECT * FROM users
WHERE id = 1;

این دستور فقط رکوردی را برمی‌گرداند که مقدار ستون id آن برابر با ۱ باشد.

۲. ایجاد جدول نمونه برای تمرین WHERE

برای درک بهتر مثال‌های این آموزش، فرض می‌کنیم جدولی با نام users داریم که اطلاعات کاربران در آن ذخیره شده است.

ساختار جدول به شکل زیر است:

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(150) NOT NULL,
    age INT,
    city VARCHAR(100),
    status VARCHAR(20),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

برای وارد کردن اطلاعات آزمایشی می‌توانیم از دستور INSERT استفاده کنیم:

INSERT INTO users (name, email, age, city, status)
VALUES
('Ali', 'ali@example.com', 25, 'Tehran', 'active'),
('Sara', 'sara@example.com', 30, 'Shiraz', 'active'),
('Reza', 'reza@example.com', 17, 'Tabriz', 'inactive'),
('Mina', 'mina@example.com', 22, 'Tehran', 'active'),
('Amir', 'amir@example.com', 35, 'Mashhad', 'inactive'),
('Neda', 'neda@example.com', 28, 'Shiraz', 'active');

اکنون جدول users اطلاعاتی مشابه جدول زیر دارد:

idnameemailagecitystatus
1Aliali@example.com25Tehranactive
2Sarasara@example.com30Shirazactive
3Rezareza@example.com17Tabrizinactive
4Minamina@example.com22Tehranactive
5Amiramir@example.com35Mashhadinactive
6Nedaneda@example.com28Shirazactive

در ادامه تمام مثال‌ها را با استفاده از همین جدول بررسی می‌کنیم.

۳. استفاده از عملگر مساوی (=) در WHERE

ساده‌ترین روش فیلتر کردن اطلاعات، استفاده از عملگر مساوی است. این عملگر زمانی استفاده می‌شود که بخواهیم رکوردهایی را انتخاب کنیم که مقدار یک ستون دقیقاً برابر با مقدار مشخصی باشد.

برای مثال، دریافت کاربرانی که در شهر تهران زندگی می‌کنند:

SELECT * FROM users
WHERE city = 'Tehran';

این کوئری فقط اطلاعات کاربرانی را نمایش می‌دهد که مقدار ستون city آن‌ها برابر با Tehran است.

مثال دیگر، دریافت کاربران فعال:

SELECT * FROM users
WHERE status = 'active';

نکته: در SQL معمولاً مقادیر متنی داخل کوتیشن قرار می‌گیرند، اما مقادیر عددی را می‌توان بدون کوتیشن نوشت.

۴. عملگرهای مقایسه‌ای در دستور WHERE

برای فیلتر کردن اطلاعات بر اساس مقادیر عددی یا مقایسه‌ای، می‌توانیم از عملگرهای مختلف استفاده کنیم.

عملگرمعنیمثال
=مساویage = 25
!=نامساویage != 25
<>نامساویage <> 25
>بزرگ‌تر ازage > 18
<کوچک‌تر ازage < 18
>=بزرگ‌تر یا مساویage >= 18
<=کوچک‌تر یا مساویage <= 30

مثال اول: دریافت کاربران بالای ۱۸ سال

SELECT * FROM users
WHERE age > 18;

مثال دوم: دریافت کاربران زیر ۱۸ سال

SELECT * FROM users
WHERE age < 18;

مثال سوم: دریافت کاربران ۳۰ ساله و بزرگ‌تر

SELECT * FROM users
WHERE age >= 30;

مثال چهارم: دریافت کاربران غیر فعال

SELECT * FROM users
WHERE status != 'active';

عملگرهای != و <> هر دو برای بررسی نامساوی بودن استفاده می‌شوند.

۵. ترکیب چند شرط با عملگر AND

گاهی لازم است چند شرط به‌صورت هم‌زمان برقرار باشند. برای این کار از عملگر AND استفاده می‌کنیم.

AND فقط رکوردهایی را انتخاب می‌کند که تمام شرط‌های مشخص‌شده برای آن‌ها درست باشند.

ساختار کلی:

SELECT * FROM table_name
WHERE condition1 AND condition2;

مثال: دریافت کاربران فعال بالای ۱۸ سال

SELECT * FROM users
WHERE age >= 18
AND status = 'active';

این کوئری فقط کاربرانی را برمی‌گرداند که سن آن‌ها حداقل ۱۸ سال باشد و وضعیت حساب آن‌ها نیز active باشد.

مثال: دریافت کاربران ساکن تهران با سن بیشتر از ۲۰ سال

SELECT * FROM users
WHERE city = 'Tehran'
AND age > 20;

هر دو شرط باید برقرار باشند تا رکورد در نتیجه نمایش داده شود.

۶. ترکیب شرط‌ها با عملگر OR

عملگر OR برای زمانی استفاده می‌شود که برقرار بودن حداقل یکی از چند شرط کافی باشد.

ساختار کلی:

SELECT * FROM table_name
WHERE condition1 OR condition2;

مثال: دریافت کاربران تهران یا شیراز

SELECT * FROM users
WHERE city = 'Tehran'
OR city = 'Shiraz';

در این مثال، کاربرانی که در تهران یا شیراز زندگی می‌کنند، در نتیجه قرار می‌گیرند.

مثال: دریافت کاربران زیر ۱۸ سال یا بالای ۳۰ سال

SELECT * FROM users
WHERE age < 18
OR age > 30;

کافی است یکی از دو شرط برقرار باشد تا رکورد انتخاب شود.

۷. ترکیب AND و OR در یک دستور WHERE

در کوئری‌های پیچیده ممکن است به ترکیب چند عملگر منطقی نیاز داشته باشیم. در این شرایط استفاده از پرانتز اهمیت زیادی دارد.

برای مثال، می‌خواهیم کاربران فعال تهران یا شیراز را دریافت کنیم:

SELECT * FROM users
WHERE status = 'active'
AND (city = 'Tehran' OR city = 'Shiraz');

در این کوئری ابتدا شرط شهر با OR بررسی می‌شود و سپس شرط فعال بودن کاربر نیز باید برقرار باشد.

بدون پرانتز، ترتیب ارزیابی عملگرهای AND و OR می‌تواند نتیجه متفاوتی ایجاد کند؛ زیرا AND در SQL اولویت بالاتری از OR دارد.

برای مثال:

SELECT * FROM users
WHERE status = 'active'
AND city = 'Tehran'
OR city = 'Shiraz';

این دستور از نظر منطقی معادل عبارت زیر است:

SELECT * FROM users
WHERE (status = 'active' AND city = 'Tehran')
OR city = 'Shiraz';

بنابراین ممکن است کاربران غیرفعال شیراز نیز در نتیجه نمایش داده شوند. برای جلوگیری از چنین اشتباهاتی، شرط‌های ترکیبی را با پرانتز مشخص کنید.

۸. استفاده از NOT برای معکوس کردن شرط

عملگر NOT نتیجه یک شرط را معکوس می‌کند. یعنی رکوردهایی را انتخاب می‌کند که شرط مشخص‌شده برای آن‌ها برقرار نباشد.

مثال: دریافت تمام کاربرانی که وضعیت آن‌ها active نیست:

SELECT * FROM users
WHERE NOT status = 'active';

شکل دیگر همین کوئری:

SELECT * FROM users
WHERE status != 'active';

همچنین می‌توان از NOT همراه با عملگرهایی مانند IN، LIKE و BETWEEN استفاده کرد.

۹. فیلتر اطلاعات با BETWEEN

عملگر BETWEEN برای انتخاب مقادیری استفاده می‌شود که در یک محدوده مشخص قرار دارند.

ساختار کلی:

SELECT * FROM table_name
WHERE column_name BETWEEN value1 AND value2;

این عملگر هر دو مقدار ابتدا و انتهای محدوده را نیز شامل می‌شود.

مثال: دریافت کاربران بین ۲۰ تا ۳۰ سال

SELECT * FROM users
WHERE age BETWEEN 20 AND 30;

در این مثال کاربران ۲۰، ۲۱، ۲۲ و تمام سن‌های بین این دو مقدار تا ۳۰ سال نیز انتخاب می‌شوند.

استفاده از NOT BETWEEN

برای دریافت اطلاعات خارج از یک محدوده مشخص می‌توان از NOT BETWEEN استفاده کرد.

SELECT * FROM users
WHERE age NOT BETWEEN 20 AND 30;

این کوئری کاربرانی را برمی‌گرداند که سن آن‌ها کمتر از ۲۰ یا بیشتر از ۳۰ سال است.

استفاده از BETWEEN برای تاریخ

BETWEEN فقط برای اعداد نیست و می‌توان از آن برای فیلتر کردن تاریخ‌ها نیز استفاده کرد.

SELECT * FROM orders
WHERE order_date BETWEEN '2026-01-01' AND '2026-01-31';

نکته مهم: اگر ستون order_date از نوع DATETIME باشد، مقدار انتهایی بالا به ابتدای روز ۳۱ ژانویه اشاره می‌کند و ممکن است سفارش‌های ثبت‌شده در ادامه آن روز را شامل نشود. برای پوشش کامل ماه، بهتر است از شرط بازه‌ای زیر استفاده کنید:

SELECT * FROM orders
WHERE order_date >= '2026-01-01'
AND order_date < '2026-02-01';

این روش برای ستون‌های DATE و DATETIME انتخاب دقیق‌تری است.

۱۰. فیلتر اطلاعات با IN و NOT IN

زمانی که می‌خواهیم یک ستون را با چند مقدار مشخص مقایسه کنیم، می‌توانیم به‌جای نوشتن چند شرط OR از عملگر IN استفاده کنیم.

مثال: دریافت کاربران تهران، شیراز و تبریز:

SELECT * FROM users
WHERE city IN ('Tehran', 'Shiraz', 'Tabriz');

این دستور معادل کوئری زیر است:

SELECT * FROM users
WHERE city = 'Tehran'
OR city = 'Shiraz'
OR city = 'Tabriz';

استفاده از IN در چنین شرایطی باعث کوتاه‌تر و خواناتر شدن کوئری می‌شود.

استفاده از NOT IN

برای دریافت رکوردهایی که مقدار ستون آن‌ها در فهرست مشخص‌شده وجود ندارد، از NOT IN استفاده می‌کنیم.

SELECT * FROM users
WHERE city NOT IN ('Tehran', 'Shiraz');

این کوئری کاربران شهرهایی غیر از تهران و شیراز را برمی‌گرداند.

نکته مهم: اگر فهرست داخل NOT IN شامل NULL باشد، نتیجه ممکن است مطابق انتظار نباشد. در کوئری‌های پیچیده بهتر است وضعیت NULL را بررسی کنید و در صورت نیاز از NOT EXISTS استفاده کنید.

۱۱. جستجوی متنی با LIKE

عملگر LIKE برای جستجوی متنی و پیدا کردن رکوردهایی استفاده می‌شود که بخشی از مقدار یک ستون با الگوی مشخص‌شده مطابقت دارد.

در LIKE دو کاراکتر پرکاربرد وجود دارد:

  • %: نشان‌دهنده صفر یا چند کاراکتر است.
  • _: نشان‌دهنده دقیقاً یک کاراکتر است.

مثال اول: نام‌هایی که با Ali شروع می‌شوند

SELECT * FROM users
WHERE name LIKE 'Ali%';

مثال دوم: نام‌هایی که به Ali ختم می‌شوند

SELECT * FROM users
WHERE name LIKE '%Ali';

مثال سوم: نام‌هایی که شامل Ali هستند

SELECT * FROM users
WHERE name LIKE '%Ali%';

مثال چهارم: استفاده از زیرخط

SELECT * FROM users
WHERE name LIKE '_li';

در مثال آخر، مقدارهایی مانند Ali با الگوی مشخص‌شده مطابقت دارند؛ زیرا قبل از li دقیقاً یک کاراکتر وجود دارد.

نکته: حساس بودن LIKE به حروف بزرگ و کوچک به Collation ستون و تنظیمات مقایسه رشته‌ها بستگی دارد.

۱۲. بررسی مقادیر NULL با IS NULL و IS NOT NULL

مقدار NULL در MySQL نشان‌دهنده نبودن یا نامشخص بودن یک مقدار است. برای بررسی این مقادیر نمی‌توان از عملگر مساوی استفاده کرد.

برای دریافت کاربرانی که شهر آن‌ها مشخص نشده است:

SELECT * FROM users
WHERE city IS NULL;

برای دریافت کاربرانی که شهر آن‌ها ثبت شده است:

SELECT * FROM users
WHERE city IS NOT NULL;

استفاده از شرط city = NULL صحیح نیست. برای بررسی مقادیر NULL همیشه از IS NULL یا IS NOT NULL استفاده کنید.

توجه داشته باشید که NULL با رشته خالی یا عدد صفر تفاوت دارد. این سه مقدار نباید با یکدیگر اشتباه گرفته شوند.

۱۳. استفاده از WHERE همراه با ORDER BY

می‌توان دستور WHERE را همراه با ORDER BY استفاده کرد. در این حالت ابتدا رکوردهای موردنظر فیلتر می‌شوند و سپس نتیجه مرتب می‌شود.

مثال: دریافت کاربران فعال و مرتب‌سازی آن‌ها بر اساس سن از بیشترین به کمترین:

SELECT * FROM users
WHERE status = 'active'
ORDER BY age DESC;

در این کوئری ابتدا فقط کاربران فعال انتخاب می‌شوند و سپس بر اساس ستون age به‌صورت نزولی مرتب می‌شوند.

۱۴. استفاده از WHERE همراه با LIMIT

اگر بخواهیم فقط تعداد مشخصی از رکوردهای مطابق با شرط را دریافت کنیم، می‌توانیم WHERE و LIMIT را ترکیب کنیم.

مثال: دریافت پنج کاربر فعال:

SELECT * FROM users
WHERE status = 'active'
LIMIT 5;

برای دریافت نتیجه قابل پیش‌بینی بهتر است مرتب‌سازی نیز مشخص شود:

SELECT * FROM users
WHERE status = 'active'
ORDER BY id DESC
LIMIT 5;

۱۵. استفاده از WHERE در PHP با PDO

تا اینجا مثال‌ها را مستقیماً در MySQL اجرا کردیم. اکنون می‌خواهیم یاد بگیریم چگونه با استفاده از PHP و PDO اطلاعات را بر اساس شرط‌های مختلف دریافت کنیم.

ابتدا باید به پایگاه داده متصل شویم. برای این کار یک فایل با نام database.php ایجاد می‌کنیم:

<?php

$host = "localhost";
$dbname = "my_database";
$username = "root";
$password = "";

try {
    $pdo = new PDO(
        "mysql:host=$host;dbname=$dbname;charset=utf8mb4",
        $username,
        $password
    );

    $pdo->setAttribute(
        PDO::ATTR_ERRMODE,
        PDO::ERRMODE_EXCEPTION
    );

} catch (PDOException $e) {
    error_log($e->getMessage());
    exit("خطا در اتصال به پایگاه داده.");
}

?>

در این مثال، اتصال به MySQL با استفاده از PDO ایجاد شده و حالت گزارش خطا روی Exception تنظیم شده است.

دریافت کاربران با یک شرط

فرض کنید می‌خواهیم فقط کاربرانی را دریافت کنیم که وضعیت آن‌ها active است.

<?php

require_once "database.php";

$sql = "SELECT * FROM users
        WHERE status = 'active'";

$stmt = $pdo->query($sql);

$users = $stmt->fetchAll(PDO::FETCH_ASSOC);

foreach ($users as $user) {
    echo htmlspecialchars($user["name"]) . "<br>";
}

?>

از آنجا که در این کوئری مقدار شرط ثابت است و از ورودی کاربر دریافت نمی‌شود، استفاده از query() امکان‌پذیر است.

دریافت اطلاعات با شرط متغیر

اگر مقدار شرط از کاربر دریافت شود، باید از Prepared Statement استفاده کنیم.

<?php

require_once "database.php";

$city = "Tehran";

$sql = "SELECT * FROM users
        WHERE city = :city";

$stmt = $pdo->prepare($sql);

$stmt->execute([
    "city" => $city
]);

$users = $stmt->fetchAll(PDO::FETCH_ASSOC);

foreach ($users as $user) {
    echo htmlspecialchars($user["name"]) . "<br>";
}

?>

در این مثال، پارامتر :city به مقدار متغیر city متصل شده است. استفاده از پارامترگذاری باعث می‌شود مقدار ورودی به‌عنوان داده در نظر گرفته شود، نه بخشی از دستور SQL.

۱۶. استفاده از چند شرط WHERE در PHP با PDO

در پروژه‌های واقعی ممکن است بخواهیم چند شرط را به‌صورت هم‌زمان بررسی کنیم. برای مثال، فقط کاربران فعال بالای ۱۸ سال را دریافت کنیم.

<?php

require_once "database.php";

$age = 18;
$status = "active";

$sql = "SELECT id, name, email, age
        FROM users
        WHERE age >= :age
        AND status = :status";

$stmt = $pdo->prepare($sql);

$stmt->execute([
    "age" => $age,
    "status" => $status
]);

$users = $stmt->fetchAll(PDO::FETCH_ASSOC);

foreach ($users as $user) {
    echo "نام: " . htmlspecialchars($user["name"]) . "<br>";
    echo "ایمیل: " . htmlspecialchars($user["email"]) . "<br>";
    echo "سن: " . htmlspecialchars((string) $user["age"]) . "<br>";
    echo "<hr>";
}

?>

در این مثال، هر دو شرط باید برقرار باشند. اگر کاربری سن مناسب داشته باشد اما وضعیت او inactive باشد، در نتیجه نمایش داده نمی‌شود.

۱۷. دریافت اطلاعات با WHERE و LIKE در PHP

یکی از کاربردهای رایج WHERE، ساخت سیستم جستجو است. برای مثال، می‌توانیم فرمی ایجاد کنیم که کاربر نام موردنظر خود را وارد کند و PHP اطلاعات مرتبط را از MySQL دریافت کند.

<?php

require_once "database.php";

$search = trim($_GET["search"] ?? "");

$users = [];

if ($search !== "") {

    $sql = "SELECT id, name, email
            FROM users
            WHERE name LIKE :search
            ORDER BY id DESC";

    $stmt = $pdo->prepare($sql);

    $stmt->execute([
        "search" => "%" . $search . "%"
    ]);

    $users = $stmt->fetchAll(PDO::FETCH_ASSOC);
}

?>

<!DOCTYPE html>
<html lang="fa" dir="rtl">
<head>
    <meta charset=UTF-8>
    <title>جستجوی کاربران</title>
</head>
<body>

    <h1>جستجوی کاربران</h1>

    <form method="GET">

        <input
            type=text
            name=search
            placeholder="نام کاربر را وارد کنید"
            value="<?= htmlspecialchars($search) ?>"
        >

        <button type=submit>جستجو</button>

    </form>

    <hr>

    <?php if ($search !== ""): ?>

        <?php if (count($users) > 0): ?>

            <h2>نتایج جستجو

در این پروژه، کاربر عبارت موردنظر را وارد می‌کند. سپس PHP با استفاده از LIKE و Prepared Statement، رکوردهایی را پیدا می‌کند که نام آن‌ها شامل عبارت جستجو باشد.

استفاده از htmlspecialchars() هنگام نمایش مقدار جستجو و اطلاعات کاربران به جلوگیری از اجرای ناخواسته کدهای HTML و JavaScript کمک می‌کند.

۱۸. استفاده از WHERE در PHP با MySQLi

علاوه بر PDO، می‌توان از افزونه MySQLi برای اجرای کوئری‌های دارای شرط نیز استفاده کرد.

ابتدا اتصال به پایگاه داده را ایجاد می‌کنیم:

<?php

$mysqli = new mysqli(
    "localhost",
    "root",
    "",
    "my_database"
);

if ($mysqli->connect_error) {
    error_log($mysqli->connect_error);
    exit("خطا در اتصال به پایگاه داده.");
}

$mysqli->set_charset("utf8mb4");

?>

دریافت کاربر با شناسه مشخص

<?php

$id = 1;

$stmt = $mysqli->prepare(
    "SELECT * FROM users WHERE id = ?"
);

$stmt->bind_param("i", $id);

$stmt->execute();

$result = $stmt->get_result();

$user = $result->fetch_assoc();

if ($user) {
    echo htmlspecialchars($user["name"]);
} else {
    echo "کاربر پیدا نشد.";
}

$stmt->close();

?>

در این مثال، علامت سؤال محل قرارگیری پارامتر را مشخص می‌کند. متد bind_param() مقدار متغیر id را به کوئری متصل می‌کند.

استفاده از چند شرط در MySQLi

<?php

$age = 18;
$status = "active";

$stmt = $mysqli->prepare(
    "SELECT * FROM users
     WHERE age >= ? AND status = ?"
);

$stmt->bind_param("is", $age, $status);

$stmt->execute();

$result = $stmt->get_result();

while ($user = $result->fetch_assoc()) {
    echo htmlspecialchars($user["name"]) . "<br>";
}

$stmt->close();

?>

در رشته is، حرف i به معنی عدد صحیح و حرف s به معنی رشته است.

نکته: متد get_result() به درایور mysqlnd نیاز دارد. اگر این درایور در محیط شما فعال نیست، می‌توانید از bind_result() و fetch() استفاده کنید.

۱۹. استفاده از WHERE در دستور UPDATE

دستور WHERE فقط برای SELECT کاربرد ندارد. یکی از مهم‌ترین کاربردهای آن در دستور UPDATE است.

با استفاده از UPDATE می‌توانیم اطلاعات رکوردهای مشخصی را تغییر دهیم. WHERE تعیین می‌کند کدام رکوردها باید ویرایش شوند.

مثال: تغییر وضعیت کاربر با شناسه ۱ به inactive:

UPDATE users
SET status = 'inactive'
WHERE id = 1;

اگر WHERE را در این دستور حذف کنیم، وضعیت تمام کاربران تغییر خواهد کرد. بنابراین قبل از اجرای UPDATE همیشه شرط موردنظر را بررسی کنید.

نمونه امن با PDO

<?php

require_once "database.php";

$id = 1;
$status = "inactive";

$sql = "UPDATE users
        SET status = :status
        WHERE id = :id";

$stmt = $pdo->prepare($sql);

$stmt->execute([
    "status" => $status,
    "id" => $id
]);

echo "عملیات انجام شد.";

?>

۲۰. استفاده از WHERE در دستور DELETE

دستور DELETE برای حذف رکوردها از جدول استفاده می‌شود. با استفاده از WHERE می‌توانیم مشخص کنیم فقط کدام رکوردها حذف شوند.

مثال: حذف کاربری با شناسه ۵:

DELETE FROM users
WHERE id = 5;

این دستور فقط رکوردی را حذف می‌کند که شناسه آن برابر با ۵ باشد.

نمونه امن با PDO

<?php

require_once "database.php";

$id = 5;

$sql = "DELETE FROM users
        WHERE id = :id";

$stmt = $pdo->prepare($sql);

$stmt->execute([
    "id" => $id
]);

echo "عملیات حذف انجام شد.";

?>

هشدار: اجرای DELETE بدون WHERE باعث حذف تمام رکوردهای جدول می‌شود. در عملیات حذف اطلاعات مهم، بهتر است قبل از اجرا از داده‌ها نسخه پشتیبان تهیه کنید و شرط حذف را به‌دقت بررسی کنید.

۲۱. استفاده از WHERE همراه با JOIN

در بسیاری از پروژه‌ها اطلاعات در چند جدول مرتبط ذخیره می‌شوند. با استفاده از JOIN می‌توانیم اطلاعات چند جدول را ترکیب کنیم و سپس با WHERE نتایج موردنیاز را فیلتر کنیم.

فرض کنید دو جدول users و orders داریم. جدول orders شامل ستون‌های id، user_id، total_price و status است.

برای دریافت سفارش‌های پرداخت‌شده کاربران:

SELECT
    users.name,
    orders.total_price,
    orders.status
FROM users
INNER JOIN orders
ON users.id = orders.user_id
WHERE orders.status = 'paid';

این کوئری ابتدا ارتباط بین کاربران و سفارش‌ها را با INNER JOIN برقرار می‌کند و سپس فقط سفارش‌هایی را نمایش می‌دهد که وضعیت آن‌ها paid است.

ترکیب JOIN با چند شرط

SELECT
    users.name,
    orders.total_price
FROM users
INNER JOIN orders
ON users.id = orders.user_id
WHERE orders.status = 'paid'
AND orders.total_price > 500000;

در این مثال فقط سفارش‌های پرداخت‌شده‌ای نمایش داده می‌شوند که مبلغ آن‌ها بیشتر از ۵۰۰ هزار تومان باشد.

۲۲. تفاوت WHERE و HAVING در MySQL

دو عبارت WHERE و HAVING برای فیلتر کردن اطلاعات استفاده می‌شوند، اما عملکرد آن‌ها یکسان نیست.

  • WHERE: رکوردها را قبل از گروه‌بندی فیلتر می‌کند.
  • HAVING: گروه‌های ایجادشده با GROUP BY را فیلتر می‌کند.

مثال استفاده از WHERE:

SELECT * FROM users
WHERE age > 18;

در این کوئری کاربران بالای ۱۸ سال انتخاب می‌شوند.

مثال استفاده از HAVING:

SELECT city, COUNT(*) AS total
FROM users
GROUP BY city
HAVING COUNT(*) > 2;

در این کوئری ابتدا کاربران بر اساس شهر گروه‌بندی می‌شوند و سپس فقط شهرهایی نمایش داده می‌شوند که بیش از دو کاربر دارند.

ترکیب WHERE و HAVING

SELECT city, COUNT(*) AS total
FROM users
WHERE status = 'active'
GROUP BY city
HAVING COUNT(*) > 1;

ابتدا کاربران فعال انتخاب می‌شوند، سپس بر اساس شهر گروه‌بندی شده و در نهایت گروه‌هایی که بیش از یک کاربر دارند نمایش داده می‌شوند.

۲۳. ساخت سیستم فیلتر محصولات با PHP و MySQL

یکی از کاربردهای مهم WHERE در فروشگاه‌های اینترنتی، فیلتر کردن محصولات بر اساس قیمت و دسته‌بندی است.

فرض کنید جدول products دارای ستون‌های id، name، price و category است. می‌خواهیم کاربر بتواند حداقل قیمت، حداکثر قیمت و دسته‌بندی موردنظر را وارد کند.

<?php

require_once "database.php";

$minPrice = $_GET["min_price"] ?? "";
$maxPrice = $_GET["max_price"] ?? "";
$category = trim($_GET["category"] ?? "");

$conditions = [];
$params = [];

if ($minPrice !== "" && filter_var($minPrice, FILTER_VALIDATE_FLOAT) !== false) {
    $conditions[] = "price >= :min_price";
    $params["min_price"] = (float) $minPrice;
}

if ($maxPrice !== "" && filter_var($maxPrice, FILTER_VALIDATE_FLOAT) !== false) {
    $conditions[] = "price <= :max_price";
    $params["max_price"] = (float) $maxPrice;
}

if ($category !== "") {
    $conditions[] = "category = :category";
    $params["category"] = $category;
}

$sql = "SELECT id, name, price, category FROM products";

if (!empty($conditions)) {
    $sql .= " WHERE " . implode(" AND ", $conditions);
}

$sql .= " ORDER BY id DESC LIMIT 100";

$stmt = $pdo->prepare($sql);
$stmt->execute($params);

$products = $stmt->fetchAll(PDO::FETCH_ASSOC);

?>

<!DOCTYPE html>
<html lang="fa" dir="rtl">
<head>
    <meta charset=UTF-8>
    <title>فیلتر محصولات</title>
</head>
<body>

    <h1>فیلتر محصولات</h1>

    <form method="GET">

        <label>حداقل قیمت:</label>
        <input
            type=number
            name=min_price
            min="0"
            value="<?= htmlspecialchars((string) $minPrice) ?>"
        >

        <label>حداکثر قیمت:</label>
        <input
            type=number
            name=max_price
            min="0"
            value="<?= htmlspecialchars((string) $maxPrice) ?>"
        >

        <label>دسته‌بندی:</label>
        <input
            type=text
            name=category
            value="<?= htmlspecialchars($category) ?>"
        >

        <button type=submit>اعمال فیلتر</button>

    </form>

    <hr>

    <h2>نتایج محصولات</h2>

    <?php if (count($products) > 0): ?>

        <table border=1 cellpadding="10">

            <thead>
                <tr>
                    <th>شناسه</th>
                    <th>نام محصول</th>
                    <th>قیمت</th>
                    <th>دسته‌بندی</th>
                </tr>
            </thead>

            <tbody>

                <?php foreach ($products as $product): ?>

                    <tr>
                        <td>
                            <?= htmlspecialchars((string) $product["id"]) ?>
                        </td>

                        <td>
                            <?= htmlspecialchars($product["name"]) ?>
                        </td>

                        <td>
                            <?= htmlspecialchars((string) $product["price"]) ?>
                        </td>

                        <td>
                            <?= htmlspecialchars($product["category"]) ?>
                        </td>
                    </tr>

                <?php endforeach; ?>

            </tbody>

        </table>

    <?php else: ?>

        <p>محصولی با شرایط انتخاب‌شده پیدا نشد.</p>

    <?php endif; ?>

</body>
</html>

در این پروژه، شرط‌ها به‌صورت پویا ساخته می‌شوند. اگر کاربر فقط حداقل قیمت را وارد کند، تنها همان شرط به کوئری اضافه می‌شود. اگر دسته‌بندی و حداکثر قیمت نیز وارد شوند، شرط‌های مربوط به آن‌ها با AND ترکیب خواهند شد.

نکته مهم امنیتی: در این مثال، بخش‌های ثابت SQL در کد نوشته شده‌اند و مقدارهای متغیر از طریق پارامترهای Prepared Statement ارسال می‌شوند. هرگز مقدار ورودی کاربر را مستقیماً به متن SQL اضافه نکنید.

۲۴. اعتبارسنجی ورودی‌ها هنگام استفاده از WHERE

استفاده از Prepared Statement برای جلوگیری از SQL Injection ضروری است، اما به‌تنهایی جایگزین اعتبارسنجی ورودی‌ها نیست.

برای مثال، اگر انتظار داریم شناسه کاربر یک عدد صحیح مثبت باشد، باید نوع و محدوده آن را بررسی کنیم.

<?php

$id = filter_input(
    INPUT_GET,
    "id",
    FILTER_VALIDATE_INT
);

if ($id === false || $id === null || $id < 1) {
    exit("شناسه واردشده معتبر نیست.");
}

$sql = "SELECT * FROM users WHERE id = :id";

$stmt = $pdo->prepare($sql);

$stmt->execute([
    "id" => $id
]);

$user = $stmt->fetch(PDO::FETCH_ASSOC);

if ($user) {
    echo htmlspecialchars($user["name"]);
} else {
    echo "کاربری با این شناسه پیدا نشد.";
}

?>

در این مثال از FILTER_VALIDATE_INT برای بررسی عدد صحیح استفاده شده است. همچنین شناسه‌های کوچک‌تر از یک نیز پذیرفته نمی‌شوند.

اگر ورودی از نوع قیمت، تاریخ، ایمیل یا متن باشد، باید متناسب با کاربرد آن اعتبارسنجی مناسب انجام شود.

۲۵. آیا می‌توان نام ستون را با Prepared Statement جایگزین کرد؟

یکی از اشتباهات رایج هنگام استفاده از PDO این است که تصور می‌شود می‌توان نام ستون یا جدول را مانند مقدارهای عادی پارامترگذاری کرد.

نمونه نادرست:

<?php

$column = "name";

$sql = "SELECT * FROM users
        ORDER BY :column";

$stmt = $pdo->prepare($sql);

$stmt->execute([
    "column" => $column
]);

?>

پارامترهای Prepared Statement برای مقدارهای داده‌ای هستند و جایگزین نام ستون‌ها، نام جدول‌ها یا بخش‌های دستوری SQL نمی‌شوند.

اگر لازم است کاربر ترتیب نمایش را انتخاب کند، باید مقدار ورودی را با فهرستی از گزینه‌های مجاز مقایسه کنیم.

<?php

$allowedColumns = [
    "name",
    "age",
    "created_at"
];

$sort = $_GET["sort"] ?? "name";

if (!in_array($sort, $allowedColumns, true)) {
    $sort = "name";
}

$sql = "SELECT * FROM users ORDER BY `$sort` ASC";

$stmt = $pdo->query($sql);

$users = $stmt->fetchAll(PDO::FETCH_ASSOC);

?>

در این مثال فقط نام ستون‌هایی که در فهرست مجاز قرار دارند وارد دستور SQL می‌شوند. این روش برای کنترل نام ستون و بخش‌های غیرقابل پارامترگذاری مناسب است.

۲۶. نکات مهم برای افزایش امنیت و سرعت کوئری‌های WHERE

  • استفاده از Prepared Statement: مقدارهای دریافتی از کاربر را مستقیماً وارد SQL نکنید و از پارامترگذاری امن استفاده کنید.
  • اعتبارسنجی ورودی‌ها: نوع، طول و محدوده مقدارهای ورودی را متناسب با نیاز برنامه بررسی کنید.
  • انتخاب ستون‌های موردنیاز: به‌جای SELECT * فقط ستون‌هایی را دریافت کنید که واقعاً به آن‌ها نیاز دارید.
  • استفاده از ایندکس مناسب: برای ستون‌هایی که زیاد در شرط‌های WHERE استفاده می‌شوند، وجود ایندکس مناسب را بررسی کنید.
  • بررسی عملکرد کوئری: با استفاده از EXPLAIN می‌توانید نحوه اجرای کوئری و استفاده از ایندکس‌ها را بررسی کنید.
  • پرهیز از توابع غیرضروری روی ستون‌های ایندکس‌شده: اعمال تابع روی ستون در شرط WHERE ممکن است استفاده مؤثر از ایندکس معمولی را دشوار کند. در صورت امکان شرط را به شکل قابل استفاده از ایندکس بنویسید.
  • استفاده از LIMIT: برای جلوگیری از دریافت تعداد بسیار زیاد رکورد، نتایج را متناسب با نیاز محدود کنید.
  • استفاده صحیح از NULL: برای بررسی مقدارهای NULL از IS NULL و IS NOT NULL استفاده کنید.
  • توجه به Collation: نتیجه مقایسه رشته‌ها و حساسیت به حروف بزرگ و کوچک می‌تواند به Collation ستون وابسته باشد.
  • مدیریت خروجی: داده‌های دریافت‌شده از پایگاه داده را هنگام نمایش در HTML با htmlspecialchars() مناسب بافت خروجی کنید.

۲۷. خطاهای رایج در استفاده از WHERE

خطای اول: فراموش کردن کوتیشن برای مقدارهای متنی

نمونه اشتباه:

SELECT * FROM users
WHERE city = Tehran;

نمونه صحیح:

SELECT * FROM users
WHERE city = 'Tehran';

مقدارهای متنی باید مطابق قواعد SQL داخل کوتیشن قرار بگیرند.

خطای دوم: استفاده از مساوی برای NULL

نمونه اشتباه:

SELECT * FROM users
WHERE city = NULL;

نمونه صحیح:

SELECT * FROM users
WHERE city IS NULL;

خطای سوم: استفاده نادرست از AND و OR

ترکیب نادرست این دو عملگر ممکن است رکوردهایی را نمایش دهد که موردنظر ما نیستند. برای کنترل ترتیب منطقی شرط‌ها از پرانتز استفاده کنید.

خطای چهارم: استفاده مستقیم از ورودی کاربر

ساخت کوئری با اتصال مستقیم رشته ورودی کاربر به SQL می‌تواند باعث SQL Injection شود. برای مقدارهای متغیر از Prepared Statement استفاده کنید.

خطای پنجم: فراموش کردن WHERE در UPDATE و DELETE

حذف یا ویرایش شرط WHERE ممکن است باعث تغییر یا حذف تمام رکوردهای جدول شود. پیش از اجرای چنین دستورهایی، کوئری را به‌دقت بررسی کنید.

خطای ششم: استفاده نادرست از BETWEEN برای تاریخ و زمان

در ستون‌های DATETIME باید به بخش ساعت نیز توجه کنید. برای دریافت تمام رکوردهای یک بازه زمانی، استفاده از شرط بزرگ‌تر یا مساوی برای ابتدا و کوچک‌تر برای انتها معمولاً روش مطمئن‌تری است.

۲۸. تمرین عملی برای یادگیری دستور WHERE

برای اینکه بتوانید به‌صورت عملی با دستور WHERE کار کنید، تمرین‌های زیر را روی جدول users اجرا کنید.

  1. تمام کاربرانی را دریافت کنید که در شهر تهران زندگی می‌کنند.
  2. کاربرانی را پیدا کنید که سن آن‌ها بیشتر از ۲۵ سال است.
  3. فقط کاربران فعال بالای ۱۸ سال را نمایش دهید.
  4. کاربران تهران یا شیراز را با استفاده از OR دریافت کنید.
  5. کاربرانی را پیدا کنید که سن آن‌ها بین ۲۰ تا ۳۰ سال است.
  6. کاربرانی را دریافت کنید که در شهرهای تهران، شیراز یا تبریز زندگی می‌کنند.
  7. کاربرانی را پیدا کنید که نام آن‌ها با حرف A شروع می‌شود.
  8. کاربرانی را نمایش دهید که شهر آن‌ها NULL است.
  9. اطلاعات کاربران فعال را بر اساس سن به‌صورت نزولی مرتب کنید.
  10. پنج کاربر فعال را با استفاده از LIMIT دریافت کنید.
  11. با استفاده از PDO یک فرم جستجوی کاربران ایجاد کنید.
  12. با استفاده از Prepared Statement اطلاعات کاربر را بر اساس شناسه دریافت کنید.
  13. وضعیت کاربر مشخصی را با UPDATE تغییر دهید.
  14. با استفاده از DELETE و WHERE فقط یک کاربر مشخص را حذف کنید.

۲۹. سوالات متداول درباره دستور WHERE در MySQL

۱. دستور WHERE در MySQL چه کاربردی دارد؟

دستور WHERE برای فیلتر کردن رکوردهای جدول بر اساس یک یا چند شرط استفاده می‌شود. این دستور کمک می‌کند فقط اطلاعات موردنیاز را دریافت یا تغییر دهیم.

۲. آیا WHERE فقط با SELECT استفاده می‌شود؟

خیر. WHERE علاوه بر SELECT در دستورهای UPDATE و DELETE نیز کاربرد دارد و مشخص می‌کند کدام رکوردها باید ویرایش یا حذف شوند.

۳. تفاوت AND و OR در WHERE چیست؟

AND زمانی رکورد را انتخاب می‌کند که تمام شرط‌ها برقرار باشند؛ اما OR زمانی رکورد را انتخاب می‌کند که حداقل یکی از شرط‌ها درست باشد.

۴. تفاوت WHERE و HAVING چیست؟

WHERE رکوردها را پیش از گروه‌بندی فیلتر می‌کند، اما HAVING برای فیلتر کردن نتیجه گروه‌بندی‌شده با GROUP BY استفاده می‌شود.

۵. عملگر BETWEEN چه کاری انجام می‌دهد؟

BETWEEN رکوردهایی را انتخاب می‌کند که مقدار مشخص‌شده در یک محدوده قرار داشته باشد. ابتدا و انتهای این محدوده نیز در نتیجه لحاظ می‌شوند.

۶. تفاوت IN و OR چیست؟

هر دو می‌توانند برای بررسی چند مقدار استفاده شوند، اما IN در شرایطی که یک ستون باید با چند مقدار مقایسه شود، کد کوتاه‌تر و خواناتری ایجاد می‌کند.

۷. چگونه در WHERE مقادیر NULL را بررسی کنیم؟

برای بررسی مقدارهای NULL باید از IS NULL و IS NOT NULL استفاده کنیم. مقایسه با = NULL روش صحیحی نیست.

۸. چگونه از SQL Injection در کوئری‌های WHERE جلوگیری کنیم؟

برای ارسال مقدارهای متغیر به کوئری از Prepared Statement در PDO یا MySQLi استفاده کنید و ورودی‌ها را نیز اعتبارسنجی کنید.

۹. آیا می‌توان چند شرط را در WHERE ترکیب کرد؟

بله. با استفاده از AND، OR، NOT و پرانتز می‌توان چندین شرط ساده و پیچیده را در یک کوئری ترکیب کرد.

۱۰. آیا WHERE باعث افزایش سرعت کوئری می‌شود؟

WHERE تعداد رکوردهای موردنیاز را محدود می‌کند، اما سرعت اجرای کوئری به عواملی مانند ایندکس‌ها، تعداد رکوردها، نوع شرط و ساختار جدول نیز بستگی دارد. استفاده از ایندکس مناسب می‌تواند عملکرد فیلتر کردن اطلاعات را بهبود دهد.

جمع‌بندی

در این قسمت از آموزش PHP و MySQL با دستور WHERE و روش‌های مختلف فیلتر کردن اطلاعات در پایگاه داده آشنا شدیم. یاد گرفتیم چگونه با استفاده از عملگرهای مقایسه‌ای، AND، OR، NOT، BETWEEN، IN، LIKE و IS NULL رکوردهای موردنظر خود را انتخاب کنیم.

همچنین نحوه استفاده از WHERE در PHP با PDO و MySQLi را بررسی کردیم و با ساخت سیستم جستجوی کاربران و فیلتر محصولات، کاربرد عملی این دستور را یاد گرفتیم.

یکی از مهم‌ترین نکات این آموزش، استفاده از Prepared Statement برای جلوگیری از SQL Injection بود. همچنین یاد گرفتیم که WHERE در دستورهای UPDATE و DELETE اهمیت زیادی دارد؛ زیرا حذف یا تغییر این شرط می‌تواند باعث ویرایش یا حذف ناخواسته تمام اطلاعات یک جدول شود.

تسلط بر دستور WHERE یکی از مهارت‌های ضروری برای برنامه‌نویسان PHP است. تقریباً در تمام پروژه‌های واقعی، از فروشگاه اینترنتی و سیستم مدیریت کاربران گرفته تا وبلاگ، پنل مدیریت و سامانه‌های جستجو، به این دستور نیاز خواهید داشت.

پیشنهاد ویژه ما:آموزش رایگان PHP

اشتراک گذاری :
ملیکا اسمعیلی
نویسنده

ملیکا اسمعیلی

من یک توسعه‌دهنده وردپرس و متخصص سئو هستم که به کسب‌وکارها کمک می‌کنم وب‌سایت‌های خود را به پلتفرم‌هایی بهینه برای موتورهای جستجو و با نرخ تبدیل بالا تبدیل کنند. با تجربه عملی در Python، HTML و CSS، مهارت‌های فنی توسعه وب را با درک عمیق از سئوی داخلی (On-Page SEO) و سئوی محتوا ترکیب می‌کنم؛

TEST_VALUE_123
https://t.me/artarasaneh
tel:09193426251
https://wa.me/+989193426251
https://instagram.com/artarasaneh_com