پرس و جوهای فرعی تودرتو و مرتبط در SQL، محمول وجود دارد. استفاده از عملگر EXISTS با استفاده از تابع exists Queries

جایی که وجود دارد

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

استعلام فرعی

بر اساس پرس و جوی فرعی کاملاً تشکیل شده، مجموعه داده های حاصل بازیابی می شود.

قوانین عمومی

عملگر EXISTS وجود یک یا چند ردیف را در یک پرس و جو فرعی از یک کوئری والد آزمایش می کند.

SELECT * FROM jobs WHERE NOT EXISTS (انتخاب * از کارمند WHERE jobs.job_id=employye.job_id);

این مثال با استفاده از کلیدواژه NOT اضافی، در زیرپرسش های رکوردها بررسی می شود. مثال زیر برای بازیابی مجموعه نتایج اصلی، رکوردهای خاصی را در یک پرسش فرعی جستجو می کند.

SELECT au_lname از نویسندگان WHERE EXISTS (انتخاب * از ناشران WHERE authors.city=publishers.city);

این پرسش نام خانوادگی نویسندگان (au_lname) را که در همان شهر ناشران زندگی می کنند، برمی گرداند. توجه داشته باشید که می توانید از یک ستاره در پرس و جوی فرعی استفاده کنید زیرا پرس و جو باید فقط یک رکورد با مقدار بولی TRUE برگرداند. در چنین مواردی، ستون ها اهمیتی ندارند. نکته کلیدی وجود رشته است.

در بسیاری از کوئری ها، عملگر EXISTS همان عملکرد ANY را انجام می دهد. عملگر EXISTS معمولاً وقتی با پرس و جوهای همبسته استفاده می شود کارآمدتر است.

عملگر EXISTS از نظر معنایی معادل عملگر ANY است.

یک پرسش فرعی در عبارت EXISTS معمولاً یکی از دو نوع جستجو را انجام می دهد. اولین گزینه استفاده از علامت عام - یک ستاره (به عنوان مثال، SELECT * FROM...) است، در این صورت شما هیچ ستون یا مقدار خاصی را بازیابی نمی کنید. ستاره در اینجا به معنای "هر ستون" است. گزینه دوم این است که فقط یک ستون خاص را در زیرپرس و جو انتخاب کنید (مثلاً SELECT aujd FROM). برخی از پلتفرم‌های مجزا درخواست‌های فرعی را در چندین ستون اجازه می‌دهند (مانند SELECT aujd، aujname FROM...). با این حال، این ویژگی نادر است و باید در کدهایی که باید به پلتفرم های دیگر منتقل شوند، اجتناب شود.

تفاوت بین پلتفرم ها

همه پلتفرم ها از عملگر EXISTS به شکلی که در بالا توضیح دادیم پشتیبانی می کنند.

"قبلا راحت تر بود" - وقتی نشستم برای بهینه سازی پرس و جو بعدی در SQL فکر کردم استودیوی مدیریت. وقتی زیر MySQL نوشتم، همه چیز واقعا ساده تر بود - یا کار می کند یا نمی کند. یا سرعتش کم میشه یا نه. توضیح همه مشکلات من حل شد، چیزی بیشتر لازم نبود. اکنون من یک محیط قدرتمند برای توسعه، اشکال زدایی و بهینه سازی پرس و جوها و رویه ها/توابع دارم، و این همه درهم و برهمی از نظر من فقط مشکلات بیشتری ایجاد می کند. و چرا همه؟ زیرا بهینه ساز پرس و جو داخلی بد است. اگر در MySQL و PostgreSQL بنویسم

* را از a، b، c که در آن a.id = b.id، b.id = c.id انتخاب کنید

و هر یک از تبلت ها حداقل 5 هزار خط خواهد داشت - همه چیز منجمد می شود. و خدا را شکر! چون در غیر این صورت توسعه دهنده در بهترین حالت تنبلی برای درست نوشتن پیدا می کند و در بدترین حالت اصلا نمی فهمد دارد چه می کند! پس از همه، همان پرس و جو در MSSQL به طور مشابه کار خواهد کرد

* را از یک join b در a.id = b.id join c در b.id = c.id انتخاب کنید

بهینه ساز داخلی درخواست اضافی را برطرف می کند و همه چیز درست می شود.

او همچنین تصمیم خواهد گرفت که چه کاری بهتر است انجام دهد - وجود داشته باشد یا بپیوندد و خیلی بیشتر. و همه چیز تا حد امکان بهینه کار خواهد کرد.

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

بنابراین در اینجا به نقطه مقاله است. وجود دارد و در عملیات های بسیار سنگین هستند. این در واقع یک سوال فرعی جداگانه است برای هرخطوط نتیجه و اگر تودرتو نیز وجود داشته باشد، به طور کلی چراغ ها را خاموش می کند. وقتی 1، 10، 50 خط برگردانده شود، همه چیز درست می شود. شما تفاوت را احساس نخواهید کرد و شاید پیوستن کندتر باشد. اما وقتی 500 بیرون کشیده می شود، مشکلات شروع می شود. 500 سوال فرعی در یک درخواست جدی است.

اگرچه از نظر درک انسانی، in و وجود بهتر است، اما از نظر هزینه زمانی برای پرس و جوهایی که 50+ ردیف را برمی گرداند، قابل قبول نیستند.

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

مثال هایی از قیاس های کامل می زنم. به طور کلی، من هنوز با پرس و جوهایی با چنین درجه ای از پیچیدگی مواجه نشده ام که نتوان آنها را به یک آبشار از اتصالات گسترش داد. ممکن است یک روز طول بکشد، اما همه چیز را می توان فاش کرد.

* را از a که در آن a.id در انتخاب کنید (شناسه را از b انتخاب کنید) * را از a که وجود دارد انتخاب کنید (بالای 1 1 را از b که در آن b.id = a.id انتخاب کنید) * را از یک عضویت b در a.id = b انتخاب کنید. id را انتخاب کنید * از a که در آن a.id نیست (شناسه را از b انتخاب کنید) * را از a که وجود ندارد انتخاب کنید (بالای 1 1 را از b که در آن b.id = a.id انتخاب کنید) * را از یک پیوست سمت چپ b روی a انتخاب کنید. id = b.id که در آن b.id پوچ است

تکرار می کنم - بهینه ساز MSSQL این نمونه ها را برای آنها بهینه می کند حداکثر عملکردو هرگز افراد احمقی با چنین درخواست های ساده ای وجود نخواهند داشت.

بیایید اکنون نمونه ای از یک پرس و جو واقعی را در نظر بگیریم که باید بازنویسی می شد زیرا به سادگی روی برخی از نمونه ها ثابت شد (ساختار بسیار ساده شده است و مفاهیم جایگزین شده اند، نیازی به ترس از عدم بهینه بودن ساختار پایگاه داده وجود ندارد. ).

شما باید تمام «محصولات» تکراری را در حساب‌های مختلف بیرون بکشید، با تمرکز بر پارامترهای محصول، گروه آن، و گروه مادر، در صورت وجود.

d.PRODUCT_ID را از PRODUCT s انتخاب کنید، PRODUCT_GROUP sg سمت چپ پیوستن به M_PG_DEPENDENCY sd در (sg.PRODUCT_GROUP_ID = sd.M_PG_DEPENDENCY_CHILD_ID)، PRODUCT d، PRODUCT_GROUP در M_PG_DEPENDENCY dg باقی مانده است. UP_ID = روز .M_PG_DEPENDENCY_CHILD_ID) که در آن s.PRODUCT_GROUP_ID=sg .PRODUCT_GROUP_ID و d.PRODUCT_GROUP_ID=dg.PRODUCT_GROUP_ID و sg.PRODUCT_GROUP_PERSPEC=dg.PRODUCT_GROUP_PERSPEC و sg.PRODUCT_GROUP_NAME.NAME.NAME.NAME=dg.PROUPRODUCT.NAME=dg.PROUPRODUCT. .PRODUCT_TYPE=d.PRODUCT_TYPE و s.PRODUCT_IS_SECURE=d.PRODUCT_IS_SECURE و s.PRODUCT_MULTISELECT=d.PRODUCT_MULTISELECT و dg.PRODUCT_GROUP_IS_TMPL=0 و ((sd.M_PG_DEPENDENCY_CHILD_ID تهی است و dd.M_PG_DEPENDENCY_CHILD_ID تهی است (DUGROUPGCT، DUGROUP1، PROUPGCT تهی است) یا dg1 که در آن sd.M_PG_DEPENDENCY_PARENT_ID = sg1.PRODUCT_GROUP_ID و dd .M_PG_DEPENDENCY_PARENT_ID = dg1.PRODUCT_GROUP_ID و sg1.PRODUCT_GROUP_PERSPEC=dg1.PRODUCT_GROUP_PERSPEC و sg1.PRODUCT_GROUP_NAME=dg1.PRODUCT_NAME و)GROUP)

بنابراین این مورد زمانی است که بهینه ساز منصرف شد. و برای هر خط یک heavy exists اجرا شد که دیتابیس را از بین برد.

