MariaDB
 sql >> база данни >  >> RDS >> MariaDB

MariaDB SQL оператори за набор

Операторите за набор са SQL операторите, които се занимават с комбиниране по различни начини на различни набори от резултати. Да речем, че имате два различни SELECT s, които искате да комбинирате в един набор от резултати, операторите за набор влизат в игра. MariaDB поддържа UNION и UNION ALL set оператори за дълго време и това са най-често срещаните SQL оператори за набор.

Но тук се изпреварваме, нека първо да обясня операторите на SQL набор, които имаме и как работят. Ако искате да опитате това, можете да използвате съществуващото си внедряване на MariaDB Server или да изпробвате това в облачна база данни на MariaDB SkySQL.

UNION и UNION ALL

UNION и UNION ALL операторите за набор добавят резултата от два или повече набора от резултати. Нека започнем с UNION ALL и UNION тогава ще бъде вариант на UNION ALL .

Нека да разгледаме как изглежда в SQL. Да предположим, че управляваме уеб магазин и че за продуктите, които продаваме, имаме инвентар. Сега искаме да видим всички продукти, които са по поръчка или са в инвентара, заявка за това ще изглежда така:

 ИЗБЕРЕТЕ oi.prod_id, p.prod_name ОТ order_items oi ПРИСЪЕДИНЕТЕ продукти p ON oi.prod_id =p.id UNION ВСИЧКИ ИЗБЕРЕТЕ i.prod_id, p.prod_name ОТ инвентара i ПРИСЪЕДИНЕТЕ продукти p ON i.prod_id =p.id; 

В теорията на множеството това е UNION на комплектите продукти, които са поръчани и комплектите продукти, които са в инвентара. Което е добре на теория, но има проблем с резултата от тази заявка. Проблемът е, че продукт, който се появява както в поръчките, така и в инвентара, или на множество места в инвентара, ще се появи повече от веднъж в изхода. Този проблем е причината UNION ALL не се използва много и вместо това UNION DISTINCT (DISTINCT е по подразбиране и може да се игнорира). Например:

ИЗБЕРЕТЕ oi.prod_id, p.prod_name ОТ order_items oi ПРИСЪЕДИНЕТЕ продукти p ON oi.prod_id =p.id UNION ИЗБЕРЕТЕ i.prod_id, p.prod_name ОТ инвентара i ПРИСЪЕДИНЕТЕ продукти p ON i.prod_id =p.id; 

С тази заявка продукт, който е по поръчка или съществува в инвентара, е посочен само веднъж. Имайте предвид, че когато премахваме дубликати тук, стойностите се сравняват, така че два реда с еднакви стойности в една и съща колона се считат за равни, въпреки че стойностите идват от различни таблици или колони.

За да бъда честен обаче, няма нищо в заявката по-горе, което да не може да се направи с обикновен SELECT от продуктите маса и няколко съединения. В известен смисъл UNION може да е по-лесно за четене. От друга страна, ако искаме да имаме списък с продукти по поръчка или в инвентара и също така искаме да знаем кой е бил, тогава заявката ще бъде нещо подобно:

 ИЗБЕРЕТЕ 'По поръчка', oi.prod_id, p.prod_name FROM order_items oi ПРИСЪЕДИНЕТЕ продукти p ON oi.prod_id =p.id UNION ИЗБЕРЕТЕ 'Inventory', i.prod_id, p.prod_name ОТ инвентар i ПРИСЪЕДИНЕТЕ продукти p ON i.prod_id =p.id;

Ето заявка, която не е лесна за изпълнение с обикновен SELECT от продуктите таблица, тъй като разглеждаме един и същ ред от таблицата с продукти два пъти (веднъж за order_items и веднъж за инвентара ).

Още оператори за SQL набор

С MariaDB Server 10.3 дойдоха два нови оператора за SQL набор, въведени до голяма степен за подобряване на съвместимостта с Oracle, но тези оператори са полезни сами по себе си. След това MariaDB Server 10.4 добавя възможността за контрол на приоритета на оператора. Ще разгледаме и това. Без възможност за контрол на приоритета на оператора, зададените оператори не винаги работят, както бихте искали или очаквате.

