محدودسازی، گروه بندی و مرتب سازی نتایج در MySQL

در مبحث قبل از بخش آموزش مقدماتی MySQL در خصوص نحوه استفاده از دستور WHERE برای تعیین آدرس دقیق ردیف ها و بدست آوردن نتایج مورد نظر از دیتابیس توضیحاتی ارائه شد، در ادامه این مباحث و در این آموزش می خواهیم دیگر پارامترهای وابسته به دستور WHERE را بررسی کنیم که هدف های دیگری از جمله محدودسازی، گروه بندی و مرتب سازی نتایج پرس و جوها را محقق می کنند، منظور از این اصطلاحات تعیین تعداد ردیف های خروجی یا محدود کردن دامنه انتخاب نتایج، گروه بندی ردیف های با مقدار مشابه و مرتب سازی نتایج به فرض بر اساس حروف الفبا یا مقایسه مقادیر عددی (کوچکتر بزرگتر) است، در زبان SQL (که در MySQL از آن برای نگارش و پردازش پرس و جوها استفاده می کنیم) برای این هدف ها دستورات خاصی در نظر گرفته شده از جمله LIMIT برای محدودسازی، GROUP BY برای گروه بندی ستون های یکسان، HAVING برای تعیین شرط، DISTINCT برای حذف موارد تکراری و ORDER BY برای مرتب سازی (Sorting) نتایج که در ادامه در خصوص هر کدام از این پارامترها و چند پارامتر مرتبط دیگر شامل ASC، DESC، RAND، AND، OR، IN و BETWEEN به همراه نمونه کد توضیح خواهیم داد.
ساخت دیتابیس، جدول و ورود نمونه اطلاعات
قبل از پرداختن به مباحث اصلی آموزش ابتدا با استفاده از برنامه phpMyAdmin یک دیتابیس با نام دلخواه (ترجیحا Collation به صورت utf8_persian_ci) و دو جدول فرضی با نام های tbl_1_name و tbl_2_name با نمونه ردیف های زیر در آن ایجاد می کنیم، برای جدول tbl_1_name:
id => int(11) AUTO_INCREMENT
name => varchar(255)
age => int(11)
point => int(11)
هم به صورت دستی و هم با اجرای دستورات زیر در قسمت SQL برنامه phpMyAdmin می توانیم جدول بالا را ایجاد کنیم:CREATE TABLE IF NOT EXISTS `tbl_1_name` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8_persian_ci DEFAULT NULL,
`age` int(11) UNSIGNED DEFAULT NULL,
`point` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_persian_ci;
و برای جدول tbl_2_name:id => int(11) AUTO_INCREMENT
name => varchar(255)
برای ساخت این جدول هم علاوه بر شیوه دستی می توانیم در قسمت SQL برنامه phpMyAdmin دستورات زیر را اجرا کنیم:CREATE TABLE IF NOT EXISTS `tbl_2_name` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8_persian_ci DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_persian_ci;
نکته مهم: با توجه به اینکه ممکن است در آینده حروف زبان فارسی را در دیتابیس ذخیره یا از آن دریافت کنیم توصیه می شود Collation دیتابیس و جداول را در برنامه phpMyAdmin به صورت utf8_persian_ci تنظیم کنیم.برای اینکه نمونه اطلاعاتی جهت تست و بررسی در اختیار داشته باشیم دستورات زیر را در قسمت SQL برنامه phpMyAdmin برای جدول tbl_1_name و tbl_2_name اجرا می کنیم، برای جدول tbl_1_name:
INSERT INTO `tbl_1_name` (`id`, `name`, `age`, `point`) VALUES
(1, 'A', 20, 12),
(2, 'B', 13, 15),
(3, 'C', 15, 33),
(4, 'D', 23, 12),
(5, 'E', 12, 13),
(6, 'F', 16, 35);
و برای جدول tbl_2_name:INSERT INTO `tbl_2_name` (`id`, `name`) VALUES
(1, 'A'),
(2, 'C');
یا اینکه می توانیم کدهای زیر را در یک فایل PHP درج و با انجام تنظیمات اتصال به دیتابیس در قسمت متغیر conn، فایل PHP را در مرورگر فراخوانی و اجرا کنیم.برنامه نویسی رویه ای (Procedural):
<?php
$array = array(
'name' => array('A', 'B', 'C', 'D', 'E', 'F'),
'age' => array(20, 13, 15, 23, 12, 16),
'point' => array(12, 15, 33, 12, 13, 35)
);
$count = count($array['name']);
//اتصال به دیتابیس
$conn = mysqli_connect("localhost", "username", "password", "dbname");
if(!$conn){
echo "PHP & MySQL Connection: Error! " . mysqli_connect_errno() . ' - ' . mysqli_connect_error();
exit;
} else {
//ذخیره نمونه اطلاعات در جدول
for($i = 0; $i < $count; $i++){
$sql = "INSERT INTO tbl_1_name(name, age, point) VALUES('" . $array['name'][$i] . "', '" . $array['age'][$i] . "', '" . $array['point'][$i] . "')";
$query = mysqli_query($conn, $sql);
if(!$query) {
echo "Inserting Into Table tbl_1_name: Error! " . mysqli_error($conn);
break;
} else {
echo "tbl_1_name: Row " . ($i + 1) . " Inserted!<br>";
}
}
$sql = "INSERT INTO tbl_2_name(name) VALUES('" . $array['name'][0] . "')";
$query = mysqli_query($conn, $sql);
if(!$query) {
echo "Inserting Into Table tbl_2_name: Error! " . mysqli_error($conn) . '<br>';
} else {
echo "tbl_2_name: Row 1 Inserted!<br>";
}
$sql = "INSERT INTO tbl_2_name(name) VALUES('" . $array['name'][2] . "')";
$query = mysqli_query($conn, $sql);
if(!$query) {
echo "Inserting Into Table tbl_2_name: Error! " . mysqli_error($conn) . '<br>';
} else {
echo "tbl_2_name: Row 2 Inserted!<br>";
}
}
//پایان اتصال
mysqli_close($conn);
?>
برنامه نویسی شی گرا (Object-oriented):<?php
$array = array(
'name' => array('A', 'B', 'C', 'D', 'E', 'F'),
'age' => array(20, 13, 15, 23, 12, 16),
'point' => array(12, 15, 33, 12, 13, 35)
);
$count = count($array['name']);
//اتصال به دیتابیس
$conn = new mysqli("localhost", "username", "password", "dbname");
if(!$conn){
echo "PHP & MySQL Connection: Error! " . $conn->errno . ' - ' . $conn->error;
exit;
} else {
//ذخیره نمونه اطلاعات در جدول
for($i = 0; $i < $count; $i++){
$sql = "INSERT INTO tbl_1_name(name, age, point) VALUES('" . $array['name'][$i] . "', '" . $array['age'][$i] . "', '" . $array['point'][$i] . "')";
$query = $conn->query($sql);
if(!$query) {
echo "Inserting Into Table tbl_1_name: Error! " . $conn->error;
break;
} else {
echo "tbl_1_name: Row " . ($i + 1) . " Inserted!<br>";
}
}
$sql = "INSERT INTO tbl_2_name(name) VALUES('" . $array['name'][0] . "')";
$query = $conn->query($sql);
if(!$query) {
echo "Inserting Into Table tbl_2_name: Error! " . $conn->error . '<br>';
} else {
echo "tbl_2_name: Row 1 Inserted!<br>";
}
$sql = "INSERT INTO tbl_2_name(name) VALUES('" . $array['name'][2] . "')";
$query = $conn->query($sql);
if(!$query) {
echo "Inserting Into Table tbl_2_name: Error! " . $conn->error . '<br>';
} else {
echo "tbl_2_name: Row 2 Inserted!<br>";
}
}
//پایان اتصال
$conn->close();
?>
در نهایت اطلاعات جدول tbl_1_name باید به صورت زیر باشد:id name age point
1 A 20 12
2 B 13 15
3 C 15 33
4 D 23 12
5 E 12 13
6 F 16 35
و اطلاعات جدول tbl_2_name نیز به صورت زیر باشد:id name
1 A
2 C
از ساختار و اطلاعات این نمونه جداول برای تست و بررسی پارامترهایی که در ادامه خواهیم گفت استفاده می کنیم.استفاده از LIMIT
اجرای پرس و جوهای هرچند ساده با استفاده از دستور WHERE به تنهایی و بدون محدود کردن تعداد نتایج با پارامترهای اضافه می تواند منجر به دریافت حجم زیادی از اطلاعات ناخواسته شود که قطعا حالت بهینه نیست و احتمالا باعث کندی برنامه و فشار بی دلیل بر پایگاه داده خواهد شد، از این رو در زبان SQL برای WHERE پارامترهای محدود کننده ای مانند LIMIT در نظر گرفته اند، دستور LIMIT تعداد ردیف های نتایج به دست آمده از اجرای پرس و جوهای دیتابیس را به موارد مشخصی محدود می کند، به فرض در پرس و جوی فرضی زیر صرفا 3 ردیف از اطلاعات به عنوان خروجی درخواست برگردانده می شود:
SELECT * FROM tbl_1_name WHERE name != '' LIMIT 3
id name age point
1 A 20 12
2 B 13 15
3 C 15 33
علاوه بر تعیین تعداد ردیف ها می توانیم نقطه شروع انتخاب ردیف ها را هم برای MySQL مشخص کنیم که در این صورت برای LIMIT از دو پارامتر عددی استفاده می کنیم، عدد اول شماره ردیف برای تعیین نقطه آغاز دریافت نتایج و عدد دوم تعداد نتایجی است که پرس و جو را به آن محدود کرده ایم، به طور مثال در نمونه کد زیر از ردیف 2 به بعد 3 ردیف به عنوان نتیجه برگردانده می شود (شامل خود ردیف دوم نمی شود):SELECT * FROM tbl_1_name WHERE name != '' LIMIT 2, 3
id name age point
3 C 15 33
4 D 23 12
5 E 12 13
با استفاده از این شیوه می توانیم به صورت داینامیک قابلیت هایی مانند صفحه بندی محتوا را در برنامه های وب ایجاد کنیم که در آموزش های کاربردی MySQL در این خصوص خواهیم گفت، برای تست و بررسی دستور LIMIT کافی است پرس و جوهای بالا را در قسمت SQL برنامه phpMyAdmin اجرا یا کد زیر را در یک فایل PHP درج و پس از اعمال تنظیمات اتصال در متغیر conn از طریق مرورگر فراخوانی کنیم.برنامه نویسی رویه ای (Procedural):
<?php
//اتصال به دیتابیس
$conn = mysqli_connect("localhost", "username", "password", "dbname");
if(!$conn){
echo "PHP & MySQL Connection: Error! " . mysqli_connect_errno() . ' - ' . mysqli_connect_error();
exit;
} else{
//سازگاری با حروف فارسی
$sql = "SET NAMES 'utf8'";
$query = mysqli_query($conn, $sql);
//اانتخاب اطلاعات از جدول و ستون ها
$sql = "SELECT name, age, point FROM tbl_1_name WHERE name != '' LIMIT 2, 3";
$query = mysqli_query($conn, $sql);
if(!$query){
echo "Selecting From Table tbl_1_name: Error! " . mysqli_error($conn) . '<br>';
} else{
//تعداد ردیف های انتخاب شده
$count = mysqli_num_rows($query);
$loop = 1;
//پردازش و خروجی ردیف های اطلاعات
if($count > 0){
echo '<div style="direction: ltr; border: 1px solid #999;">';
echo 'Row Count: ' . $count . '<br><br>';
while($row = mysqli_fetch_array($query)){
echo 'Row ' . $loop . ' => ' .
'Name: ' . $row['name'] . ' - ' .
'Age: ' . $row['age'] . ' - ' .
'Point: ' . $row['point'] . '<br><br>';
$loop++;
}
echo '</div>';
} else{
echo "No Rows Found in Table tbl_1_name!";
}
}
}
//پایان اتصال
mysqli_close($conn);
?>
برنامه نویسی شی گرا (Object-oriented):<?php
//اتصال به دیتابیس
$conn = new mysqli("localhost", "username", "password", "dbname");
if(!$conn){
echo "PHP & MySQL Connection: Error! " . $conn->errno . ' - ' . $conn->error;
exit;
} else {
//سازگاری با حروف فارسی
$sql = "SET NAMES 'utf8'";
$conn->query($sql);
//اانتخاب اطلاعات از جدول و ستون ها
$sql = "SELECT name, age, point FROM tbl_1_name WHERE name != '' LIMIT 2, 3";
$query = $conn->query($sql);
//دریافت اطلاعات از جدول
if(!$query) {
echo "Selecting From Table tbl_1_name: Error! " . $conn->error . '<br>';
} else {
//تعداد ردیف های انتخاب شده
$count = $query->num_rows;
$loop = 1;
//پردازش و خروجی ردیف های اطلاعات
if($count > 0){
echo '<div style="direction: ltr; border: 1px solid #999;">';
echo 'Row Count: ' . $count . '<br><br>';
while($row = $query->fetch_array()){
echo 'Row ' . $loop . ' => ' .
'Name: ' . $row['name'] . ' - ' .
'Age: ' . $row['age'] . ' - ' .
'Point: ' . $row['point'] . '<br><br>';
$loop++;
}
echo '</div>';
} else{
echo "No Rows Found in Table tbl_1_name!";
}
}
}
//پایان اتصال
$conn->close();
?>
خروجی نمونه کدهای بالا به صورت زیر خواهد بود:Row Count: 3
Row 1 => Name: C - Age: 15 - Point: 33
Row 2 => Name: D - Age: 23 - Point: 12
Row 3 => Name: E - Age: 12 - Point: 13
همان طور که مشخص است از ردیف دوم به بعد 3 ردیف انتخاب شده اند.استفاده از GROUP BY
یک قابلیت کاربردی دیگر که در زمینه دسته بندی و نمایش بهتر نتایج حاصل از اجرای پرس و جوهای پایگاه داده MySQL می توانیم از آن استفاده کنیم قابلیت گروه بندی نتایج دارای مقادیر مشترک با GROUP BY و خلاصه کردن نتیجه در یک ردیف است، به فرض در نمونه اطلاعاتی که در دیتابیس بالا درج کرده ایم در جدول tbl_1_name دو ردیف 1 و 4 دارای point یکسان هستند و بر این اساس می توانیم نمونه پرس و جوی متغیر sql را به صورت زیر بنویسیم:
SELECT name, age, point FROM tbl_1_name WHERE name != '' GROUP BY point
با اجرای کدها خروجی به صورت نمونه زیر خواهد بود:Row Count: 5
Row 1 => Name: A - Age: 20 - Point: 12
Row 2 => Name: E - Age: 12 - Point: 13
Row 3 => Name: B - Age: 13 - Point: 15
Row 4 => Name: C - Age: 15 - Point: 33
Row 5 => Name: F - Age: 16 - Point: 35
با در نظر گرفتن دستور GROUP BY برای ستون دارای مقدار مشترک (در اینجا point) تمام ردیف ها در یک ردیف خلاصه می شوند، اگر در نتایج به دست آمده دقت کنیم GROUP BY صرفا در خلاصه کردن نتیجه بدست آمده تاثیرگذار نیست و نحوه چینش را هم بر اساس ستون در نظر گرفته شده تغییر می دهد.استفاده از HAVING
به همراه گروه بندی با دستور GROUP BY می توانیم با HAVING (برگرفته از have به معنی داشتن) شرط مضاعف تعیین کنیم، به طور مثال می خواهیم در پرس و جوی بالا فقط ردیف هایی را در نتایج داشته باشیم که میزان ردیف سن از 15 بیشتر باشد، برای این منظور می توانیم نمونه پرس و جوی متغیر sql را به صورت زیر بنویسیم:
SELECT name, age, point FROM tbl_1_name WHERE name != '' GROUP BY point HAVING age > 15
با اجرای کدها خروجی به صورت نمونه زیر خواهد بود:Row Count: 2
Row 1 => Name: A - Age: 20 - Point: 12
Row 2 => Name: F - Age: 16 - Point: 35
استفاده از HAVING می تواند به همراه توابع تجمیعی (مانند SUM) باشد که در این خصوص در آموزش پیش رو به صورت اختصاصی صحبت خواهیم کرد.استفاده از DISTINCT
عبارت DISTINCT به معنی جداسازی و افتراق است و برای اینکه نتایج تکراری را در پرس و جوهای MySQL نداشته باشیم می توانیم از این دستور استفاده کنیم، ممکن است DISTINCT و GROUP BY نتیجه مشابهی داشته باشند اما با دو هدف متفاوت در موتور MySQL تعریف شده اند و در مراحل متفاوتی پردازش می شوند:
- DISTINCT در مرحله انتخاب ردیف ها حذف موارد تکراری را اعمال می کند.
- GROUP BY پس از انتخاب ردیف ها گروه بندی نتایج یکسان را انجام می دهد.
این دو کارکرد متفاوت در هنگام نوشتن پرس و جوهای پیشرفته و چندبخشی به طور مثال در ترکیب با توابع تجمیعی (در آموزش بعدی توضیح خواهیم داد) این امکان را فراهم می کنند که در مراحل مختلف پردازش پرس و جو دستورات متفاوتی را با هم استفاده و نتایج دقیق و و یکتا (Unique) به دست آوریم.
برای آشنایی بیشتر با نحوه کار دستور DISTINCT در نمونه اطلاعاتی که در دیتابیس بالا درج کرده ایم در جدول tbl_1_name دو ردیف 1 و 4 دارای point یکسان هستند و بر این اساس می توانیم نمونه پرس و جوی متغیر sql را به صورت زیر بنویسیم:
SELECT DISTINCT point FROM tbl_1_name WHERE name != ''
با اجرای کدها و اصلاح قسمت while به این شکل:while($row = mysqli_fetch_array($query)){
echo 'Row ' . $loop . ' => ' .
'Point: ' . $row['point'] . '<br><br>';
$loop++;
}
ردیف دوم با مقدار point 12 حذف و خروجی به صورت نمونه زیر خواهد بود:Row Count: 5
Row 1 => Point: 12
Row 2 => Point: 13
Row 3 => Point: 15
Row 4 => Point: 33
Row 5 => Point: 35
اگر برای دستور DISTINCT چند ستون در نظر بگیریم، به فرض:SELECT DISTINCT point, name FROM tbl_1_name WHERE name != ''
هر دو ستون (point و name) باید در یک ردیف شامل مقدار مشترک باشند تا در نتیجه پرس و جو ردیف های تکراری آنها حذف شود در غیر اینصورت به فرض اگر فقط یک ستون دارای مقدار مشترک باشد عمل حذف ردیف تکراری انجام نمی شود.استفاده از ORDER BY
در بسیاری از برنامه ها و صفحات وب نیاز به مرتب سازی و استخراج نتایج سفارشی از پایگاه داده به فرض بر اساس شماره ID، به ترتیب حروف الفبا، طبق تاریخ، بر اساس بزرگتر کوچکتری مقادیر ستون های عددی و مواردی از این قبیل وجود دارد که به همین دلیل پارامتر دیگری تحت عنوان ORDER BY در زبان SQL در نظر گرفته شده است، با استفاده از این دستور در کنار WHERE می توانیم نتایج سفارشی از پرس و جوها استخراج یا آنها را مرتب سازی کنیم، به فرض اگر بخواهیم نتایج پرس و جو در نمونه دیتابیس بالا بر اساس سن کاربران از بزرگتر به کوچکتر دریافت و چینش شوند می توانیم متغیر sql را به شکل زیر تغییر دهیم:
SELECT name, age, point FROM tbl_1_name WHERE name != '' ORDER BY age LIMIT 3
با اجرای کدها خروجی به صورت نمونه زیر خواهد بود:Row Count: 3
Row 1 => Name: E - Age: 12 - Point: 13
Row 2 => Name: B - Age: 13 - Point: 15
Row 3 => Name: C - Age: 15 - Point: 33
با دقت در نحوه چینش ردیف ها مشخص است که اطلاعات بر اساس سن (مقادیر ستون age) از کوچکتر به بزرگتر انتخاب و مرتب سازی شده اند.استفاده از ASC، DESC و تابع RAND
در حالت پیش فرض MySQL نتایج را به صورت صعودی (از کوچک به بزرگ یا Ascending) مرتب سازی می کند، اما مرتب سازی به صورت نزولی (از بزرگ به کوچک یا Descending) و همچنین انتخاب اتفاقی (تصادفی یا Random) با افزودن عباراتی که در ادامه بررسی می کنیم امکانپذیر است، برای تعیین نوع انتخاب و مرتب سازی می توانیم یکی از پارامترهای زیر را در کنار دستور ORDER BY استفاده کنیم:
ASC: استخراج و مرتب سازی پیش فرض یا صعودی (از کوچک به بزرگ)
DESC: استخراج و مرتب سازی نزولی (از بزرگ به کوچک)
RAND: استخراج و مرتب سازی به صورت اتفاقی (تصادفی)
بر این اساس کدی که در بالا نوشتیم را می توانیم به صورت های زیر ویرایش و چینش نتایج حاصل از اجرای پرس و جو را به شکل سفارشی و دلخواه تغییر دهیم.
تغییر پرس و جو با استفاده از ASC برای استخراج و نمایش نتایج به صورت چینش صعودی (حالت پیش فرض):
SELECT name, age, point FROM tbl_1_name WHERE name != '' ORDER BY age ASC LIMIT 3
نمونه خروجی:Row Count: 3
Row 1 => Name: E - Age: 12 - Point: 13
Row 2 => Name: B - Age: 13 - Point: 15
Row 3 => Name: C - Age: 15 - Point: 33
تغییر پرس و جو با استفاده از DESC برای استخراج و نمایش نتایج به صورت چینش نزولی:SELECT name, age, point FROM tbl_1_name WHERE name != '' ORDER BY age DESC LIMIT 3
نمونه خروجی:Row Count: 3
Row 1 => Name: D - Age: 23 - Point: 12
Row 2 => Name: A - Age: 20 - Point: 12
Row 3 => Name: F - Age: 16 - Point: 35
همانطور که مشخص است ردیف ها بر اساس بیشترین مقدار ستون age انتخاب و مرتب سازی شده اند.تغییر پرس و جو با استفاده از تابع RAND برای استخراج و نمایش نتایج به صورت چینش اتفاقی (تصادفی):
SELECT name, age, point FROM tbl_1_name WHERE name != '' ORDER BY RAND() LIMIT 3
نمونه خروجی:Row Count: 3
Row 1 => Name: A - Age: 20 - Point: 12
Row 2 => Name: D - Age: 23 - Point: 12
Row 3 => Name: E - Age: 12 - Point: 13
با دقت در کدها مشخص است که نام هیچ ستونی پس از ORDER BY درج نشده و برای RAND هم از کاراکترهای () استفاده کرده ایم، این کار به دلیل تابع بودن RAND در MySQL است به عبارتی ماهیتا این پارامتر با پارامترهای دیگر متفاوت است و باید Syntax صحیح را در نگارش پرس و جو رعایت کنیم تا برنامه با خطا مواجه نشود.استفاده از AND و OR
در آموزش های مقدماتی زبان PHP با کاربرد کاراکترهای && و || برای سخت و محدود کردن یا بسط دامنه شمول مقایسه های شرطی آشنا شدیم، گفتیم که در برنامه نویسی اگر بخواهیم شرط را سخت و محدود به بررسی پارامترهای بیشتر کنیم از کاراکتر && و اگر بخواهیم دامنه شمول کدهایمان را بسط داده و با تحقق یکی از شرایط، مقایسه برقرار باشد از کاراکتر || استفاده می کنیم، مشابه این مبحث در نوشتن پرس و جوهای MySQL نیز با دستورات AND (به معنی 'و') و OR (به معنی 'یا') قابل استفاده است، از دستور AND برای محدود کردن هرچه بیشتر ردیف های انتخابی و از OR برای بسط پرس و جو و انتخاب ردیف ها با تحقق یکی از شرایط بهره می گیریم.
به طور مثال اگر بخواهیم از نمونه جدول بالا اسامی را استخراج کنیم که age آنها از 15 بزرگتر و point آنها از 15 کوچکتر باشد خواهیم نوشت:
SELECT name, age, point FROM tbl_1_name WHERE name != '' AND age > 15 AND point < 15
دستور بالا کاربرانی را که سن آنها بالاتر از 15 و امتیاز کسب شده کمتر از 15 باشد را در لیست نتایج پرس و جو نمایش می دهد:Row Count: 2
Row 1 => Name: A - Age: 20 - Point: 12
Row 2 => Name: D - Age: 23 - Point: 12
همین پرس و جو را اگر با OR بنویسیم خروجی متفاوت خواهد بود:SELECT name, age, point FROM tbl_1_name WHERE name != '' AND age > 15 OR point < 15
Row Count: 4
Row 1 => Name: A - Age: 20 - Point: 12
Row 2 => Name: D - Age: 23 - Point: 10
Row 3 => Name: E - Age: 12 - Point: 13
Row 4 => Name: F - Age: 16 - Point: 35
در این حالت ردیف هایی از دیتابیس انتخاب می شوند که یا age آنها از 15 بزرگتر باشد یا اینکه point آنها از 15 کمتر باشد، با برقرار بودن هر کدام از این دو شرط فیلد متناظر انتخاب و به لیست نتایج اضافه می شود.استفاده از IN و BETWEEN
آخرین دستوراتی که در این آموزش قصد بررسی آنها را داریم IN و BETWEEN هستند، IN وجود مقدار ستون مد نظر در لیست مقادیر یا نتیجه یک پرس و جوی مستقل زیرمجموعه (Subquery) دیگر را بررسی می کند، BETWEEN نیز برای بررسی قرار داشتن مقدار ستون مورد نظر در یک بازه (Range) خاص (شامل اعداد و تاریخ) استفاده می شود.
به فرض اگر بخواهیم از نمونه جداولی که در بالا ایجاد کرده ایم صرفا ردیف هایی از جدول tbl_1_name استخراج شوند که مقادیر ستون name آنها در جدول tbl_2_name وجود داشته باشد می توانیم پرس و جوی متغیر sql را به شکل زیر بنویسیم:
SELECT name, age, point FROM tbl_1_name WHERE name IN (SELECT name FROM tbl_2_name)
خروجی نمونه پرس و جوی بالا به شکل زیر خواهد بود:Row Count: 2
Row 1 => Name: A - Age: 20 - Point: 12
Row 2 => Name: C - Age: 15 - Point: 33
از دستور IN برای جستجو در لیست مقادیر هم می توانیم استفاده کنیم، مثال:SELECT name, age, point FROM tbl_1_name WHERE name IN ('A', 'D', 'F')
خروجی این حالت به شکل زیر خواهد بود:Row Count: 3
Row 1 => Name: A - Age: 20 - Point: 12
Row 2 => Name: D - Age: 23 - Point: 12
Row 3 => Name: F - Age: 16 - Point: 35
دستور IN در حالت لیست معادل کاربرد چند OR در پرس و جو است.شکل منفی دستور IN با افزودن NOT قابل تعریف است، در این حالت ردیف هایی انتخاب می شوند که در لیست IN وجود نداشته باشند، مثال:
SELECT name, age, point FROM tbl_1_name WHERE name NOT IN (SELECT name FROM tbl_2_name)
خروجی این پرس و جو به شکل زیر خواهد بود:Row Count: 4
Row 1 => Name: B - Age: 13 - Point: 15
Row 2 => Name: D - Age: 23 - Point: 12
Row 3 => Name: E - Age: 12 - Point: 13
Row 4 => Name: F - Age: 16 - Point: 35
همان طور که مشخص است ردیف هایی از جدول tbl_1_name استخراج شده اند که مقادیر ستون name آنها در جدول tbl_2_name وجود ندارد.دستور BETWEEN نیز برای محدود کردن نتایج مورد نظر به بازه خاصی کاربرد دارد، این بازه با توجه به نوع داده ستون مورد نظر می تواند عدد یا تاریخ باشد، به فرض اگر بخواهیم از جدول tbl_1_name صرفا ردیف هایی را استخراج کنیم که مقادیر point آنها بین 13 و 33 باشد قسمت sql را به شکل زیر می نویسیم:
SELECT name, age, point FROM tbl_1_name WHERE point BETWEEN 13 AND 33
خروجی پرس و جوی بالا به شکل زیر خواهد بود:Row Count: 3
Row 1 => Name: B - Age: 13 - Point: 15
Row 2 => Name: C - Age: 15 - Point: 33
Row 3 => Name: E - Age: 12 - Point: 13
در حالت مثبت BETWEEN اعداد 13 و 33 راهم شامل می شود (در اصطلاح Inclusive) و معادل بزرگتر مساوی و کوچکتر مساوی (<= و >=) است، اما در حالت منفی با NOT اعداد 13 و 33 شامل نمی شوند، مثال:SELECT name, age, point FROM tbl_1_name WHERE point NOT BETWEEN 13 AND 33
که خروجی این پرس و جو برابر است با:Row Count: 3
Row 1 => Name: A - Age: 20 - Point: 12
Row 2 => Name: D - Age: 23 - Point: 10
Row 3 => Name: F - Age: 16 - Point: 35
مقایسه BETWEEN در حالت منفی بر مبنای بزرگتر و کوچکتر (< و >) است.دستور BETWEEN برای استخراج نتایج در بازه زمانی نیز کاربرد دارد، در این حالت به جای دو عدد دو تاریخ با فرمت میلادی (yyyy-mm-dd) یا به صورت برچسب زمان (Unix Timestamp) به عنوان نقطه شروع و پایان بازه جستجو در جدول در نظر می گیریم، مثال:
SELECT col_name FROM tbl_name WHERE col_date BETWEEN '2020-01-02' AND '2020-03-18';
در حالت عادی رفتار BETWEEN به صورت Inclusive است یعنی خود تاریخ شروع و پایان را نیز شامل می شود اما اگر تاریخ ها به همراه زمان یا با نوع داده نامعتبری باشند ممکن است برخی ردیف ها در لیست نتایج انتخاب نشوند، برای دریافت تمام ردیف ها شامل روز شروع و پایان و جلوگیری از مشکلات پیش بینی نشده می توانیم با تابع DATE یا CAST به صورت نمونه های زیر ورودی ها یا مقدار ستون مورد نظر را به فرمت استاندارد تبدیل کنیم:SELECT col_name FROM tbl_name WHERE col_date BETWEEN CAST('2014-02-01 21:13:16' AS DATE) AND CAST('2014-02-28 06:11:01' AS DATE);
SELECT col_name FROM tbl_name WHERE DATE(col_date) BETWEEN '2014-02-01' AND '2014-02-28';
در صورت کار با تاریخ و زمان به صورت برچسب زمان (Unix Timestamp) تابع UNIX_TIMESTAMP برای تبدیل تاریخ عادی به برچسب زمان و تابع FROM_UNIXTIME برای تبدیل برچسب زمان به تاریخ عادی در پرس و جوهای MySQL کاربرد خواهند داشت، مثال:SELECT col_name FROM tbl_name WHERE col_date BETWEEN UNIX_TIMESTAMP('2014-02-01 00:00:00') AND UNIX_TIMESTAMP('2014-02-28 00:00:00');
SELECT col_name FROM tbl_name WHERE FROM_UNIXTIME(col_date) BETWEEN '2014-02-01 00:00:00' AND '2014-02-28 00:00:00';