d.PRODUCT_ID را از PRODUCT انتخاب کنید join PRODUCT d در s.PRODUCT_TYPE=d.PRODUCT_TYPE و s.PRODUCT_NAME=d.PRODUCT_NAME و s.PRODUCT_IS_SECURE=d.PRODUCT_IS_SECURE و s.PRODUCT_IS_SECURE و s.PRODUCT_IS_SECURE و s.TIPRODUCT_IS_SECURE و s.TIPRODUCT_IS_SECURE و s.TIPRODUCT_SELECT=d.PRODUCT_TYPE=d.PRODUCT_TYPE sg در s.PRODUCT_GROUP_ID= sg.PRODUCT_GROUP_ID به PRODUCT_GROUP dg در d.PRODUCT_GROUP_ID=dg.PRODUCT_GROUP_ID و sg.PRODUCT_GROUP_NAME=dg.PRODUCT_GROUP_NAME و sg.PRODUCT_GROUP_GROUP_GROUP_DSPROUPGROUP_GROUP_dg سمت چپ می‌پیوندید. PEND ENCY sd در sg.PRODUCT_GROUP_ID = sd.M_PG_DEPENDENCY_CHILD_ID سمت چپ پیوستن به M_PG_DEPENDENCY dd در dg. PRODUCT_GROUP_ID = د. Y_PARENT_ID و sgp.PRODUC T_GROUP_NAME = dgp.PRODUCT_GROUP_NAME و isnull(sgp.PRODUCT_GROUP_IS_TMPL، 0) = isnull( dgp. PRODUCT_GROUP_IS_TMPL، 0) که در آن (sd.M_PG_DEPENDENCY_CHILD_ID پوچ است و dd.M_PG_DEPENDENCY_CHILD_ID پوچ است) یا (sgp.PRODUCT_GROUP_NAME null نیست و dgp dgp نیست و dgp dgp نیست.

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

این یک مثال واضح از این است که چگونه اعتماد بهینه ساز MSSQL می تواند یک شوخی بی رحمانه بازی کند. به او اعتماد نکنید، تنبل نباشید، به صورت دستی بپیوندید، هر بار فکر کنید که در یک موقعیت خاص چه چیزی بهتر است - وجود دارد، در آن شرکت کنید یا بپیوندید.

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

وجود دارد (انتخاب * از TABLE_NAME ...).

این عبارت زمانی که پرس و جو یک یا چند ردیف منطبق با شرایط را پیدا می کند true را برمی گرداند و زمانی که هیچ ردیفی یافت نشد false را برمی گرداند.

برای NOT EXISTS برعکس است. اصطلاح

وجود ندارد (انتخاب * از TABLE_NAME ...)

زمانی که هیچ ردیفی در پرس و جو یافت نشد true و زمانی که حداقل یک سطر پیدا شد false را برمی گرداند.

ساده ترین پرس و جو با گزاره SQL وجود دارد

در مثال‌ها با پایگاه داده کتابخانه و جداول «کتاب در حال استفاده» (BOOKINUSE) و «کاربر» (USER) آن کار می‌کنیم. در حال حاضر، ما فقط به جدول "کتاب در حال استفاده" (BOOKINUSE) نیاز داریم.

نویسندهعنوانسال انتشاراتInv_Noشناسه کاربر
تولستویجنگ و صلح2005 28 65
چخوفباغ گیلاس2000 17 31
چخوفداستان های برگزیده2011 19 120
چخوفباغ گیلاس1991 5 65
ایلف و پتروفدوازده صندلی1985 3 31
مایاکوفسکیاشعار1983 2 120
هویج وحشیدکتر ژیواگو2006 69 120
تولستوییکشنبه2006 77 47
تولستویآنا کارنینا1989 7 205
پوشکیندختر کاپیتان2004 25 47
گوگولنمایشنامه2007 81 47
چخوفداستان های برگزیده1987 4 205
هویج وحشیموارد دلخواه2000 137 18

مثال 1.شناسه کاربرانی که کتاب های تولستوی به آنها داده شده و کتاب های چخوف نیز به آنها داده شده است را مشخص کنید. پرس و جو بیرونی داده های مربوط به کاربرانی را که کتاب های تولستوی به آنها داده شده است، انتخاب می کند، و محمول EXISTS یک شرط اضافی را مشخص می کند که در پرس و جو داخلی بررسی می شود - کاربرانی که کتاب های چخوف به آنها داده شده است. یک شرط اضافی در درخواست داخلی این است که شناسه های کاربر از درخواست های خارجی و داخلی مطابقت داشته باشند: User_ID=tols_user.user_id. درخواست به شرح زیر خواهد بود:

این کوئری نتیجه زیر را برمی گرداند:

تفاوت بین محمولات EXISTS و IN

در نگاه اول به جستارهای با گزاره EXISTS، ممکن است این تصور را داشته باشید که یکسان است. محمول IN. این اشتباه است. اگرچه آنها بسیار شبیه هستند. گزاره IN مقادیری را از محدوده مشخص شده در آرگومان خود جستجو می کند و اگر چنین مقادیری وجود داشته باشد، تمام ردیف های مربوط به این محدوده انتخاب می شوند. نتیجه گزاره EXISTS یک پاسخ "بله" یا "خیر" به این سؤال است که آیا اصلاً مقادیری مطابق با مقادیر مشخص شده در استدلال وجود دارد. علاوه بر این، قبل از گزاره IN، نام ستونی وجود دارد که برای جستجوی ردیف هایی که با مقادیر موجود در محدوده مطابقت دارند، استفاده می شود. بیایید به مثالی نگاه کنیم که تفاوت بین گزاره EXISTS و گزاره IN را نشان می دهد و مشکل با استفاده از گزاره IN حل شده است.

مثال 4.شناسه کاربرانی که توسط نویسندگانی که کتابشان برای کاربر با شناسه 31 صادر شده است را تعیین کنید. درخواست به شرح زیر خواهد بود:

شناسه کاربر
120
65
205

یک پرسش داخلی (پس از IN) نویسندگان را انتخاب می کند: چخوف; ایلف و پتروف. پرس و جو خارجی همه کاربرانی را که کتاب های آنها توسط این نویسندگان صادر شده است را انتخاب می کند. می بینیم که بر خلاف گزاره EXISTS، پیش از گزاره IN نام ستون قرار می گیرد، در این مورد - Author.

جستارهایی با محمول EXISTS و شرایط اضافی

اگر علاوه بر گزاره EXISTS در پرس و جو، حداقل یک شرط اضافی را اعمال کنید، برای مثال، با استفاده از توابع جمع، سپس چنین پرس و جوهایی می توانند برای تجزیه و تحلیل ساده داده ها استفاده شوند. بیایید این را با مثال زیر نشان دهیم.

مثال 5.شناسه کاربرانی که حداقل یک کتاب توسط پاسترناک صادر شده و بیش از 2 کتاب برای آنها صادر شده است را مشخص کنید. پرس و جوی زیر را می نویسیم که در آن شرط اول با گزاره EXISTS با پرس و جوی تودرتو مشخص می شود و شرط دوم با عملگر HAVING باید همیشه بعد از پرس و جوی تودرتو آمده باشد:

نتیجه درخواست:

شناسه کاربر
120

همانطور که از جدول BOOKINUSE پیداست، کتاب پاسترناک نیز با شناسه 18 برای کاربر صادر شده است، اما تنها یک کتاب به او داده شده است و در نمونه قرار ندارد. اگر تابع COUNT را مجدداً برای یک جستار مشابه اعمال کنید، اما این بار برای شمارش ردیف های انتخاب شده (این را خودتان تمرین کنید)، می توانید اطلاعاتی در مورد تعداد کاربرانی که کتاب های پاسترناک را می خوانند، کتاب های نویسندگان دیگر را نیز مطالعه کرده اند. این قبلاً از حوزه تجزیه و تحلیل داده ها است.

پرس و جوهایی با گزاره EXISTS در دو جدول

کوئری هایی با گزاره EXISTS می توانند داده ها را از بیش از یک جدول بازیابی کنند. بسیاری از مشکلات را می توان با استفاده از همان نتیجه حل کرد اپراتور JOIN، اما در برخی موارد استفاده از EXISTS به شما امکان می دهد یک پرس و جو کمتر دست و پا گیر ایجاد کنید. ترجیحاً استفاده از EXISTS در مواردی که جدول به دست آمده شامل ستون هایی از یک جدول باشد، ترجیح داده می شود.

در مثال زیر، از همین پایگاه داده، علاوه بر جدول BOOKINUSE، به یک جدول USER نیز نیاز خواهید داشت.

نتیجه پرس و جو جدول زیر خواهد بود:

نویسنده
چخوف
مایاکوفسکی
هویج وحشی

همانند استفاده از عملگر JOIN، در مواردی که بیش از یک جدول وجود دارد، باید از نام مستعار جدول استفاده کنید تا بررسی کنید که مقادیر کلیدهای متصل کننده جداول مطابقت داشته باشند. در مثال ما، نام مستعار جدول bk و us هستند و کلید اتصال جداول User_ID است.

در پیوندهای بیش از دو جدول گزاره وجود دارد

اکنون با جزئیات بیشتری خواهیم دید که چرا ترجیح داده می شود از EXISTS در مواردی استفاده شود که جدول حاصل تنها شامل ستون هایی از یک جدول باشد.

ما با پایگاه داده "املاک و مستغلات" کار می کنیم. جدول معامله حاوی داده هایی درباره معاملات است. برای وظایف ما، ستون Type با داده های مربوط به نوع معامله - فروش یا اجاره - در این جدول مهم خواهد بود. جدول Object حاوی داده هایی در مورد اشیا است. در این جدول، به مقادیر ستون‌های Rooms (تعداد اتاق‌ها) و LogBalc نیاز داریم که حاوی داده‌هایی در مورد وجود یک ایوان یا بالکن در قالب بولی است: 1 (بله) یا 0 (خیر). جداول Client، Manager و Owner به ترتیب حاوی داده هایی در مورد مشتریان، مدیران شرکت و مالکان هستند. در این جداول FName و LName به ترتیب نام و نام خانوادگی هستند.

مثال 7.مشتریانی را که املاکی را خریداری یا اجاره کرده اند که ایوان یا بالکن ندارند، شناسایی کنید. ما پرس و جوی زیر را می نویسیم که در آن گزاره EXISTS دسترسی به نتیجه اتصال دو جدول را مشخص می کند:

از آنجایی که ستون‌ها از جدول Client با استفاده از عملگر ستاره انتخاب می‌شوند، تمام ستون‌های این جدول نمایش داده می‌شوند که به تعداد کلاینت‌هایی که با شرط تعیین‌شده توسط محمول EXISTS مطابقت دارند، سطر دارند. ما نیازی به خروجی هیچ ستونی از جداول نداریم که توسط subquery به اتصال آنها دسترسی دارد. بنابراین، برای صرفه جویی در زمان ماشین، تنها یک ستون بازیابی می شود. برای این کار بعد از کلمه SELECT یک واحد نوشته می شود. از همین تکنیک در پرس و جوهای مثال های زیر استفاده شده است.

خودتان یک پرس و جوی SQL با گزاره EXISTS بنویسید و سپس به راه حل نگاه کنید

ما به نوشتن پرس و جوهای SQL همراه با محمول EXISTS ادامه می دهیم

مثال 9.تعیین مالکان اشیایی که اجاره داده شده است. ما پرس و جوی زیر را می نویسیم که در آن گزاره EXISTS نیز دسترسی به نتیجه پیوستن به دو جدول را مشخص می کند:

مانند مثال قبلی، تمام فیلدهای جدولی که توسط کوئری خارجی به آنها دسترسی پیدا می کند، برگردانده می شوند.

مثال 10.تعداد مالکانی که دارایی آنها توسط مدیر ساولیف اداره می شد را تعیین کنید. ما یک پرس و جو می نویسیم که در آن پرس و جو بیرونی به پیوندی از سه جدول دسترسی دارد و محمول EXISTS دسترسی به تنها یک جدول را مشخص می کند:

همه پرس و جوها با پایگاه داده موجود بررسی می شوند. استفاده موفق!

پایگاه های داده رابطه ای و زبان SQL

آکادمی دولتی اقتصاد و مدیریت نووسیبیرسک

تمرین آزمایشگاهی در مورد نظم و انضباط

"پایگاه داده"

کار آزمایشگاهی شماره 7

«زبان پایگاه ها داده های SQL: دستورات دستکاری داده ها»

NOVOSIBIRSK 2000

SQL مخفف Structured Query Language است. از نام زبان مشخص می شود که هدف اصلی آن ایجاد پرس و جو برای به دست آوردن اطلاعات از پایگاه داده است. دستورات برای بازیابی داده ها اساس زبان دستکاری داده ها DML را تشکیل می دهند - بخشی جدایی ناپذیر از زبان SQL. با این حال، DML فراتر از دستوراتی برای بازیابی داده ها از پایگاه داده است. همچنین دستوراتی برای اصلاح داده ها، مدیریت داده ها و غیره وجود دارد.

کار آزمایشگاهی ابزارهای اساسی زبان DML را بررسی می کند. در حال پیش رفت کار آزمایشگاهیما به استاندارد SQL2 پایبند خواهیم بود.

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

برای انجام کارهای آزمایشگاهی، آگاهی از مبانی مدل داده های رابطه ای، مبانی جبر رابطه ای و حساب رابطه ای و اصول کار با DBMS MS SQL Server مورد نیاز است.

در نتیجه تکمیل کار آزمایشگاهی، شما بر روش های دستکاری داده ها با استفاده از دستورات زبان SQL مسلط خواهید شد، لهجه زبان پیاده سازی شده در MS SQL Server DBMS را در نظر بگیرید.

معرفی

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

ساختار اصلی نحو SQL (یا حداقل به نظر می رسید) بر اساس حساب رابطه ای Codd بود. تنها عملیات پشتیبانی شده در جبر رابطه ای، اتحاد بود.

SQL2 علاوه بر نحو محاسباتی رابطه‌ای که در استاندارد قبلی توسعه یافته بود، مستقیماً عملیات اتحاد، تقاطع، تفاوت و پیوستن را پیاده‌سازی می‌کند. عملیات انتخاب، پروژه و محصول تقریباً مستقیماً پشتیبانی می‌شوند (و همچنان ادامه می‌یابند)، در حالی که عملیات تقسیم و واگذاری به شکل دست و پاگیرتری پشتیبانی می‌شوند.

ابتدا زبان پرس و جوی SQL و سپس عملیات ورود و اصلاح داده های آن را شرح می دهیم. عملیات اصلاح داده در آخر توضیح داده خواهد شد، زیرا ساختار آنها تا حد معینی به ساختار زبان پرس و جو متکی است.

پرس و جوهای ساده

برای ما درخواست سادهیک پرس و جو وجود خواهد داشت که تنها به یک جدول در پایگاه داده دسترسی دارد. پرس و جوهای ساده به ما کمک می کنند تا ساختار اصلی SQL را نشان دهیم.

درخواست سادهکوئری که فقط به یک جدول پایگاه داده دسترسی دارد.

درخواست:چه کسی گچ کار می کند؟

WHERE SKILL_TYPE = "گچکار"

نتیجه:

جی.ریکور

این پرس و جو سه مورد از رایج ترین ها را نشان می دهد عبارات SQL: SELECT، FROM و WHERE. اگرچه در مثال ما آنها را در خطوط مختلف قرار دادیم، اما همه آنها می توانند در یک خط ظاهر شوند. آنها همچنین می توانند به طور متفاوتی تورفتگی داشته باشند، و کلمات درون عبارات را می توان با تعداد دلخواه فاصله از هم جدا کرد. بیایید به ویژگی های هر عبارت نگاه کنیم.

انتخاب کنید. عبارت SELECT ستون هایی را که باید در جدول به دست آمده ظاهر شوند را فهرست می کند. اینها همیشه ستون های برخی از جدول های رابطه ای هستند. در مثال ما، جدول حاصل از یک ستون (NAME) تشکیل شده است، اما به طور کلی می تواند شامل چندین ستون باشد. همچنین می تواند حاوی مقادیر یا ثابت های محاسبه شده باشد. ما نمونه هایی از هر یک از این گزینه ها را بیان می کنیم. اگر جدول به دست آمده باید بیش از یک ستون داشته باشد، تمام ستون های مورد نیاز بعد از آن فهرست می شوند دستورات SELECTبا کاما از هم جدا می شوند. به عنوان مثال، عبارت SELECT WORKER_ID، NAME به جدولی متشکل از ستون های WORKER_ID و NAME منجر می شود.

بند SELECT.ستون های جدول حاصل را مشخص می کند.

از جانب. عبارت FROM یک یا چند جدول را مشخص می کند که توسط پرس و جو قابل دسترسی هستند. تمام ستون های فهرست شده در عبارت SELECT و WHERE باید در یکی از جداول فهرست شده در دستور FROM وجود داشته باشند. در SQL2، این جداول می توانند مستقیماً در طرحواره به عنوان جداول پایه یا نماهای داده تعریف شوند، یا می توانند خود جداول بی نامی باشند که از پرس و جوهای SQL حاصل می شوند. در مورد دوم، درخواست به صراحت در دستور FROM آورده شده است.

عبارت FROM.جداول موجود را مشخص می کند که توسط پرس و جو قابل دسترسی هستند.

جایی که. عبارت WHERE شامل یک شرط است. که بر اساس آن سطرهای جدول(های) انتخاب می شوند. در مثال ما، شرط این است که ستون SKILL_TYPE باید حاوی ثابت "Plasterer" محصور در آپاستروف باشد، همانطور که همیشه با ثابت های متنی در SQL انجام می شود. عبارت WHERE فرارترین دستور SQL است. ممکن است شامل شرایط مختلفی باشد. بیشتر بحث ما به نشان دادن ساختارهای مختلف مجاز در دستور WHERE اختصاص خواهد داشت.

بند WHERE.شرایطی را مشخص می کند که بر اساس آن ردیف ها از جداول مشخص شده انتخاب می شوند.

درخواست SQL فوق توسط سیستم به ترتیب زیر پردازش می شود: FROM، WHERE، SELECT. یعنی ردیف های جدول مشخص شده در دستور FROM برای پردازش در ناحیه کار قرار می گیرند. سپس عبارت WHERE به ترتیب به هر ردیف اعمال می شود. تمام ردیف هایی که شرایط WHERE را برآورده نمی کنند از بررسی حذف می شوند. سپس آن ردیف هایی که شرط WHERE را برآورده می کنند توسط دستور SELECT پردازش می شوند. در مثال ما، NAME از هر ردیف انتخاب شده است و تمام مقادیر انتخاب شده به عنوان نتایج پرس و جو خروجی می شوند.

درخواست:ارائه تمام اطلاعات در مورد ساختمان های اداری.

WHERE TYPE = "دفتر"

نتیجه:

BLDG IDADDRESSTYPEQLTY LEVELSTATUS

312 Elm St., 123 Office 2 2

210 خیابان Berezovaya. 1011 Office Z 1

خیابان اوسینوایا 111. 1213 Office 4 1

ستاره (*) در دستور SELECT به معنای "کل ردیف" است. این یک کوتاه نویسی مناسب است که ما اغلب از آن استفاده خواهیم کرد.

درخواست:حقوق هفتگی هر برقکار چقدر است؟

SELECT NAME، "حقوق هفتگی = "، 40 * HRLY_RATE

WHERE SKILL_TYPE = "برق"

نتیجه:

M. Faraday حقوق هفتگی = 500.00

H.Columbus حقوق هفتگی = 620.00

این پرس و جو استفاده از هر دو ثابت کاراکتر (در مثال ما "حقوق هفتگی = ") و محاسبات در دستور SELECT را نشان می دهد. در دستور SELECT، می توانید محاسباتی را انجام دهید که از ستون های عددی و ثابت های عددی و همچنین عملگرهای حسابی استاندارد استفاده می کنند. +، -، *، /)، در صورت لزوم با استفاده از پرانتز گروه بندی می شوند. ما همچنین یک جدید اضافه کرده ایم دستور ORDER BY، که نتیجه پرس و جو را به ترتیب الفبای عددی صعودی بر اساس ستون مشخص شده مرتب می کند. اگر می خواهید نتایج را به ترتیب نزولی مرتب کنید، باید DESC را به دستور اضافه کنید. عبارت ORDER BY می تواند نتایج را بر اساس چندین ستون مرتب کند، برخی به ترتیب صعودی و برخی دیگر به ترتیب نزولی. ستون کلید اصلی مرتب سازی ابتدا فهرست شده است.

