Web Programming Advanced SQL and PHP Advanced queries Querying more than one table Searching tables to find information Aliasing tables PHP functions for using query results
استفاده از جداول مرتبط SQL یک پایگاه داده رابطه ای است. یعنی می توان با چند جدول کار نمود و همزمان چندین جدول را مورد سوال قرار داد. استفاده از چند جدول مختلف و مرتبط بصورت همزمان دارای مزایای زیر است : می توان اطلاعات بیشتری را بدون تکرار کردن و اضافه کاری ذخیره نمود. به روز رسانی جداول و تغییر آنها راحتتر است. می توان انواع مختلفی از پرس و جوها را انجام داد و اطلاعات را منطبق بر نیازهای مساله بازیابی نمود.
پرس و جوهای پیشرفته فرض کنید جداول زیر را تعریف نموده ایم. mysql> describe clients; | Field | Type | Null | Key | Default | Extra | | client_id | int(11) | NO | PRI | NULL | auto_increment | | f_name | varchar(20) | YES | | NULL | | | l_name | varchar(30) | NO | | | | | address | varchar(40) | YES | | NULL | | | city | varchar(30) | YES | | NULL | | | postcode | varchar(12) | YES | | NULL | | rows in set (0.01 sec) mysql> describe purchases; | Field | Type | Null | Key | Default | Extra | | purchase_id | int(11) | NO | PRI | NULL | auto_increment | | client_id | int(11) | NO | | | | | date | date | NO | | | | rows in set (0.00 sec)
mysql> describe itemlist; | Field | Type | Null | Key | Default | Extra | | item_id | int(11) | NO | PRI | NULL | auto_increment | | purchase_id | int(11) | NO | | | | | book_id | int(11) | NO | | | | rows in set (0.00 sec) mysql> describe books; | Field | Type | Null | Key | Default | Extra | | book_id | int(11) | NO | PRI | NULL | auto_increment | | title | varchar(50) | NO | | | | | pages | int(11) | YES | | NULL | | rows in set (0.00 sec) mysql> ادامه....
در مساله قبلی، ما تعدادی مشتری داریم که خریدهای متفاوتی را انجام می دهند. هر خرید شامل چندین آیتم است. هر آیتم یک کتاب است که ممکن است توسط چندین مشتری خریداری شود. تعریف جداول متفاوت به ما اجازه می دهد که از تکرار اطلاعات جلوگیری کنیم و به صورتهای مختلفی پرس و جو های مورد نیاز را انجام دهیم. فیلد id به ما اجازه می دهد جداول را با هم استفاده کنیم. مثلا، هر مشتری یک client_id دارد که خریدهای متفاوتی را ممکن است انجام دهد. اگر در جدول خریدها دنبال client_id بگردیم می توانیم خریدهای مشتری را پیدا کنیم. بطورمشابه می توانیم با جستجوی purchase_id در جدول itemlist آیتمهای خریداری شده را مشخص کنیم.
انتشار جداول فرض کنید داده های زیر را در جداول تعریف شده ذخیره کرده ایم. mysql> select * from clients; | client_id | f_name | l_name | address | city | postcode | | 1 | Russell | Martin | Dept of Computer Science | Liverpool | L69 3BX | | 2 | Bob | Milnor | 12 Peachtree Ln | Liverpool | L12 3DX | | 3 | Sarah | Ford | 542b Jersey Rd | West Kirby | L43 8JK | | 4 | Larry | Vance | 76 Jarhead Ln | Liverpool | L12 4RT | | 5 | Paul | Abbott | 90 Crabtree Pl | Leamingotn Spa | CV32 7YP | rows in set (0.01 sec) mysql> select * from books; | book_id | title | pages | | 1 | Linux in a Nutshell | 120 | | 2 | Learning SQL | 289 | | 3 | Abstract Algebra | 320 | | 4 | Rising Sun | 830 | | 5 | Round the Moon | 136 | | 6 | Blackbeard | 292 | rows in set (0.00 sec) mysql>
ادامه... mysql> SELECT * FROM purchases; | purchase_id | client_id | date | | 1 | 1 | | | 2 | 1 | | | 4 | 2 | | | 5 | 4 | | | 6 | 3 | | | 7 | 5 | | | 8 | 3 | | rows in set (0.00 sec) mysql> SELECT * FROM itemlist; | item_id | purchase_id | book_id | | 1 | 1 | 2 | | 2 | 1 | 6 | | 3 | 1 | 3 | | 4 | 2 | 4 | | 5 | 2 | 5 | | 6 | 4 | 5 | | 7 | 4 | 6 | | 8 | 5 | 1 | | 9 | 5 | 3 | | 10 | 6 | 5 | | 11 | 7 | 2 | | 12 | 8 | 3 | rows in set (0.00 sec) mysql>
جستجوهای پیشرفته 1 myql> SELECT * from clients, purchases WHERE clients.client_id=purchases.client_id ORDER BY purchase_id; |client_id | f_name | l_name | address | city | postcode | purchase_id | client_id | date | | 1 | Russell | Martin | Dept of Computer Science | Liverpool | L69 3BX | 1 | 1 | | | 1 | Russell | Martin | Dept of Computer Science | Liverpool | L69 3BX | 2 | 1 | | | 2 | Bob | Milnor | 12 Peachtree Ln | Liverpool | L12 3DX | 4 | 2 | | | 4 | Larry | Vance | 76 Jarhead Ln | Liverpool | L12 4RT | 5 | 4 | | | 3 | Sarah | Ford | 542b Jersey Rd | West Kirby | L43 8JK | 6 | 3 | | | 5 | Paul | Abbott | 90 Crabtree Pl | Leamingotn Spa | CV32 7YP | 7 | 5 | | | 3 | Sarah | Ford | 542b Jersey Rd | West Kirby | L43 8JK | 8 | 3 | | rows in set (0.01 sec) mysql>
جستجوهای پیشرفته 2 فیلد client_id تکرار شده است. زیرا ما تمام ستونها را انتخاب کرده ایم ( استفاده از گزینه *). برای جلوگیری از این امر بدین صورت عمل می کنیم. mysql> SELECT clients.client_id, f_name, l_name, address, city, postcode, purchases.purchase_id,date from clients, purchases WHERE clients.client_id=purchases.client_id ORDER BY purchase_id; | client_id | f_name | l_name | address | city | postcode | purchase_id | date | | 1 | Russell | Martin | Dept of Computer Science | Liverpool | L69 3BX | 1 | | | 1 | Russell | Martin | Dept of Computer Science | Liverpool | L69 3BX | 2 | | | 2 | Bob | Milnor | 12 Peachtree Ln | Liverpool | L12 3DX | 4 | | | 4 | Larry | Vance | 76 Jarhead Ln | Liverpool | L12 4RT | 5 | | | 3 | Sarah | Ford | 542b Jersey Rd | West Kirby | L43 8JK | 6 | | | 5 | Paul | Abbott | 90 Crabtree Pl | Leamingotn Spa | CV32 7YP | 7 | | | 3 | Sarah | Ford | 542b Jersey Rd | West Kirby | L43 8JK | 8 | | rows in set (0.00 sec) mysql> استفاده از گزینه NATURAL JOIN نتیجه مشابهی دارد. mysql> SELECT * FROM clients NATURAL JOIN purchases;
جستجوهای پیشرفته 3 لازم نیست تمام فیلدها را بازیابی نمود. mysql> SELECT f_name,l_name, purchases.purchase_id FROM clients NATURAL JOIN purchases ORDER BY purchase_id; | f_name | l_name | purchase_id | | Russell | Martin | 1 | | Russell | Martin | 2 | | Bob | Milnor | 4 | | Larry | Vance | 5 | | Sarah | Ford | 6 | | Paul | Abbott | 7 | | Sarah | Ford | 8 | rows in set (0.00 sec) mysql>
جستجوهای پیشرفته 4 با استفاده از WHERE می توان جستجوهای پیشرفته تری انجام داد. mysql> SELECT purchases.purchase_id, f_name, l_name, date FROM purchases, clients WHERE purchases.client_id=clients.client_id; | purchase_id | f_name | l_name | date | | 1 | Russell | Martin | | | 2 | Russell | Martin | | | 4 | Bob | Milnor | | | 5 | Larry | Vance | | | 6 | Sarah | Ford | | | 7 | Paul | Abbott | | | 8 | Sarah | Ford | | rows in set (0.00 sec) mysql>
ادامه.... پیدا کردن تمام خریدهای انجام شده توسط فردی به نام Ford mysql> SELECT purchases.purchase_id, f_name, l_name, date FROM purchases, clients WHERE (purchases.client_id=clients.client_id) AND (l_name='Ford'); | purchase_id | f_name | l_name | date | | 6 | Sarah | Ford | | | 8 | Sarah | Ford | | rows in set (0.01 sec) mysql>
سوال از چند جدول می توان بیش از دو جدول را مورد سوال قرار داد : ابتدا تمام خریدهای انجام شده توسط فردی به نام martin را پیدا می کنیم. mysql> select purchases.purchase_id, f_name, l_name, date FROM purchases, clients WHERE (purchases.client_id=clients.client_id) AND (l_name='Martin') ORDER BY purchases.purchase_id; | purchase_id | f_name | l_name | date | | 1 | Russell | Martin | | | 2 | Russell | Martin | | rows in set (0.00 sec) mysql>
ادامه... حال ببینیم چه کتابهایی خریده است : mysql> SELECT purchases.purchase_id, f_name, l_name, date, itemlist.book_id FROM purchases, clients, itemlist WHERE (purchases.client_id=clients.client_id) AND (l_name='Martin') AND (purchases.purchase_id=itemlist.purchase_id) ORDER BY purchases.purchase_id; | purchase_id | f_name | l_name | date | book_id | | 1 | Russell | Martin | | 2 | | 1 | Russell | Martin | | 6 | | 1 | Russell | Martin | | 3 | | 2 | Russell | Martin | | 5 | | 2 | Russell | Martin | | 4 | rows in set (0.00 sec) mysql>
حال عنوان کتابهای خریداری شده را مشخص می کنیم. mysql> SELECT purchases.purchase_id, f_name, l_name, date, itemlist.book_id, title FROM purchases, clients, itemlist, books WHERE (purchases.client_id=clients.client_id) AND (l_name='Martin') AND (purchases.purchase_id=itemlist.purchase_id) AND (itemlist.book_id=books.book_id) ORDER BY purchases.purchase_id; | purchase_id | f_name | l_name | date | book_id | title | | 1 | Russell | Martin | | 6 | Blackbeard | | 1 | Russell | Martin | | 2 | Learning SQL | | 1 | Russell | Martin | | 3 | Abstract Algebra | | 2 | Russell | Martin | | 4 | Rising Sun | | 2 | Russell | Martin | | 5 | Round the Moon | rows in set (0.00 sec) mysql> ادامه...
مثل سابق لازم نیست تمام فیلدها را بازیابی نمود. mysql> SELECT purchases.purchase_id, title FROM purchases, clients, itemlist, books WHERE (purchases.client_id=clients.client_id) AND (l_name='Martin') AND (purchases.purchase_id=itemlist.purchase_id) AND (itemlist.book_id=books.book_id) ORDER BY purchases.purchase_id; | purchase_id | title | | 1 | Blackbeard | | 1 | Learning SQL | | 1 | Abstract Algebra | | 2 | Rising Sun | | 2 | Round the Moon | rows in set (0.00 sec) mysql>
استفاده از اسامی مستعار در جستجوها می توان از اسامی مستعار برای کاهش طول جستجوها استفاده نمود. mysql> select p.purchase_id, title FROM purchases AS p, clients AS c, itemlist AS i, books WHERE (p.client_id=c.client_id) AND (l_name='Martin') AND (p.purchase_id=i.purchase_id) AND (i.book_id=books.book_id) ORDER BY p.purchase_id; | purchase_id | title | | 1 | Blackbeard | | 1 | Learning SQL | | 1 | Abstract Algebra | | 2 | Rising Sun | | 2 | Round the Moon | rows in set (0.00 sec)
جستجوی جداول 1 کاراکتر wildcard زبان SQL علامت % است. % با هر چیزی مطابقت دارد. mysql> SELECT * FROM clients WHERE l_name LIKE '%a%'; | client_id | f_name | l_name | address | city | postcode | | 1 | Russell | Martin | Dept of Computer Science | Liverpool | L69 3BX | | 4 | Larry | Vance | 76 Jarhead Ln | Liverpool | L12 4RT | | 5 | Paul | Abbott | 90 Crabtree Pl | Leamingotn Spa | CV32 7YP | rows in set (0.00 sec) جستجوی بالا تمام کاربرانی را که در اسم فامیلی آنها حرف a وجود دارد را پیدا می کند. mysql> SELECT * FROM clients where l_name LIKE '%an%'; | client_id | f_name | l_name | address | city | postcode | | 4 | Larry | Vance | 76 Jarhead Ln | Liverpool | L12 4RT | row in set (0.00 sec) جستجوی فوق تمام کاربرانی را که اسم فامیلی آنها شامل an است را پیدا می کند.
جستجوی جداول 2 mysql> SELECT clients.client_id, f_name, l_name FROM clients NATURAL JOIN purchases where l_name LIKE '%a%'; | client_id | f_name | l_name | | 1 | Russell | Martin | | 4 | Larry | Vance | | 5 | Paul | Abbott | rows in set (0.00 sec) mysql> SELECT clients.client_id, f_name, l_name FROM clients, purchases WHERE (l_name LIKE '%a%') AND (clients.client_id=purchases.client_id) AND (clients.client_id > 1); | client_id | f_name | l_name | | 4 | Larry | Vance | | 5 | Paul | Abbott | rows in set (0.00 sec)
ارتباط PHP و MySQL برای افزایش امنیت سایت بهتر است اطلاعات مربوط به سرور mysql ، اسم پایگاه داده، اسم کاربر و رمز عبور را در فایل جداگانه ای تایپ کرده و در برنامه اصلی آنرا include کنید. <?php /* Save this as db_login.php (or whatever you like) and include it in your php script. */ // Here ’ s the information to connect to the database. $db_host = ‘ mysql ’ ; $db_database= ‘ martin ’ ; $db_username= ‘ martin ’ ; $db_password= ‘’ ; ?> اگر حتی کسی اسم فایل فوق را بداند و بخواهد فایل فوق را ببیند، وب سرور در بین راه وجود دارد. چون این فایل هیچ دستور echo ندارد یک صفحه خالی برای او ارسال خواهد شد.
وصل شدن به پایگاه داده حال در صفحه اصلی به صورت زیر عمل کنید. <?php include_once ( ‘ db_login.php ’ ); $connection = mysql_connect($db_host, $db_username, $db_password); if (!$connection) { exit( “ Could not connect to the database: ”. htmlspecialchars(mysql_error()) ); } else { // more statements here... } ?> Note: The function ‘ htmlspecialchars() ’ converts special characters in a string into their HTML escape sequences (like ‘ & ’ into ‘ & ’ and so forth). This can also be used to increase the security of your code by and help thwart attacks on your database by passing it information that your client has submitted before trying to insert it in your database.
انجام جستجوهای MySQL از طریق PHP جستجوهایی که از طریق PHP به mysql فرستاده می شوند کاملا مشابه هستند با این تفاوت که نیازی به تایپ ; وجود ندارد. <?php // Assuming a valid database connection has been established. // Build the query string by assigning variables... $query = $select. $column. $from. $tables. $where; $result = mysql_query($query); if(!$result) { exit( “ Could not query the database: ”. htmlspecialchars(mysql_error()) ); } else { // process the data } ?>
پردازش نتایج جستجو توابع ‘ mysql_fetch_row() ’ و ‘ mysql_fetch_array() ’ برای خواندن نتایج مفید هستند. <?php // Assuming a database connection, and a valid query string. $result = mysql_query( $query ); while ($result_row = mysql_fetch_row($result)) { echo $result_row[2]. ‘ ’ ; } ?> تابع mysql_fetch_row() نتایج جستجو را بصورت یک آرایه می خواند و هر بار یک ردیف را می خواند. وقتی دیگر ردیفی وجود نداشته باشد مقدار FALSE را بر می گرداند.
پردازش نتایج جستجو ( ادامه ) تابع mysql_fetch_array یک ردیف از نتایج را به صورت انجمنی می خواند. اگر ارگومان دوم که اختیاری است یرابر MYSQL_ASSOC باشد، نتایج بر اساس اسم ستونها ایندکس می شوند و می توان یک ستون خاص را مورد سوال قرار داد. اگر ارگومان دوم یرابر MYSQL_NUM باشد، نتایج بر اساس شماره ستونها ایندکس می شوند و می توان یک ستون خاص را مورد سوال قرار داد. مقدار پیش فرض MYSQL_BOTH نیز به هر دو صورت کار می کند. while ( $row = mysql_fetch_array($result, MYSQL_ASSOC) ) { echo $row[ “ title ” ]. ‘ ’ ; }
توابع مفید دیگر در PHP/SQL تابع ‘ mysql_data_seek($result, $value) ’ را می توان برای حرکت دادن اشاره گر داخلی نتایج استفاده نمود. یعنی می توان کاری کرد که ردیفهای قبلی را مورد استفاده قرار داد بدون اینکه پایگاه داده را دوباره مورد سوال قرار داد. تابع ‘ mysql_data_seek($result, 0); ’ ما را به اول نتایج می برد. تابع ‘ mysql_num_rows ($result); ’ تعداد ردیفهای جواب را بر می گرداند. تابع ‘ mysql_affected_rows(); ’ تعداد ردیفهایی را که در اثر اجرای دستورات INSERT, DELETE, UPDATE, یا REPLACE تغییر کرده اند را بر می گرداند. تابع ‘ mysql_insert_id(); ’ آخرین id که توسط AUTO_INCREMENT تولید شده است را بر می گرداند. اگر مقدار برگشتی صفر باشد یعنی AUTO_INCREMENT تغییر نکرده است.