استفاده از WHERE در پرس و جوی MySQL
آموزش MySQL، سیستم مدیریت پایگاه داده
اتصال PHP به MySQL با اکستنشن MySQLi
نحوه ذخیره کردن اطلاعات با دستور INSERT در MySQL
توابع تجمیعی (Aggregate Functions) در MySQL


mysql_query("SELECT * FROM table WHERE name != '' AND age > 40 OR name != '' AND age < 20 ORDER BY age");
این کد را میتوان به این شکل ساده تر نمودmysql_query("SELECT * FROM table WHERE name != '' AND (age > 40 OR age < 20) ORDER BY age");
استفاده از پرانتز کلید تکرار نشدن کدها است. احتمالا استاد نمیدونستن با عرض پوزش$sql = "SELECT `id`, `user`, (SELECT COUNT(*) FROM `table` WHERE table.point >= (SELECT `point` FROM `table` WHERE `user` = 'D')) AS `position` FROM `table` WHERE `user` = 'D'";
$result = mysqli_query($conn, $sql);
while($row = mysqli_fetch_array($result, MYSQLI_ASSOC)){
echo $row["position"];
}
قاعدتا این کد کامل نیست و با توجه به اکستنشی که از آن استفاده می کنید (MySQL، MySQLi یا PDO) باید قسمت ارتباط با پایگاه داده را اضافه و نام کاربر را ویرایش کنید، یعنی به جای عبارت D که فرضی است نام کاربر را به صورت متغیر در پرس و جو جایگزین نمائید، با توجه به اینکه یکی از ساده ترین روش های هک سایت ها نفوذ از طریق پرس و جوهای دیتابیس است، اکیدا توصیه می کنیم آموزش های مقدماتی MySQL را از پایه دنبال کنید تا با نحوه نوشتن پرس و جوهای امن و استفاده از روش هایی مانند Prepared Statements آشنا شوید.من یه جدول ساختم که توش چندین کاربر با امتیازات متفاوت وجود داره و این امتیازات هر لحظه متغیر است میخوام هر دفعه کاربر درخواست داد بتونه با توجه به امتیاز خود رتبه خودش رو ببینه یعنی جدول بر ارسال امتیاز نفرات را مرتب کنه و کسی که درخواست کرده در ردیف چند هست را براش بفرسته مثال ساده اینکه مثلا سه نفر تو جدول هستش
اکبر 10 امتیاز
علی 7 امتیاز
نادر 5 امتیاز
حالا وقتی علی خواست رتبه رو ببینه جدول بر ارسال امتیاز اول بیاد اوردر بای کنه تا اسامی طبق چینش بالا مرتب بشه و بعد علی که در رتبه دوم هست عدد 2 را براش ارسال کنه ممنون میشم این کد رو برام بفرستین مرسیSELECT `id`, `user`, (SELECT COUNT(*) FROM `table` WHERE table.point >= (SELECT `point` FROM `table` WHERE `user` = 'D')) AS `position` FROM `table` WHERE `user` = 'D'
برای تست پرس و جوی بالا یک جدول با نام فرضی table با سه ستون id، user و point در برنامه phpMyAdmin بسازید و چند کاربر با نام های A، B، C و D را با مقادیر دلخواه وارد کنید.دوتا سوال دارم
سوال اول در مورد group by
SELECT `tbl_packages`.`id`, COUNT(`tbl_stickers`.`id`) AS `total_stickers` FROM `tbl_packages` INNER JOIN `tbl_stickers` ON `tbl_packages`.`id` = `tbl_stickers`.`package_id` GROUP BY `tbl_stickers`.`package_id` HAVING `total_stickers` < '3'
من اینجا میخوام در خروجی فقط ستون id از جدول tbl_packages بره و چیز دیگه ای نره الان هم آیدی به خروجی میره هم total_stickers به نظر شما چه راهی دارم ؟ اگه این دستور رو بردارم COUNT(`tbl_stickers`.`id`) AS `total_stickers`
مشکل تا حدی حله ولی عملیات group by بهم میریزه و از ستون فرضی که ساختم قسمت شرط HAVING ازش استفاده میکنم لطفا یه راه حلی بدیداما سوال دوم در مورد بازم GROUP BY
من یک هاستی خریدم که عملیات گروپ بای مشکل داره در بعضی موارد مثلا اگه دستور بالا رو بنویسم مشکل نداره اما همون دستور بالا رو اگه اینطوری تغییر بدم مشکل داره
SELECT * FROM `tbl_packages` INNER JOIN `tbl_stickers` ON `tbl_packages`.`id` = `tbl_stickers`.`package_id` GROUP BY `tbl_stickers`.`package_id`
اما اگه select * from رو یه تغییری بدم مثلا اینطوری کنمselect `tbl_packages`.* FROM
مشکلش رفع میشه یا اینکه اگه این دستور رو بنویسم مشکل دارهSELECT * FROM `tbl_users` GROUP BY `chat_id`
در اینجا اگه * (استار) رو تغییر بدم مثل قبلی بازم مشکلش رفع نیمشه و در هر دو مورد یک ارور رو میدن که متن ارور رو عکسشو لینکش در پایین هستhttp://up.iranblog.com/files/1541788655.png
توضیحات اضافی:در مورد این مشکل با پشتیبانی هاستم صحبت کردم گفت با یک برنامه نویس در این مورد صحبت کنید احتمالا کدای mysql بلد نیستید!! ولی همین کارا رو تو xampp انجام میدم هیچ مشکلی نداره
در مورد سوال اول می توانید پرس و جو را به شکل زیر ویرایش کنید:
SELECT `tbl_packages`.`id` FROM `tbl_packages` INNER JOIN `tbl_stickers` ON `tbl_packages`.`id` = `tbl_stickers`.`package_id` GROUP BY `tbl_stickers`.`package_id` HAVING COUNT(`tbl_stickers`.`id`) < '3';
در مورد سوال دوم این به فعال بودن حالت ONLY_FULL_GROUP_BY در SQL Mode برمی گردد، ظاهرا در آخرین نسخه های MySQL این حالت به صورت پیش فرض فعال است و بهتر است پرس و جوها را با همین فرض بنویسید، در صورت نیاز نیز می توانید از طریق برنامه phpMyAdmin سربرگ Variables قسمت sql mode را پیدا کرده و پارامتر ONLY_FULL_GROUP_BY را حذف کنید، اگر دسترسی به این قسمت محدود شده باشد باید از پشتیبانی هاست خود بخواهید.بازم از زحماتتون ممنونم
Array
(
[0] => Array
(
[Name1] => 1
[Score1] => 1
)
)
بر همین اساس راه حل پیشنهادی ایجاد خروجی به صورت نمونه آرایه زیر بود (کد ویرایش شده خروجی مشابه این آرایه تولید می کند):Array
(
[0] => Array
(
[Name1] => 1
[Score1] => 1
)
[1] => Array
(
[Name2] => 2
[Score2] => 2
)
[2] => Array
(
[Name3] => 3
[Score3] => 3
)
[3] => Array
(
[Name4] => 4
[Score4] => 4
)
)
اگر با آرایه ها در PHP آشنا باشید می توانید از این خروجی هر طور که مورد نیاز است استفاده کنید، البته احتمالا باید کدهای قسمت چاپ نتیجه نیز ویرایش شوند، اگر نتوانید از این آرایه استفاده کنید صرفا با دسترسی و امکان تست کدها است که می توان مشکل را رفع کرد.$pdo = new PDO(dsn, username, password);
if(isset($_POST['Rotbe'])){
$stmt = $pdo -> query( ' SELECT * FROM Emtiyazat ORDER BY Score DESC LIMIT 10 ');
$a = array ();
$loop = 1;
while($row = $stmt->fetch ()){
array_push($a, array('Name' . $loop => $row['Name'], 'Score' . $loop => $row['Score']));
$loop++;
}
echo json_encode($a);
$pdo = null;
}
با سلام خدمت استاد عزیزکد بالا درست کار میکنه و طبق دستور نام و امتیازات ده نفر اول جدول بر اساس id را ارسال میکنه و در برنامه در یک تکست نشان میدهد مشکل همین است تمام اسمها را در یک تکست نشان میدهد من اگر بخواهم نام نفر اول را و دوم را و سوم را و تا ده هر کدام را جدا جدا بفرستت باید چه دستوری اضافه کنم
در اینجا Name1 تمامی اسمها را دریافت میکند مثلا چه دستوری بنویسم که Name1 نام نفر اول جدول طبق id بگیرد و مثلا Name2 نام نفر دوم و الی اخر
ممنون از سایت خوبتون
دقیقا این
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'rand()' at line 1
مشکل اینجا بود که id از نوع int نبود. حل شد. خیلی خیلی ممنون از لطف شما
بدون شرط هم امتحان کردم ولی باز مرتب نمیکنه طرز صحیح نوشتن کد با شرط و بدون شرط رو اگه ممکنه بهم بگین. ممنون
res = mysqli_query($conn, "select * from sabt Order By id");
این دستور رو نوشتم ولی زمانی که داده ها نمایش داده میشوند باز مرتب نشون نمیده
$res = mysqli_query($conn, "select * from sabt where id=$id Order By id");
من با دستور LIMIT تعداد رکورد های دریافتی رو 10 قرار دادم. حالا سوال اینه اگر قصد دسترسی به 10 رکورد بعدی رو داشته باشم باید چیکار کنم؟؟ و به همین ترتیب..
ممنون میشم راهنماییم کنید.
واقعا دستتون درد نکنه.
الان که بیشتر دقت میکنم میبینم که تو آموزش شما بهترین هستید.
واقعا کارتون عالیه.
ایشالا همیشه موفق باشید
یا علی
حذف شد
چه تغييري بايد در كد بالا بدم؟؟؟از شما ممنون !!! لازم به ذكره با كمك هاي شما تا حالا تونستم يك مديريت محتواي ساده راه اندازي كنم.
با تشكر اوس
$query_Recordset1 = "SELECT * FROM page_index ORDER BY id ASC";
نکته: ستون id می تواند در جدول شما نام دیگری داشه باشد (معمولا id شماره یکتای هر مطلب از کوچکتر به بزرگتر است).
- به سوالات کلی، زمانبر، مبهم و مشکلاتی که تلاشی برای رفع آنها نکرده باشید پاسخ مختصر داده شده یا به بخش برنامه نویسی اختصاصی ارجاع داده می شوند.
- کدها و اسکریپت های طولانی را ترجیحا در یک صفحه وب آنلاین یا به صورت حساب موقت و آزمایشی قرار دهید تا امکان بررسی دقیق مشکل و خطایابی میسر باشد.
- تمام دیدگاه های ارسالی خوانده شده و برای هر کاربر مدت زمان لازم جهت پاسخگویی در نظر گرفته می شود، لطفا از طرح سوالات متعدد در بازه زمانی کوتاه خودداری کنید.