ثابت کاراکترثابتی متشکل از حروف، اعداد و کاراکترهای "ویژه".

درخواست:چه کسی نرخ ساعتی 10 تا 12 دلار دارد؟

WHERE HRLY_RATE > = 10 و HRLY_RATE< - 12

نتیجه:

شناسه کارگر NAME HRLY_RATE SKILL_TYPE SUPV_ID

این پرس و جو برخی از ویژگی های اضافی عبارت WHERE را نشان می دهد: عملگرهای مقایسه و عملگر Boolean AND. شش عملگر مقایسه (=<>(نا برابر)،<, >, <=, >=). عملگرهای بولی AND، OR و NOT را می توان برای ایجاد شرایط مرکب یا نفی یک شرط استفاده کرد. همانطور که در زبان های برنامه نویسی رایج است، می توان از پرانتز برای گروه بندی شرایط استفاده کرد.

عملگرهای مقایسه =،<>, <, >, <=, >=.

عملیات بولی AND (AND)، OR (OR) و NOT (HE) .

همچنین می توانید از عملگر BETWEEN (بین) برای فرمول بندی این پرس و جو استفاده کنید:

جایی که HRLY_RATE بین 10 و 12 است

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

درخواست: گچ کارها، سقف ها و برقکاران را فهرست کنید.