Новите оператори за SQL набор са INTERSECT и EXCEPT и те са полезни, особено при използване на анализи. Също така, въпреки че JOIN s и други конструкции често могат да се използват вместо това, SQL операторите за набор позволяват SQL синтаксис, който може да бъде по-лесен за четене и разбиране. И ако имате приложения на Oracle, които мигрирате към MariaDB, полезността на тези оператори е очевидна.

Операторът за набор INTERSECT

INTERSECT операторът ще върне всички елементи, които съществуват в два или повече набора, или в SQL термини, всички редове, които съществуват в два набора от резултати. В този случай се създава напречно сечение на двата комплекта елементи. В термините на SQL това означава, че се връщат само редове, които съществуват и в двата набора, така че ако искам да проверя кои продукти имам по поръчка и кои също са в инвентара, една заявка може да изглежда така:

 ИЗБЕРЕТЕ oi.prod_id, p.prod_name ОТ order_items oi ПРИСЪЕДИНЕТЕ продукти p ON oi.prod_id =p.id INTERSECT SELECT i.prod_id, p.prod_name ОТ инвентара i ПРИСЪЕДИНЕТЕ се продукти p ON i.prod_id =p.id; 

Отново тази заявка може да бъде конструирана с помощта на JOIN на продуктите таблица, но заявката по-горе е малко по-ясна за това, което се опитваме да постигнем.

Операторът за набор EXCEPT

В случай на EXCEPT оператор, искаме елементите, които са в един от наборите, но не и в другия. Така че, отново използвайки примера по-горе, ако искаме да видим продуктите, които имаме по поръчка, но за които нямаме инвентар, можем да напишем заявка като тази:

 ИЗБЕРЕТЕ oi.prod_id, p.prod_name ОТ order_items oi ПРИСЪЕДИНЕТЕ продукти p ON oi.prod_id =p.id ОСВЕН ИЗБЕРЕТЕ i.prod_id, p.prod_name ОТ инвентара i ПРИСЪЕДИНЕТЕ се продукти p ON i.prod_id =p.id; 

Отново има други начини за писане на тази конкретна заявка, но за други, по-разширени заявки, когато комбинираме данни от две различни таблици, това не е така.

Комбиниране на множество оператори за набор

Можете да комбинирате повече от 2 набора оператора, ако това е полезно. Например, нека видим дали можем да намерим продукти, които са по поръчка и са доставени или са на склад. SQL за това би изглеждал така:

ИЗБЕРЕТЕ oi.prod_id, p.prod_name ОТ order_items oi ПРИСЪЕДИНЕТЕ продукти p ON oi.prod_id =p.id INTERSECT SELECT d.prod_id, p.prod_name ОТ доставки d ПРИСЪЕДИНЕТЕ продукти p ON d.prod_id =p.id UNION SELECT i.prod_id, p.prod_name ОТ инвентара i ПРИСЪЕДИНЕТЕ се към продукти p ON i.prod_id =p.id;

За да изразя това на разбираем език, това, което се случва е, че първо проверявам кои продукти са поръчани и кои са доставени, а след това комбинирам този набор от продукти с всички продукти в инвентара. Всеки продукт, който не е в набора от резултати, не е в инвентара но може да е по поръчка или да е доставено, но не и двете.

Но сега нека изразим това по различен начин и да видим какво ще се случи. Искам списък на всички продукти, които са на склад или са доставени и са по поръчка. Тогава SQL ще бъде нещо подобно, подобно на SQL по-горе, но малко по-различно:

 ИЗБЕРЕТЕ i.prod_id, p.prod_name ОТ инвентара i JOIN продукти p ON i.prod_id =p.id UNION SELECT oi.prod_id, p.prod_name ОТ order_items oi ПРИСЪЕДИНЕТЕ продукти p ON oi.prod_id =p.id INTERSECT SELECT SELECT SELECT. d.prod_id, p.prod_name ОТ доставки d ПРИСЪЕДИНЕТЕ се към продукти p ON d.prod_id =p.id;

