با سلام، در این قسمت از سری آموزشی ارتباط شیء گرا با پایگاه داده (PDO) به سراغ مباحث پیرامون ردیف ها (مانند تعداد ردیف ها و ردیف های تاثیر گرفته) می پردازیم.
رابط PDO تابعی به نام ()PDOstatement::rowCount
ارائه می دهد که تعداد ردیف های پیدا شده توسط کوئری را به شما برمیگرداند. این تابع بسیار به ندرت استفاده می شود و اگر بخواهم صادقانه تر بگویم احتمالا هیچ وقت در برنامه های عادی خود از آن استفاده نکنید اما از باب آشنایی توضیح کوتاهی از آن ارائه می دهیم.
اگر از قبل با این تابع آشنا بوده اید میدانید که این تابع یکی از آن توابعی است که در موارد بسیار زیادی به شکل اشتباه استفاده شده است.
توسعه دهندگان مبتدی و حتی بعضا حرفه ای بیشتر اوقات برای شمردن چیزی از آن استفاده نمی کنند بلکه با آن چک می کنند تا ببینند داده ای برگشت داده شده است یا نه. این کار اشتباهی است! چرا که برای چنین مواقعی خود داده را دارید! یعنی از دستورات ()fetch و ()fetchAll استفاده کنید و دقیقا همین کار را برایتان انجام می دهند.
فرض کنید می خواهیم ببینیم آیا کاربری با فلان نام خاص وجود دارد یا خیر. اگر وجود داشت تنها یک ردیف را انتخاب می کنیم:
$stmt = $pdo->prepare("SELECT 1 FROM users WHERE name=?"); $stmt->execute([$name]); $userExists = $stmt->fetchColumn();
این حالت دقیقا برای دریافت یک ردیف یا چندین ردیف در یک آرایه یکی است:
$data = $pdo->query("SELECT * FROM table")->fetchAll(); if ($data) { // در اینجا داده را دارید و نیازی به تابع دیگری نیست }
اگر به کد بالا توجه کنید می بینید که نیازی به تابع ()rowCount
نیست چرا که اینجا نیازی به تعداد دقیق ردیف ها نداریم بلکه نیاز به یک flag بولین داریم که بگوید آیا داده ای داریم یا خیر. به همین سادگی و با کد بالا می توانید این کار را انجام دهید و حافظه و منابع سرور را هدر ندهید.
استفاده ی اشتباه دیگری که از تابع ()rowCount
می شود این است که برخی برنامه نویسان مبتدی از آن برای شمردن ردیف های پایگاه داده استفاده می کنند!!
هیچ گاه از چنین روشی استفاده نکنید چرا که تنها نتیجه ی آن هدر دادن منابع سرور است.
برای چنین کاری شما باید از پایگاه داده بخواهید ردیف ها را برای شما بشمارد و مقدار را در یک ردیف تحویل بدهد:
$count = $pdo->query("SELECT count(1) FROM t")->fetchColumn();
این تنها راه صحیح برای چنین موقعیتی است.
به طور خلاصه:
(*)SELECT COUNT
استفاده کنید.()rowCount
استفاده کرده و یا تابع ()count
را روی آرایه ی برگشت داده شده از ()fetchAll
اجرا کنید.بر اساس چیزی که گفته شد می فهمیم این جواب در stackoverflow نامناسب و بی معنی است. دستور ()rowCount
هیچ گاه جایگزین کوئری (*)SELECT COUNT
نمی شود چرا که هدف این دو کاملا متفاوت است.
صدا زدن یک کوئری برای دریافت تعداد ردیف های برگشتی از یک کوئری دیگر کاری بسیار عجیب و صد البته اشتباه است. به این ترتیب کوئری های خود را دو برابر کرده ایم!
PDO برای دریافت تعداد ردیف های تاثیر گرفته1 از دستور SELECT و همچنین تعداد ردیف های تاثیر گرفته از کوئری های DML (کوئری های INSERT و UPDATE و DELETE) از یک تابع استفاده میکند.
()PDOstatement::rowCount
بنابراین برای دریافت تعداد ردیف های تاثیر گرفته، پس از اجرای کوئری این تابع را صدا بزنید.
1- منظور ما از ردیف های تاثیر گرفته (affected) ردیف هایی است که به خاطر استفاده از یک دستور یا کوئری خاص تحت تاثیر قرار گرفته اند. این تاثیر می تواند به شکل های مختلفی (مثل آپدیت شدن و تغییر کردن و ...) باشد.
مسئله ی دیگر این است که اگر مقدار جدید با مقدار قبلی در جدول یکی باشد، mysql دیگر آن ردیف را آپدیت نمی کند؛ بنابراین ممکن است تعداد ردیف های تاثیر گرفته با تعداد ردیف هایی که با کوئری WHERE منطبق هستند (match می شوند) فرق داشته باشد. گرچه می توان به دستور ()rowCount اعلام کرد که به جای تعداد ردیف های تاثیر گرفته، تعداد ردیف هایی که با کوئری منطبق هستند را برگرداند (با استفاده از PDO::MYSQL_ATTR_FOUND_ROWS
) اما متاسفانه این دستور connection-only (مخصوص اتصال) است؛ یعنی تنها هنگام ساخت کانکشن تعیین می شود و در هنگام اجرای دستورات مختلف نیز تغییر نمی کند.
بنابراین باید یک حالت را از ابتدا انتخاب کرده و تا انتها با همان پیش بروید.
نکته ی مهم: متاسفانه دستور PDO::MYSQL_ATTR_FOUND_ROWS
همیشه کار نمی کند و مسئله ی عجیب تر این است که اگر کار نکند، به شما هیچ اخطاری نیز نمی دهد! تنها راهی که می توانید از طریق آن بفهمید این دستور کار می کند یا خیر استفاده از (pdo->getAttribute(PDO::MYSQL_ATTR_FOUND_ROWS$
است.
متاسفانه در PDO تابعی معادل با mysql(i)_info وجود ندارد که یکی از محدود معایب آن است.
همچنین برای دریافت ID مربوط به آخرین ردیف INSERT شده می توانید از دستور PDO::lastInsertId استفاده کنید.
در این مقاله با مباحث پیرامون ردیف ها (مانند تعداد ردیف های تاثیر گرفته، تعداد کل ردیف های برگردانده شده و...) آشنا شدیم. امیدوارم از این قسمت لذت برده باشید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.