WHERE SKILL_TYPE IN ("گچکار"، "روفور"، "برق")

نتیجه:

WORKER_ID NAME HRLY_RATE SKILL_TYPE SUPV_ID

1412 K.Nemo 13.75 Plasterer 1520

2920 R. Garrett 10.00 Roofer 2920

1520 G. Rickover 11.75 Plasterer 1520

این پرس و جو استفاده از عملگر مقایسه IN (B) را توضیح می دهد. شرط WHERE در صورتی درست در نظر گرفته می شود که نوع تخصصی ردیف در داخل مجموعه مشخص شده در پرانتز قرار گیرد، یعنی اگر نوع تخصصی گچ کاری، سقف ساز یا برق کار باشد. ما دوباره اپراتور IN را در سوالات فرعی خواهیم دید.

بیایید فرض کنیم که نمی توانیم دقیقاً املای تخصص خود را به خاطر بسپاریم: "برق" یا "مهندس الکترونیک" یا چیز دیگری. کاراکترهای عام، که جایگزین رشته‌های کاراکتر تعریف‌نشده می‌شوند، یافتن املای نادرست در یک پرس و جو را آسان‌تر می‌کنند.

نمادهای الگوکاراکترهایی که جایگزین رشته های کاراکتر تعریف نشده می شوند.

درخواست:کارمندانی را فهرست کنید که نوع تخصص آنها با "Elek" شروع می شود.

WHERE SKILL_TYPE LIKE ("انتخاب٪")

نتیجه:

WORKER ID NAME HRLY_RATE SKILL_TYPE SUPV_ID

1235 م فارادی 12.50 برق 1311

1311 اچ کلمب 15.50 الکتریک 1311

SQL دارای دو کاراکتر عام است: % (درصد) و _ (خط زیر). خط زیر دقیقاً جایگزین یک کاراکتر تعریف نشده می شود. درصد جایگزین تعداد دلخواه کاراکترها می شود که با صفر شروع می شود. هنگامی که از کاراکترهای wildcard استفاده می شود، یک عملگر LIKE برای مقایسه متغیرهای کاراکتر با ثابت ها مورد نیاز است. نمونه های دیگر:

NAME LIKE "__Columbus"

NAME LIKE "__K%"

شرط در مثال اول درست است اگر NAME از دو نویسه و به دنبال آن "Columbus" تشکیل شده باشد. در جدول WORKER، همه نام ها با حرف اول و نقطه شروع می شوند. بنابراین با استفاده از این شرط ما. بیایید همه کارمندان با نام خانوادگی "کلمب" را پیدا کنیم. شرط مثال دوم به ما امکان می دهد همه کارمندانی که نام خانوادگی آنها با حرف "K" شروع می شود را پیدا کنیم.

درخواست:تمام مشاغلی را که ظرف دو هفته آینده شروع می شوند، پیدا کنید.

WHERE START_DATE بین CURRENT_DATE و

نتیجه:(فرض کنید که تاریخ فعلی CURRENT DATE = 10.10 باشد)

WORKER_ID BLDG_ID START_DATE NUM_DAYS

1235 312 10.10 5

1235 515 17.10 22

3231 111 10.10 8

1412 435 15.10 15

3231 312 24.10 20

1311 460 23.10 24

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

CURRENT_DATE + INTERVAL "14" روز

یک دوره دو هفته ای را به تاریخ فعلی اضافه می کند. بنابراین، اگر مقدار ستون START_DATE آن بین 10/10 و 10/24 باشد، ASSIGNMENT انتخاب می‌شود (با فرض اینکه امروز 10/10 باشد). از اینجا می توانیم ببینیم که می توانیم مقادیر بازه ای را به فیلدهای تاریخ اضافه کنیم. علاوه بر این، می توانیم مقادیر بازه ها را در مقادیر صحیح ضرب کنیم. به عنوان مثال، فرض کنید می‌خواهیم بفهمیم که در چند هفته مشخص چه عددی خواهد بود (که با متغیر NUM_WEEKS مشخص می‌شود). ما می توانیم این کار را به این صورت انجام دهیم:

CURRENT_DATE + INTERVAL "7" روز * NUM_WEEKS

2. پرس و جوهای چند جدولی

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

درخواست:

داده های مورد نیاز برای پاسخ در دو جدول WORKER و ASSIGNMENT است. راه حل SQL مستلزم فهرست کردن هر دو جدول در دستور FROM و مشخص کردن نوع خاصی از عبارت WHERE است:

SKILL_TYPE را انتخاب کنید

از طرف کارگر، تکلیف

WHERE WORKER.WORKER_ID = ASSIGNMENT.WORKER_ID

و BLDG_ID = 435

اینجا چه خبره؟ ما باید دو مرحله را در نحوه پردازش این درخواست در نظر بگیریم.