Как тълкувате това тогава? Изброявате ли продукти, които са на склад и които са по поръчка и продуктите, които се доставят? Ето как изглежда това, нали? Просто това е INTERSECTEXCEPT по този въпрос) има приоритет през UNION . Двата SQL оператора произвеждат един и същ набор от резултати, поне в MariaDB и ето как SQL стандартът казва, че нещата трябва да работят. Но има изключение, Oracle.

Как работи това в Oracle

Oracle има и четирите оператора на набора SQL (UNION , UNION ALL , INTERSECT и EXCEPT ) за дълго време, много преди да бъдат стандартизирани, така че изпълнението им е малко по-различно. Нека опитаме с горните таблици и да вмъкнем някои данни в тях. Данните са много прости и отразяват не толкова успешна компания, но работят като пример и тук показваме само съответните колони.

Таблица продукти поръчкови_артикули инвентар доставки
Колона prod_id име на продукта идентификатор_на_поръчка prod_id prod_id prod_id
Данни 1 Синя ваза 1 1 1 2
2 Червена ваза 2 1 2 3
3 Червен килим 2 3

С наличните данни, нека отново да разгледаме последния SQL израз по-горе. Има функция, която ви позволява да контролирате приоритета и това е да използвате скоби или скоби (въведено в MariaDB 10.4, вижте https://jira.mariadb.org/browse/MDEV-11953) и използването им за илюстриране какво се случва, изявлението ще изглежда така:

 MariaDB> ИЗБЕРЕТЕ i.prod_id, p.prod_name -> ОТ инвентара i ПРИСЪЕДИНЯВАЙТЕ се към продуктите p ON i.prod_id =p.id -> UNION -> (ИЗБЕРЕТЕ oi.prod_id, p.prod_name -> ОТ order_items oi ПРИСЪЕДИНЕТЕ продукти p ON oi.prod_id =p.id -> INTERSECT -> SELECT d.prod_id, p.prod_name -> ОТ доставки d ПРИСЪЕДИНЕТЕ продукти p ON d.prod_id =p.id); +---------+-----------+ | prod_id | prod_name | +---------+-----------+ | 1 | Синя ваза | | 2 | Червена ваза | | 3 | Червен килим | +---------+-----------+ 3 реда в комплект (0,001 сек)

Сега нека използваме същата техника, за да наложим трите компонента на заявката да работят в строг ред:

 MariaDB> (ИЗБЕРЕТЕ i.prod_id, p.prod_name -> ОТ инвентара i ПРИСЪЕДИНЕТЕ се към продуктите p ON i.prod_id =p.id -> UNION -> ИЗБЕРЕТЕ oi.prod_id, p.prod_name -> ОТ order_items oi ПРИСЪЕДИНЕТЕ се към продукти p ON oi.prod_id =p.id) -> INTERSECT -> SELECT d.prod_id, p.prod_name -> ОТ доставки d ПРИСЪЕДИНЕТЕ продукти p ON d.prod_id =p.id; +---------+-----------+ | prod_id | prod_name | +---------+-----------+ | 2 | Червена ваза | | 3 | Червен килим | +---------+-----------+ 2 реда в комплект (0,001 сек)

И накрая без скоби:

 MariaDB [тест]> ИЗБЕРЕТЕ i.prod_id, p.prod_name -> ОТ инвентара i ПРИСЪЕДИНЯВАЙТЕ се към продукти p ON i.prod_id =p.id -> UNION -> SELECT oi.prod_id, p.prod_name -> ОТ order_items oi ПРИСЪЕДИНЕТЕ продуктите p ON oi.prod_id =p.id -> INTERSECT -> SELECT d.prod_id, p.prod_name -> ОТ доставки d ПРИСЪЕДИНЕТЕ продукти p ON d.prod_id =p.id; +---------+-----------+ | prod_id | prod_name | +---------+-----------+ | 1 | Синя ваза | | 2 | Червена ваза | | 3 | Червен килим | +---------+-----------+ 3 реда в комплект (0,001 сек)

Виждаме, че MariaDB, следвайки стандарта, прие, че INTERSECT има предимство пред UNION . Което ни отвежда до Oracle. Нека опитаме горния SQL в Oracle с помощта на sqlplus:

 SQL> ИЗБЕРЕТЕ i.prod_id, p.prod_name 2 ОТ инвентара i ПРИСЪЕДИНЕТЕ продукти p ON i.prod_id =p.id 3 UNION 4 SELECT oi.prod_id, p.prod_name 5 ОТ order_items oi ПРИСЪЕДИНЕТЕ продукти p ON oi.prod_id =p.id 6 INTERSECT 7 SELECT d.prod_id, p.prod_name 8 ОТ доставки d ПРИСЪЕДИНЕТЕ продукти p ON d.prod_id =p.id; PROD_ID PROD_NAME ---------- ------------------------------ 2 ваза Червена 3 Червен килим 

Какво става тук, питате? Е, Oracle не следва стандарта. Различните оператори на набора се третират като равни и никой няма предимство пред другия. Това е проблем, когато мигрирате приложения от Oracle към MariaDB и което е по-лошо е, че тази разлика е доста трудна за намиране. Не се създава грешка и се връщат данни и в много случаи се връщат правилните данни. Но в някои случаи, когато данните са като в нашия пример по-горе, се връщат грешни данни, което е проблем.

Ефект върху мигрирането на данни

И така, как да се справим с това, ако мигрираме приложение от Oracle към MariaDB? Има няколко опции:

  • Пренапишете приложението, така че да приеме, че данните, върнати от заявка като тази, са в съответствие със стандарта на SQL и MariaDB.
  • Пренапишете SQL изразите, като използвате скоби, така че MariaDB да връща същите данни като Oracle
  • Или и това е най-умният начин, използвайте MariaDB SQL_MODE=Oracle настройка.

За последния и най-интелигентен начин да работим, трябва да работим с MariaDB 10.3.7 или по-нова версия (това беше предложено от вас наистина в https://jira.mariadb.org/browse/MDEV-13695). Нека проверим как работи това. Сравнете резултата от този SELECT с Oracle по-горе (който дава същия резултат) и този от MariaDB по-горе (който не):

 MariaDB> задайте SQL_MODE=Oracle; Заявка ОК, 0 засегнати реда (0,001 сек) MariaDB> ИЗБЕРЕТЕ i.prod_id, p.prod_name -> ОТ инвентара i ПРИСЪЕДИНЕТЕ продукти p ON i.prod_id =p.id -> UNION -> SELECT oi.prod_id, p.prod_name -> ОТ order_items oi ПРИСЪЕДИНЕТЕ продукти p ON oi.prod_id =p.id -> INTERSECT -> SELECT d.prod_id, p.prod_name -> ОТ доставки d ПРИСЪЕДИНЕТЕ продукти p ON d.prod_id =p.id; +---------+-----------+ | prod_id | prod_name | +---------+-----------+ | 2 | Червена ваза | | 3 | Червен килим | +---------+-----------+ 2 реда в комплект (0,002 сек)

Както можете да видите, когато SQL_MODE е настроен на Oracle , MariaDB наистина се държи като Oracle. Това не е единственото нещо, което SQL_MODE=Oracle разбира се, но това е една от по-малко известните области.

Заключение

Операторите за множество INTERSECT и EXCEPT не се използват толкова много, въпреки че се появяват тук-там и има някои приложения за тях. Примерите в този блог са повече, за да илюстрират как работят тези оператори, отколкото да покажат наистина добра употреба за тях. Сигурно има по-добри примери. Въпреки това, когато мигрирате от Oracle към MariaDB, операторите за набор от SQL са наистина полезни, тъй като много приложения на Oracle ги използват и както се вижда, MariaDB може да бъде подведена да работи точно като Oracle, който не е стандартен, но все пак служи за цел. Но по подразбиране, разбира се, MariaDB работи както трябва и следва SQL стандарта.

Приятно изпълнение на SQL
/Karlsson


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как MAKE_SET() работи в MariaDB

  2. Как работи SIN() в MariaDB

  3. Обявяване на ClusterControl 1.5 – включващ автоматична проверка на архивиране и качване в облак

  4. Избягване на блокиране на доставчик на база данни за MySQL или MariaDB

  5. Как да преодолеем случайното изтриване на данни в MySQL и MariaDB