1. طبق معمول، ابتدا عبارت FROM پردازش می شود. اما در این حالت چون دستور دو جدول را مشخص می کند، سیستم یک حاصل ضرب دکارتی از ردیف های این جداول ایجاد می کند. این بدان معناست که یک جدول بزرگ (به طور منطقی) ایجاد می شود که از ستون هایی از هر دو جدول تشکیل شده است و هر ردیف از یک جدول با هر ردیف از جدول دیگر جفت می شود. در مثال ما، چون جدول WORKER دارای پنج ستون و جدول ASSIGNMENT دارای چهار ستون است، محصول دکارتی که با دستور FROM تولید می‌شود دارای 9 ستون خواهد بود. تعداد کل ردیف های حاصلضرب دکارتی برابر با m * n است که m تعداد ردیف های جدول WORKER است. و n تعداد سطرهای جدول ASIGNMENT است. از آنجایی که جدول WORKER دارای 7 ردیف و جدول ASSIGNMENT دارای 19 ردیف است، محصول دکارتی شامل 7x19 یا 133 ردیف خواهد بود. اگر دستور FROM بیش از دو جدول را لیست کند، یک محصول دکارتی از تمام جداول مشخص شده در دستور ایجاد می شود.

ضرب دکارتی. نتیجه پیوستن هر ردیف از یک جدول با هر یکیک ردیف از جدول دیگر

2. پس از ایجاد جدول رابطه ای غول پیکر، سیستم مانند قبل از دستور WHERE استفاده می کند. هر ردیف از جدول با دستور FROM ایجاد می شود. بررسی می شود تا ببیند آیا شرط WHERE برآورده می شود. ردیف هایی که شرایط را برآورده نمی کنند از بررسی مستثنی هستند. سپس عبارت SELECT بر روی سطرهای باقی مانده اعمال می شود.

عبارت WHERE در پرس و جو ما شامل دو شرط است:

1. کارگر. WORKER_ID = ASSIGNMENT.WORKER_ID

2. BLDG_ID = 435

اولین مورد از این شرایط شرط الحاق است. توجه داشته باشید که از آنجایی که هر دو جدول WORKER و ASSIGNMENT دارای ستونی به نام WORKER_ID هستند، محصول دکارتی آنها شامل دو ستون با این نام خواهد بود. برای تمایز بین آنها، نام ستون را با نام جدول منبع، که با یک نقطه از هم جدا شده است، قرار می دهیم.

شرط اول به این معنی است که در هر ردیف انتخاب شده، مقدار ستون WORKER_ID از جدول WORKER باید با مقدار ستون WORKER_ID از جدول ASSIGNMENT مطابقت داشته باشد. در واقع، ما دو جدول را توسط WORKER_ID به هم می‌پیوندیم. تمام سطرهایی که مقادیر این دو ستون در آنها برابر نیست از جدول محصول حذف می شوند. دقیقاً همین اتفاق در هنگام اجرای عملیات اتصال طبیعی جبر رابطه‌ای می‌افتد. (با این حال، هنوز تفاوتی با اتصال طبیعی وجود دارد: SQL به طور خودکار ستون WORKER_ID اضافی را حذف نمی کند). پیوستن کامل این دو جدول با شرط اضافی BLDG_ID = 435 در شکل نشان داده شده است. 1. استفاده از دستور SELECT در نهایت نتیجه پرس و جو زیر را به همراه خواهد داشت:

نوع مهارت

گچ کار

روفر

تکنسین برق

برنج. 1. پیوستن به جداول WORKER و ASSIGNMENT

اکنون نحوه پیوستن یک جدول به خود را در SQL نشان خواهیم داد.

درخواست:کارمندان را با ذکر نام مدیران آنها فهرست کنید.

A.WORKER_NAME، B.WORKER_NAME را انتخاب کنید

از کارگر A، کارگر B

WHERE B.WORKER_ID = A.SUPV_ID

عبارت FROM در این مثال دو "کپی" از جدول WORKER ایجاد می کند و نام مستعار A و B را به آنها می دهد. نام مستعار یک نام جایگزین است که به جدول داده می شود. سپس کپی های A و B جدول WORKER با دستور WHERE بر اساس شرط برابری WORKER_ID در B و SUPV_ID در A به یکدیگر متصل می شوند. بنابراین، هر سطر از A به ردیف B که حاوی اطلاعات مدیر ردیف A است متصل می شود. (شکل 2).

برنج. 2. پیوستن دو نسخه از جدول WORKER

با انتخاب دو نام کارمند از هر خط، لیست مورد نیاز را دریافت می کنیم:

A.NAMEB.NAME

M. Faraday H. Columbus

K.Nemo G.Rickover R.Gartet R.Garett

پی. میسون پی. میسون جی. ریکاور جی. ریکاور اچ.

نام مستعار.نام جایگزین داده شده به جدول.

A.WORKER_NAME نماینده کارگر و B.WORKER_NAME نماینده مدیر است. لطفاً توجه داشته باشید که برخی از کارگران مدیران خودشان هستند که از برابری WORKER_ID - SUPV_ID در خطوط آنها ناشی می شود.

در SQL، می‌توانید همزمان بیش از دو جدول را پیوند دهید:

درخواست

WORKER_NAME را انتخاب کنید

از کارگر، تکلیف، ساختمان

WHERE WORKER.WORKER_ID = ASSIGNMENT.WORKER_ID AND ASSIGNMENT.BLDG_ID = BUILDING.BLDG_ID و

TYPE = "دفتر"

نتیجه:

ام. فارادی

جی.ریکور

J. Barrister

توجه داشته باشید که اگر نام ستونی (مانند WORKER_ID یا BLDG_ID) در بیش از یک جدول ظاهر شود، برای جلوگیری از ابهام باید نام ستون را با نام جدول اصلی اضافه کنیم. اما اگر نام ستون فقط در یک جدول باشد، مانند TYPE در مثال ما، هیچ ابهامی وجود ندارد، بنابراین نیازی به تعیین نام جدول نیست.

دستورات SQL در این پرس و جو یک جدول از سه جدول پایگاه داده رابطه ای ایجاد می کند. دو جدول اول توسط WORKER_ID و پس از آن جدول سوم توسط BLDG_ID به جدول حاصل متصل می شود. وضعیت

TYPE = "دفتر"

بند WHERE باعث می شود که همه ردیف ها به جز ردیف های ساختمان های اداری حذف شوند. این الزامات درخواست را برآورده می کند.

3. سوالات فرعی

استعلام فرعی.پرس و جو در یک پرس و جو

یک پرس و جو فرعی را می توان در بند WHERE یک پرس و جو قرار داد، در نتیجه قابلیت های عبارت WHERE را گسترش داد. بیایید به یک مثال نگاه کنیم.

درخواست:کارگران منصوب به ساختمان 435 چه تخصص هایی دارند؟

SKTLL_TYPE را انتخاب کنید

FROM WORKER WHERE WORKER_ID IN

(WORKER_ID را انتخاب کنید

WHERE BLDG_ID = 435)

استعلام فرعی در این مثال

(WORKER_ID را انتخاب کنید

WHERE BLDG_ID = 435)

پرس و جوی که حاوی یک پرسش فرعی است نامیده می شود درخواست خارجییا درخواست اصلی. پرس و جو فرعی منجر به ایجاد مجموعه ای از شناسه های کارمند زیر می شود:

شناسه کارگر

درخواست خارجیپرس و جو اصلی، که شامل تمام سوالات فرعی است.

سپس این مجموعه از شناسه ها جای یک پرسش فرعی را در کوئری بیرونی می گیرد. از این مرحله به بعد، پرس و جو بیرونی با استفاده از مجموعه ایجاد شده توسط پرس و جو اجرا می شود. کوئری بیرونی هر ردیف از جدول WORKER را طبق عبارت WHERE پردازش می کند. اگر WORKER_ID یک ردیف در مجموعه (IN) ایجاد شده توسط پرس و جوی فرعی قرار داشته باشد، SKILL_TYPE ردیف انتخاب شده و در جدول حاصل نمایش داده می شود:

نوع مهارت

گچ کار

روفر

تکنسین برق

بسیار مهم است که عبارت SELECT مربوط به درخواست فرعی حاوی WORKER_ID و فقط WORKER_ID باشد. در غیر این صورت، عبارت WHERE کوئری بیرونی، به این معنی که WORKER_ID در مجموعه شناسه های کارگر قرار دارد، معنایی نخواهد داشت.

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

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

در اینجا نمونه ای از یک زیرپرسوجو در یک زیرپرسوجو آورده شده است.

درخواست: لیست کارکنان منصوب در ساختمان های اداری.

دوباره به کوئری که با آن ارتباط را بررسی کردیم نگاه می کنیم.

WORKER_MAME را انتخاب کنید

WHERE WORKER_ID در

(WORKER_ID را انتخاب کنید

WHERE BLDG_ID IN

WHERE TYPE = "دفتر"))

نتیجه:

ام. فارادی

جی.ریکور

J. Barrister

توجه داشته باشید که ما نیازی به پیشوند نام ستون ها با نام جدول در هیچ کجا نداریم، زیرا هر زیرپرسوجویی یک و تنها یک جدول را پردازش می کند، بنابراین هیچ ابهامی ایجاد نمی شود.

اجرای پرس و جو به ترتیب داخل به بیرون انجام می شود. یعنی ابتدا درونی ترین پرس و جو (یا «پایین ترین») اجرا می شود، سپس پرس و جو فرعی حاوی آن و سپس کوئری بیرونی اجرا می شود.

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

پرسش فرعی مرتبط. یک پرسش فرعی که نتیجه آن به ردیف در نظر گرفته شده توسط پرس و جو اصلی بستگی دارد.

درخواست:کارمندانی را فهرست کنید که نرخ ساعتی آنها از مدیرانشان بیشتر است.

WORKER_NAME را انتخاب کنید

WHERE A.HRLY_RATE >

(انتخاب B.HRLY_RATE

WHERE B.WORKER_ID = A.SUPV_ID)

نتیجه:

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

1. سیستم دو نسخه از جدول WORKER ایجاد می کند: کپی A و کپی B. طبق روشی که ما آنها را تعریف کردیم، A به کارمند، B به مدیر اشاره دارد.

2. سپس سیستم هر سطر A را در نظر می گیرد. یک ردیف معین در صورتی انتخاب می شود که شرط WHERE را برآورده کند. این شرط به این معنی است که اگر مقدار HRLY_RATE آن بیشتر از HRLY_RATE باشد، یک ردیف انتخاب می‌شود.

3. پرس و جوی فرعی مقدار HRLY_RATE را از ردیف B انتخاب می کند که WORKER_ID آن برابر با SUPV_ID ردیف A است، در این لحظهتوسط درخواست اصلی در نظر گرفته شده است. این HRLY_RATE مدیر است.

توجه داشته باشید که از آنجایی که A.HRLY_RATE فقط با یک مقدار قابل مقایسه است، درخواست فرعی باید فقط یک مقدار را برگرداند. این مقدار بسته به اینکه کدام ردیف A در نظر گرفته می شود تغییر می کند. بنابراین، پرس و جو فرعی با پرس و جو اصلی همبستگی دارد. بعداً وقتی توابع داخلی را مطالعه می کنیم، نمونه های بیشتری از سؤالات فرعی مرتبط را خواهیم دید.

عملگرهای EXISTS و NOT EXISTS

فرض کنید می خواهیم کارگرانی را شناسایی کنیم که در یک ساختمان خاص کار نمی کنند. در ظاهر، به نظر می رسد که چنین درخواستی را می توان به سادگی با نفی نسخه مثبت درخواست به راحتی برآورده کرد. به عنوان مثال، فرض کنید که ما به ساختمانی با BLDG_ID 435 علاقه مند هستیم. این درخواست را در نظر بگیرید:

WORKER_ID را انتخاب کنید

WHERE BLDG_ID 435 نیست

متأسفانه، این یک فرمول نادرست از محلول است. این درخواست به سادگی شناسنامه کارگران شاغل در ساختمان های دیگر را به ما می دهد. بدیهی است برخی از آنها را می توان به ساختمان 435 نیز اختصاص داد.

یک راه حل درست فرموله شده از عملگر NOT EXISTS استفاده می کند:

WORKER_ID را انتخاب کنید

جایی که وجود ندارد

WHERE ASSIGNMENT.WORKER_ID = WORKER.WORKER_ID و

نتیجه:

WORKER_ID

عملگرهای EXISTS و NOT EXISTS همیشه قبل از subquery قرار می گیرند. EXISTS در صورتی که مجموعه تولید شده توسط پرس و جو خالی نباشد، به درستی ارزیابی می شود. اگر مجموعه تولید شده توسط پرس و جو خالی باشد، EXISTS مقدار "false" را می گیرد. البته عملگر NOT EXISTS دقیقا برعکس عمل می کند. اگر نتیجه پرس و جو خالی باشد درست است و در غیر این صورت نادرست است.

اپراتور وجود دارد. اگر مجموعه نتایج خالی نباشد، true را برمی‌گرداند.

اپراتور وجود ندارد. اگر مجموعه نتایج خالی باشد، مقدار true را برمی‌گرداند.

در این مثال از عملگر NOT EXISTS استفاده کردیم. پرسش فرعی تمام ردیف‌های جدول ASSIGNMENT را انتخاب می‌کند که در آن‌ها WORKER_ID همان مقدار سطر در نظر گرفته شده توسط پرس و جو اصلی است و BLDG_ID برابر با 435 است. اگر این مجموعه خالی باشد، ردیف کارگر در نظر گرفته شده توسط پرس و جو اصلی انتخاب شده است، زیرا این بدان معناست که این کارمند در ساختمان 435 کار نمی کند.

در راه حلی که ارائه کردیم، از یک زیرپرس و جوی همبسته استفاده کردیم. اگر به جای NOT EXISTS از عملگر IN استفاده کنیم، می‌توانیم با یک زیرپرسی ناهمبسته به نتیجه برسیم:

WORKER_ID را انتخاب کنید

WHERE WORKER_ID داخل نیست

(WORKER_ID را انتخاب کنید

WHERE BLDG_ID = 435)

این راه حل ساده تر از راه حل با عملگر NOT EXISTS است. یک سوال طبیعی مطرح می شود: چرا ما به وجود و اصلاً وجود ندارد؟ پاسخ این است که NOT EXISTS تنها راه حل پرس و جوهایی است که حاوی کلمه "همه" در شرایط هستند. چنین پرس و جوهایی در جبر رابطه ای با استفاده از عملیات تقسیم و در محاسبات رابطه ای با استفاده از کمیت ساز جهانی حل می شوند. در اینجا نمونه ای از یک پرس و جو با کلمه "every" در شرایط خود آورده شده است:

درخواست:کارکنانی را که به هر ساختمان اختصاص داده اند فهرست کنید.

این سوال را می توان در SQL با استفاده از نفی دوگانه پیاده سازی کرد. ما پرس و جو را طوری فرمول بندی می کنیم که یک منفی دوگانه داشته باشد:

درخواست:چنین کارمندانی را برای چه کسانی فهرست کنید نهساختمانی وجود دارد که آنها به آن اختصاص ندارند.

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

حال می خواهیم راه حل را در SQL فرموله کنیم. برای سهولت درک راه حل نهایی، ابتدا یک راه حل برای یک مشکل اولیه ارائه می دهیم: مشکل شناسایی تمام ساختمان هایی که یک کارگر فرضی برای آنها، "1234" نهمنصوب.

(I) BLDG_ID را انتخاب کنید

جایی که وجود ندارد

ASSIGNMENT.WORKER_ID = 1234)

ما این پرس و جو را علامت گذاری کرده ایم (I) زیرا بعداً به آن اشاره خواهیم کرد. اگر ساختمانی وجود نداشته باشد که این درخواست را برآورده کند، کارگر 1234 به هر ساختمان اختصاص داده می شود و بنابراین شرایط درخواست اولیه را برآورده می کند. برای به دست آوردن یک راه حل برای پرس و جو اصلی، باید پرس و جو (I) را از یک کارگر خاص 1234 به متغیر WORKER_ID تعمیم دهیم و این پرس و جو اصلاح شده را به یک پرس و جوی فرعی از کوئری بزرگتر تبدیل کنیم. راه حل اینجاست:

(II) WORKER_ID را انتخاب کنید

جایی که وجود ندارد

جایی که وجود ندارد

WHERE ASSIGNMENT.BLDG_ID = BUILDING.BLDG_ID و

ASSIGNMENT.WORKER_ID = WORKER.WORKER_ID)

نتیجه:

شناسه کارگر

توجه داشته باشید که پرس و جوی فرعی که از خط چهارم پرس و جو شروع می شود با پرس و جو (I) یکسان است و "1234" با WORKER.WORKER_ID جایگزین شده است. پرس و جو (II) را می توان به صورت زیر خواند:

اگر ساختمانی وجود ندارد که WORKER_ID به آن اختصاص داده نشده است، WORKER_ID را از WORKER انتخاب کنید.

این با شرایط درخواست اصلی مطابقت دارد.

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

توابع داخلی

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

حداکثر و حداقل نرخ ساعتی چقدر است؟ میانگین روزهای کار کارکنان در ساختمان 435 چقدر است؟ مجموع روزهای اختصاص یافته برای گچ کاری ساختمان 312 چقدر است؟ چند تخصص مختلف وجود دارد؟

پاسخ به این سؤالات مستلزم توابع آماری است که به سطرهای زیادی در یک جدول نگاه می کند و یک مقدار واحد را برمی گرداند. پنج تابع از این قبیل در SQL وجود دارد که به آنها توابع داخلی یا توابع تنظیم می گویند. این توابع عبارتند از SUM (جمع)، AVG (متوسط)، COUNT (مقدار)، MAX (حداکثر) و MIN (حداقل).

عملکرد داخلی (عملکرد مجموعه). یک تابع آماری که روی چندین ردیف عمل می کند: SUM (جمع)، AVG (متوسط)، COUNT (مقدار)، MAX (حداکثر)، MIN (حداقل).

درخواست:حداکثر و حداقل نرخ ساعتی چقدر است؟

SELECT MAX (HRLY_RATE)، MIN (HRLY_RATE)

نتیجه: 17.40, 8.20

توابع MAXو MIN روی یک ستون جدول عمل می کنند. آنها به ترتیب مقدار حداکثر یا حداقل را از این ستون انتخاب می کنند. فرمول پرس و جو ما حاوی بند WHERE نیست. همانطور که مثال بعدی ما نشان می دهد، ممکن است برای اکثر پرس و جوها اینطور نباشد.

درخواست:میانگین روزهای کار کارکنان در ساختمان 435 چقدر است؟

انتخاب AVG (NUM_DAYS)

WHERE BLDG_ID = 435

نتیجه: 12.33

درخواست:مجموع روزهای اختصاص یافته برای گچ کاری ساختمان 312 چقدر است؟

SELECT SUM (NUM_DAYS)

از تکلیف، کارگر

WHERE WORKER.WORKER_ID = ASSIGNMENT.WORKER_ID و

SKILL_TYPE = "گچکار" و

نتیجه: 27

راه حل از اتصال بین جداول ASSIGNMENT و WORKER استفاده می کند. این ضروری است زیرا SKILL_TYPE در جدول WORKER و BLDG_ID در جدول ASSIGNMENT است.

درخواست:چند تخصص مختلف وجود دارد؟

COUNT را انتخاب کنید (مشخصات SKILL_TYPE)

نتیجه: 4

از آنجایی که یک تخصص می‌تواند در چندین ردیف مختلف ظاهر شود، باید از کلمه کلیدی DISTINCT در این پرس‌وجو استفاده کنید تا سیستم از شمارش یک نوع تخصص مشابه بیش از یک بار جلوگیری کند. عملگر DISTINCT را می توان با هر یک از توابع داخلی استفاده کرد، اگرچه البته با توابع MAX و MIN اضافی است.

متمایز. عملگر که خطوط تکراری را حذف می کند.

توابع SUM و AVG فقط باید با ستون های عددی استفاده شوند. توابع دیگر را می توان با داده های عددی و کاراکتری استفاده کرد. همه توابع به جز COUNT را می توان با عبارات محاسبه شده استفاده کرد. مثلا:

درخواست:میانگین حقوق هفتگی چقدر است؟

SELECT AVG (40 * HRLY_RATE)

نتیجه: 509.14

COUNT می تواند به یک ردیف به جای یک ستون جداگانه اشاره کند :

درخواست: چند ساختمان دارای سطح کیفی 3 هستند؟

انتخاب تعداد (*)

از ساختمان که در آن

نتیجه: 3

همانطور که همه این مثال ها نشان می دهند، اگر یک دستور SELECT دارای یک تابع داخلی باشد، هیچ چیز دیگری نمی تواند در آن دستور SELECT ظاهر شود. تنها استثنای این قاعده عبارت GROUP BY است که اکنون به بررسی آن خواهیم پرداخت.

GROUP BY و HAVING بند

در مدیریت، اطلاعات آماری در مورد هر گروه در بسیاری از گروه ها اغلب مورد نیاز است. به عنوان مثال، پرس و جو زیر را در نظر بگیرید:

درخواست:برای هر مدیر، حداکثر نرخ ساعتی را در میان زیردستان خود بیابید.

برای حل این مشکل باید کارگران را بر اساس مدیرانشان به گروه هایی تقسیم کنیم. سپس حداکثر قیمت پیشنهادی را در هر گروه تعیین خواهیم کرد. در SQL این کار به این صورت انجام می شود:

گروه بر اساس SUPV_ID

نتیجه:

SUPV_IDMAX (نرخ HRLY)

هنگام پردازش این پرس و جو، سیستم ابتدا ردیف های جدول WORKER را با استفاده از قانون زیر به گروه هایی تقسیم می کند. سطرها در یک گروه قرار می گیرند اگر و فقط در صورتی که SUPV_ID یکسان داشته باشند. سپس عبارت SELECT برای هر گروه اعمال می شود. از آنجایی که تنها یک مقدار SUPV_ID در این گروه وجود دارد، هیچ گونه عدم قطعیت SUPV_ID در گروه وجود ندارد. برای هر گروه، عبارت SELECT SUPV_ID را خروجی می دهد و همچنین مقدار MAX(HRLY_RATE) را محاسبه و خروجی می کند. نتیجه در بالا ارائه شده است.

در یک دستور SELECT با توابع داخلی، تنها ستون هایی که در بند GROUP BY گنجانده شده اند می توانند ظاهر شوند. توجه داشته باشید که SUPV_ID را می توان در دستور SELECT استفاده کرد زیرا در بند GROUP BY گنجانده شده است.

GROUP BY بند. نشان می دهد که ردیف ها باید به گروه هایی با مقادیر مشترک ستون(های) مشخص شده تقسیم شوند.

بند GROUP BY به شما امکان می دهد محاسبات پیچیده خاصی را انجام دهید. برای مثال، ممکن است بخواهیم میانگین این حداکثر پیشنهادات را دریابیم. با این حال، محاسبه با توابع داخلی محدود است به این معنا که اجازه نمی دهد توابع داخلی در داخل سایر توابع داخلی استفاده شوند. بنابراین یک عبارت مانند

AVG (MAX(HRLY_RATE))

ممنوع اجرای چنین درخواستی شامل دو مرحله خواهد بود. ابتدا باید حداکثر پیشنهادات را در جدول جدید قرار دهیم و در مرحله دوم باید میانگین آنها را محاسبه کنیم.

می توانید از عبارت WHERE با دستور GROUP BY استفاده کنید:

درخواست:برای هر نوع ساختمان پیدا کنید سطح متوسطکیفیت در بین ساختمان های وضعیت 1.

SELECT TYPE، AVG (QLTY_LEVEL)

WHERE STATUS = 1

نتیجه:

TYPEAVG (QLTY_LEVEL)

فروشگاه 1

ساختمان مسکونی 3

بند WHERE قبل از دستور GROUP BY اجرا می شود. بنابراین، هیچ گروهی نمی‌تواند شامل ردیفی باشد که وضعیتی غیر از 1 داشته باشد. ردیف‌های وضعیت 1 بر اساس مقدار TYPE گروه‌بندی می‌شوند و سپس یک عبارت SELECT برای هر گروه اعمال می‌شود.

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

همچنین می‌توانیم شرایط را برای گروه‌های ایجاد شده توسط بند GROUP BY اعمال کنیم. این کار با استفاده از عبارت HAVING انجام می شود. برای مثال، فرض کنید که ما تصمیم گرفتیم یکی از پرس و جوهای قبلی را دقیق تر کنیم:

درخواست: برای هر مدیری که بیش از یک نفر زیرمجموعه دارد، حداکثر نرخ ساعتی را در بین زیردستان خود بیابید.

ما می توانیم این شرایط را با دستور HAVING مناسب منعکس کنیم:

SELECT SUPV_ID، MAX (HRLY_RATE)

از گروه کارگر با SUPV_ID

داشتن COUNT(*) > 1

نتیجه:

SUPV_ID MAX (HRLY_RATE)

تفاوت بین جملات WHERE و HAVING در این است که WHERE برای ردیف ها اعمال می شود، در حالی که HAVING برای گروه ها اعمال می شود.

یک پرس و جو می تواند حاوی هر دو عبارت WHERE و HAVING باشد. در این حالت ابتدا عبارت WHERE اجرا می شود زیرا قبل از گروه بندی اجرا می شود. به عنوان مثال، اصلاح زیر را در پرس و جو قبلی در نظر بگیرید:

درخواست: برای هر نوع ساختمان، میانگین سطح کیفیت در بین ساختمان های وضعیت 1 را دریابید. فقط آن دسته از ساختمان ها را در نظر بگیرید که حداکثر سطح کیفی آنها از 3 بیشتر نباشد.

SELECT TYPE، AVG (QLTY_JLEVEL)

WHERE STATUS = 1

داشتن MAX (QLTY_LEVEL)<= 3

نتیجه:

TYPE AVG (QLTY_LEVEL)

فروشگاه 1

ساختمان مسکونی 3

توجه داشته باشید که با شروع از عبارت FROM، بند ها به ترتیب اجرا می شوند و سپس عبارت SELECT اعمال می شود. بنابراین، عبارت WHERE در جدول BUILDING اعمال می شود و تمام ردیف هایی که STATUS در آنها با 1 متفاوت است حذف می شوند. سطرهای باقی مانده بر اساس TYPE گروه بندی می شوند. همه سطرهایی با مقدار TYPE یکسان به یک گروه ختم می شوند. بنابراین، چندین گروه ایجاد می شود، یکی برای هر مقدار TYPE. سپس عبارت HAVING برای هر گروه اعمال می شود و گروه هایی که حداکثر سطح کیفیت آنها از 3 بیشتر است حذف می شوند. در نهایت، بند SELECT برای گروه های باقی مانده اعمال می شود.

7. توابع داخلی و سوالات فرعی

توابع داخلی را فقط می توان در یک بند SELECT یا دستور HAVING استفاده کرد. با این حال، یک عبارت SELECT حاوی یک تابع درون خطی می تواند بخشی از یک پرسش فرعی باشد. بیایید به مثالی از چنین سؤال فرعی نگاه کنیم:

درخواست:کدام کارگران نرخ ساعتی بالاتر از میانگین دارند؟

WORKER_NAME را انتخاب کنید

WHERE HRLY_RATE >

(انتخاب AVG (HRLY_RATE)

نتیجه:

اچ. کلمب

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

پرس و جوهای مرتبط همچنین می توانند از توابع داخلی استفاده کنند:

سوال: کدام کارمند در بین زیردستان همان مدیر، نرخ ساعتی بالاتر از میانگین نرخ ساعتی دارد؟

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

A. WORKER_NAME را انتخاب کنید

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

انواع عبارات جستجو:
. مقایسه با نتیجه یک استعلام فرعی (=، >=)
. بررسی تعلق به نتایج یک پرسش فرعی (IN)
. بررسی وجود (EXISTS)
. مقایسه چندگانه (کمی) (ANY، ALL)

نکات مربوط به پرس و جوهای تو در تو:
. یک پرسش فرعی باید فقط یک ستون را انتخاب کند (به جز یک پرس و جو فرعی با گزاره EXISTS)، و نوع داده نتیجه آن باید با نوع داده مقدار مشخص شده در گزاره مطابقت داشته باشد.
. در برخی موارد، می‌توانید از کلمه کلیدی DISTINCT برای اطمینان از بازگشت یک مقدار استفاده کنید.
. شما نمی توانید یک عبارت ORDER BY یا UNION را در یک درخواست فرعی قرار دهید.
. پرسش فرعی می تواند در سمت چپ یا راست شرط جستجو قرار گیرد.
. پرس و جوهای فرعی می توانند از توابع تجمع بدون بند GROUP BY استفاده کنند، که به طور خودکار مقدار خاصی را برای هر تعداد ردیف، یک محمول ویژه IN و عبارات مبتنی بر ستون برمی گرداند.
. در صورت امکان، باید به جای درخواست‌های فرعی، از اتصالات جدول JOIN استفاده کنید.

نمونه هایی برای پرس و جوهای تودرتو:

SELECT * FROM Orders WHERE SNum=(SELECT SNum FROM SalesPeople WHERE SName='Motika')
SELECT * FROM Orders WHERE SNum IN (انتخاب SNum FROM SalesPeople WHERE City='London')
SELECT * FROM Orders WHERE SNum=(SELECT DISTINCT SNum FROM Orders WHERE CNum=2001)
SELECT * FROM Orders WHERE Amt>(SELECT AVG(Amt) FROM Orders WHERE Odate=10/04/1990)
SELECT * FROM Customer WHERE CNum=(SELECT SNum+1000 FROM SalesPeople WHERE SName='Serres')

2) سوالات فرعی مرتبط

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

نمونه هایی برای سوالات فرعی مرتبط:

SELECT * FROM SalesPeople Main WHERE 1(SELECT AVG(Amt) FROM Orders O2 WHERE O2.CNum=O1.CNum) //همه سفارش هایی را که ارزش آنها از میانگین ارزش سفارش برای یک مشتری خاص بیشتر است را برمی گرداند.

3) محمول وجود دارد

شکل نحوی: وجود دارد ()

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

نکاتی در مورد محمول EXISTS:
. EXISTS یک گزاره است که TRUE یا FALSE را برمی گرداند و می تواند به تنهایی یا با سایر عبارات بولی استفاده شود.
. EXISTS نمی تواند از توابع تجمع در پرس و جوی فرعی خود استفاده کند.
. در پرس و جوهای فرعی همبسته، گزاره EXISTS برای هر ردیف از جدول بیرونی اجرا می شود.
. می توانید گزاره EXISTS را با اتصالات جدول ترکیب کنید.

مثال هایی برای گزاره EXISTS:

SELECT * FROM Customer WHERE EXISTS (SELECT * FROM Customer WHERE City='San Jose') - اگر هر یک از آنها در سن خوزه زندگی می کنند، همه مشتریان را برمی گرداند.
SELECT DISTINCT DISTINCT FROM Customer First WHERE NOT EXISTS (انتخاب * FROM Customer Send WHERE Send.SNum=First.SNum AND Send.CNumFirst.CNum) – تعداد فروشندگانی را که فقط به یک مشتری خدمت کرده اند برمی گرداند.
SELECT DISTINCT F.SNum، SName، F.City FROM SalesPeople F، Customer S WHERE EXISTS (انتخاب * از مشتری T WHERE S.SNum=T.SNum و S.CNumT.CNum و F.SNum=S.SNum) – برمی گرداند شماره، نام و شهر محل سکونت کلیه فروشندگانی که به چندین مشتری خدمات ارائه می دهند.
SELECT * FROM SalesPeople Frst WHERE EXISTS (انتخاب * FROM Customer Send WHERE Frst.SNum=Send.SNum AND 1

4) محمولات مقایسه کمی

شکل نحوی: (=|>|=|) هر|همه ()

این محمولات از یک پرس و جو به عنوان آرگومان استفاده می کنند، با این حال، در مقایسه با محمول EXISTS، همراه با محمولات رابطه ای (=،>=) استفاده می شوند. از این نظر، آنها شبیه به گزاره IN هستند، اما فقط با سوالات فرعی استفاده می شوند. استاندارد اجازه می دهد تا از کلمه کلیدی SOME به جای ANY استفاده شود، اما همه DBMS ها از آن پشتیبانی نمی کنند.

نکاتی در مورد محمول های مقایسه ای:
. اگر هر مقدار انتخاب شده در حین اجرای پرس و جو، شرایط مشخص شده در محمول پرس و جو بیرونی را برآورده کند، گزاره ALL به TRUE ارزیابی می شود. اغلب با نابرابری ها استفاده می شود.
. در صورتی که حداقل یک مقدار انتخاب شده در طول اجرای پرس و جو، شرایط مشخص شده در گزاره پرس و جو خارجی را برآورده کند، گزاره ANY به TRUE ارزیابی می شود. اغلب با نابرابری ها استفاده می شود.
. اگر پرس و جوی فرعی هیچ ردیفی را برنگرداند، ALL به طور خودکار مقدار TRUE را می گیرد (در نظر گرفته می شود که شرط مقایسه برآورده شده است) و برای ANY مقدار FALSE را می گیرد.
. اگر مقایسه برای هیچ ردیفی درست باشد و یک یا چند ردیف با مقدار NULL وجود داشته باشد، ANY ناشناخته را برمی‌گرداند.
. اگر مقایسه برای هیچ ردیفی FALSE باشد و یک یا چند ردیف با مقدار NULL وجود داشته باشد، آنگاه ALL ناشناخته را برمی‌گرداند.

مثال هایی برای محمول مقایسه کمی:

SELECT * FROM SalesPeople WHERE City=ANY(انتخاب شهر از مشتری)
SELECT * FROM Orders WHERE Amt ALL (انتخاب رتبه از مشتری WHERE City='Rome')

5) محمول یگانگی

منحصر به فرد | متمایز ()

از گزاره برای بررسی یکتایی (عدم وجود موارد تکراری) در داده های خروجی پرس و جو استفاده می شود. علاوه بر این، در گزاره UNIQUT رشته هایی با مقادیر NULL منحصر به فرد و در گزاره DISTINCT دو مقدار تعریف نشده برابر یکدیگر در نظر گرفته می شوند.

6) منطبق بر محمول

همخوانی داشتن ()

گزاره MATCH آزمایش می کند که آیا مقدار رشته پرس و جو با مقدار هر رشته ای که از پرس و جو فرعی حاصل می شود مطابقت دارد یا خیر. این پرس و جو فرعی با گزاره های IN AND ANY تفاوت دارد زیرا امکان پردازش تطابقات "جزئی" (PARTIAL) را می دهد که می تواند در بین ردیف هایی که مقادیر NULL دارند رخ دهد.

7) پرس و جو در بخش FROM

در واقع، استفاده از پرس و جوی فرعی در هر جایی که مرجع جدول مجاز است، قانونی است.

SELECT CName، Tot_Amt FROM Customer، (SELECT CNum، SUM(Amt) AS Tot_Amt FROM Orders GROUP BY CNum) WHERE City='London' AND Customer.CNum=Orders.CNum
//subquery مجموع سفارش های ارسال شده توسط هر مشتری از لندن را برمی گرداند.

8) پرس و جوهای بازگشتی

با بازگشتی
Q1 به عنوان انتخاب ... از ... کجا ...
Q2 به عنوان انتخاب ... از ... کجا ...




بالا