Join (SQL)SQL придруживање клаузула комбинује записе из две или више табела у референтне базе података. Креира сет који може бити снимљен као табела или искоришћен такав какав јесте. Програмер пише наредбу Пробне табелеРелационе базе података су обично нормализоване да елиминишу дуплирање података као што су када објекти имају једну-на-више релација. На пример , Одељење може бити повезано са великим бројем Запослених. Придруживање раздваја табеле за Одељење и Запослене и ефективно креира другу табелу која комбинује информације из обе. Ово је у неку штету у смислу времена које је потребно да се израчуна придруживање. А такође је могуће да се једноставно одржава денормализована табела ако је брзина битна, дуплиране информације могу узети додатан простор, и додати трошкове и сложеност одржавања интегритета података ако се подаци који су дуплирани касније промене. Сва накнадна објашњења о типу придруживања у овом артиклу су направљена на основу следеће две табеле. Редови у овим табелама служе да илуструју ефекат различитих типова придруживања и предиката придруживања. У наредним табелама
Напомена: У табели Запослених изнад, запослени "Вилиамс" није још додељен ниједном одељењу. Такође, приметите да нема запослених додељених "Маркетинг" одељењу . Ово је SQL наредба за креирање наведених табела. CREATE TABLE одељење
(
ОдељењеИД INT,
ОдељењеНазив VARCHAR(20)
);
CREATE TABLE запослени
(
Презиме VARCHAR(20),
ОдељењеИД INT
);
INSERT INTO одељење VALUES(31, 'Распродаја');
INSERT INTO одељење VALUES(33, 'Инжењери');
INSERT INTO одељење VALUES(34, 'Свештеници');
INSERT INTO одељење VALUES(35, 'Маркетинг');
INSERT INTO запослени VALUES('Раферти', 31);
INSERT INTO запослени VALUES('Џоунс', 33);
INSERT INTO запослени VALUES('Хаизенберг', 33);
INSERT INTO запослени VALUES('Робинсон', 34);
INSERT INTO запослени VALUES('Смит', 34);
INSERT INTO запослени VALUES('Вилиамс', NULL);
Укрштено придруживањеУКРШТЕНО ПРИДРУЖИВАЊЕ враћа Декартов производ редова табеле придруживања. Другим речима, произвешће редове који комбинују сваки ред прве табеле са сваким редом друге табеле.[1] Пример експлицитног укрштеног придруживања: SELECT *
FROM запослени CROSS JOIN одељење;
Пример имплицитног укрштеног придруживања: SELECT *
FROM запослени, одељење;
Укрштено придруживање не примењује предикат за филтрирање података из табеле придруживања. Резултат укрштеног придруживања може бити филтриран користећи У SQL:2011 стандарду, укрштена придруживања су део опционог F401, "Табела продуженог придруживања", пакета. Нормална употреба је за проверавање перформанси сервера. Природно придруживање (⋈)Природно придруживање () је бинарна операција која се записује као (R S) где су R и S релације.[2] Резултат природног придруживања је сет свих комбинација од торки у R и S који су једнаки уобичајеним именима њихових атрибута. На пример размотримо табеле Запослени and Одељење и њихово природно придруживање:
Ово такође може бити искоришћено за дефинисање композиције релација. На пример, композиција Запослени and Одељење је њихово придруживање као што је приказано горе, пројектовано на све сем заједничког атрибута ОдељењеНазив. У теорији категорије, придруживање је управо продукат влакана. Природно придруживање је вероватно једна од најбитнијих операција јер је релациони пандан логичком И. Приметите пажљиво да ако се иста променљива појављује у сваком од два предиката који су повезани са И, онда се та променљива залаже за исту ствар и оба појављивања морају бити замењена истом вредношћу. Конкретно, природно придруживање омогућује комбинацију релација које су повезане страним кључем. На пример, у горњем примеру страни кључ вероватно раздваја Запослени.ОдељењеНазив и Одељење.ОдељењеНазив и онда природно придруживање Запослених и Одељења комбинује све запослене са њиховим одељењем. Приметите да ово функционише зато што страни кључ стоји између атрибута са истим именом. Ако ово није случај да је страни кључ између Одељење.менаџер и Запослени.Име онда морамо да преименујемо колоне пре него што применимо природно придруживање. Такво придрживање се понекад поистовећује са изједначеним придруживањем. Више формалне семантике природног придруживања је дефинисано на следећи начин: где је Fun предикат који је тачан за релацију r Ако и само ако је r функција. Обично се захтева да R и S имају бар једну заједничку особину, али ако се изостави ово ограничење, и R и S немају заједничку особину, онда природно придруживање постаје баш Декартов производ. Природно придруживање може бити симулирано са Codd's primitives на следећи начин. Претпоставимо да су c1,...,cm имена атрибута заједничка за R и S, r1,...,rn су имена атрибута јединствена за R и s1,...,sk су атрибути јединствени за S. Штавише, претпоставити да имена атрибута x1,...,xm нису ни у R ни у S. У првом кораку ми сада можемо преименовати заједничка имена атрибута у S: Онда ћемо узети Декартов производ и изабрати оне врсте које треба придружити: Коначно узимамо пројекцију како би се отарасили преименованих атрибута: Природно придруживање је специјалан случај изједначеног придруживања које је специјалан случај унутрашњег придруживања као што је описано у Природном придруживању. Унутрашње придруживањеУнутрашње придруживање захтева да сваки податак из две повезане табеле има податак са којим је повезан, и обично је корисна операција у апликацијама али није засигурно најбољи избор у свим ситуацијама. Унутрашње придруживање креира нову резултујућу табелу комбиновањем вредности колона две табеле (A и B) заснованим на предикатима придруживања. Упит пореди сваки ред из А са сваким редом из B како би нашао све парове редова који задовољавају предикат придруживања. Када је предикат придруживања задовољен одговарајућим не-нула вредностима, вредности колона за сваки одговарајући пар редова A и B се комбинују у резултујући ред. Резултат придруживања може бити дефинисан као исход узимања Декартовог производа (или укрштеног придруживања) свих података табеле (комбиновање сваког податка из табеле А са сваким податком из табеле B) и затим се враћају сви подаци који задовољавају предикат придруживања. Актуелне SQL имплементације нормално користе и друге приступе, као што је [[хеш придруживање или придруживање сортирање спајањем, од ере компјутера Декартов производ је спорији и често ће захтевати недопустиво велики меморијски простор за складишћење. SQL наводи два различита синтаксна начина да изрази придруживања: "експлицитна нотација придруживања" и "имплицитна нотација придруживања". Такође "имплицитна нотација придруживања" је превазиђена у 1992, и њена употреба се не сматра најбољом праксом, ипак база података је и даље подржава. "Експлицитна нотација придруживања" користи SELECT *
FROM запослено
INNER JOIN одељење ON запослени.ОдељењеИД = одељење.ОдељењеИД;
"Имплицитна нотација придруживања" једноставно листа табеле за придруживања, у Наредни пример је еквивалентан претходном, али овај пут у имплицитној нотацији: SELECT *
FROM запослени, одељење
WHERE запослени.ОдељењеИД = одељење.ОдељењеИД;
Упити дати у примерима изнад ће придружити табеле Запослени и Одељење користећи ОдељењеИД колону обе табеле. Где се ОдељењеИД ових табела подудара (тј. предикат придруживања је задовољен), упит ће комбиновати Презиме, Одељење и ОдељењеНазив колоне из две табеле у резултујући ред. Где се ОдељењеИД не подудара, резултујући ред неће бити генерисан. Тако ће резултат извршења било која од два упита изнад бити:
Приметимо да се запослени "Вилиамс" и одељење "Маркетинг" не појављују у резултатима извршења упита. Ни једно од њих нема подударања записа у другој одговарајућој табели: "Вилиамс" нема повезано одељење, и нема запослених са одељењем ИД 35 ("Маркетинг"). Зависно од жељених резултата, ово понашање може бити суптилна грешка, која се може избећи заменом унутрашњег придруживања са спољашњим. Приметити: Програмери би требало посебно да обрате пажњу када табеле придруживања у колонама могу да садрже NULL вредности, док NULL неће никада одговарати било којој другој вредности (ни самој нули), осим ако услов придруживања експлицитно користи комбинацију предиката који прво проверавају да ли су поља придруживања Било које поље податка које може бити NULL (празно) не би требало никад да буде употребљено као веза у унутрашњем придруживању, осим ако је жељени резултат да се елиминишу подаци са NULL вредношћу. Ако су NULL поља придруживања намерно уклоњена из скупа резултата,унутрашње придруживања може бити брже од једног спољашњег зато што табела придруживања и филтрирање се обавља у једном кораку. Супротно, унутрашње придруживања може резултирати катастрофалном смањивању перформанси или чак падом сервера при коришћењу великог опсега упита у комбинацији са функцијама базе података у SQL Where клаузули.[3][4][5] Фунција у SQL Where клаузули може резултирари у бази података игнорисањем релативно компактних индекса табеле. База података може читати и селектована поља унутрашњег придруживања из обе табеле пре редуковања броја редова користећи филтер који зависи од израчунате вредности, што резултира релативно огромној количини неефикасне обраде. Када је резултујући скуп произведен придруживањем више табела, укључујући мастер табеле које се користе за тражење целокупног текстуалног описа нумеричких идентификационих кодова (Лукап табела), а NULL вредности у било ком од страних кључева може резултирати да се цео ред елиминише из резултујућег скупа, без индикације о грешци. Комплекс SQL упита који укључују један или више унутрашњих придруживања и неколико спољашњих имају исти ризик за NULL вредности у линк пољима спољашњег придруживања. Посвећеност SQL коду садржи претпоставку унутрашњег придруживања да NULL поља придруживања неће бити уведена будућим променама, укључујући vendor updates, промене дизајна и главно процесирање ван правила ваљаности апликационих података као што су конверзије података, миграције, bulk укључивања и стапања. Може се даље класификовати унутрашње придруживања као изједначено придруживање, као природно придруживања, или као укрштено придруживања. Изједначено придруживањеИзједначено придруживање је специјалан тип придруживања базираног на компаратору, који користи само једнакост поређења у предикату придруживања. Користећи друге операторе поређења (као што је SELECT *
FROM запослени JOIN одељење
ON запослени.ОдељењеИД = одељење.ОдељењеИД;
Можемо писати изједначено придруживање као испод, SELECT *
FROM запослени, одељење
WHERE запослени.ОдељењеИД = одељење.ОдељењеИД;
Ако колоне у изједначеном придруживања имају исто име, SQL-92 допушта опциону скраћену нотацију за изражавање изједначеног придруживања, путем SELECT *
FROM запослени INNER JOIN одељење USING (DepartmentID);
Природно придруживањеПриродно придруживање је врста подједнаког придруживања где join предикат настаје имплицитно поређењем свих колона у обе табеле које имају исти назив колоне у повезаној табели. Резултујућа повезана табела садржи само једну колону за сваки пар колона са истим називом. У случају да нема колона са истим називом онда се користи укрштено придруживање. Многи експерти сматрају да је ПРИРОДНО ПРИДРУЖИВАЊЕ опасно и обесхрабрује њихову употребу.[7] Опасност долази од намерног додавања нове колоне, именоване исто као друга колона у другој табели. У постојећем природном придруживању он ће "природно" да користи нову колону за поређење, вршећи поређење користећи другачије критеријуме (од различитих колона) него раније. Тако постојећи упит може произвести различите резултате, иако подаци у табели нису промењени, али јесте аргумент. Употреба имена колона да се аутоматски одреди везе између табела није добра опција у великим базама података са стотине или хиљаде табела. У реаланом свету база података су углавном дизајниране са Страни кључ подацима који нису дословно попуњени (NULL вредности су дозвољене), због правила пословања. То је уобичајена пракса да се модификују имена колона сличних података у различитим табелама и овај недостатак природног придруживања је теоретски концепт за дискусију. Горњи пример упита за унутрашње придруживање може се објаснити као природно придруживање на следећи начин: SELECT *
FROM запослени NATURAL JOIN одељење;
Као и код експлицитног коришћења
PostgreSQL, MySQL и Oracle подржавају природно придруживање; Microsoft T-SQL и IBM DB2 не подржавају. Колоне које се користе у придруживању су имплицитне па код придруживања не приказује очекиване колоне, и промене у називу колона могу да промене разултат. У SQL:2011 стандарду, природно придруижвање је део опције F401, "Проширене табеле придруживања", пакета. У многим окружењима база података имена колона су контролисана спољашњом помоћу, а не упитом програмера. Природно придруживање претпоставља стабилност и конзистентност назива колона које може да се проемни надоградњом верзије. Спољашње придруживањеПридружене табеле задржавају сваки податак—чак иако не постоји ни један други повезани податак. Спољашње придруживање се даље дели на лево спољашње, десно спољашње придруживање и потпуно спољашње придруживање, што зависи који редови табеле су задржани (леви, десни, или оба). (У случају лево и десно односи се на две стране Не постоји имплицитна нотација за спољашње придруижвање у стандарду SQL. Лево спољашње придруживањеРезултат левог спољашњег придруживања (или једноставно лево придруживање) за табеле А и Б увек садржи све податке о “левој” табели (А), чак иако се по услову-придруживања не поклапа са подацима у “десној” табели (Б). Ово значи и ако клаузула ON пронађе 0 података у Б (за задати податак из А), придруживање ће свакако вратити ред као резултат (за тај податак) - али са NULL у свакој колони за Б. Лево спољашње придруживање враћа све вредности из унутрашњег придруживањаа плус све вредности из леве табеле које нису повезане са десном табелом, укључујући редове са NULL (празне) вредностима. На пример то нам омогућава да пронађемо одељење запослених, али и даље приказује запослене који нису придружени одељењу (за разлику од унутрашњег придруживања пример горе, где непридружени нису били у резултату). Пример левог спољашњег придруживања
Пример левог спољашњег придруживања ( SELECT *
FROM запослени
LEFT OUTER JOIN одељење ON запослени.ОдељењеИД = одељење.ОдељењеИД;
Алтернативне синтаксеOracle подржава застарелу[8] синтаксу: SELECT *
FROM запослени, одељење
WHERE запослени.ОдељењеИД = одељење.ОдељењеИД(+)
Sybase подржава синтаксу (Microsoft SQL Server старија синтакса од верзије 2000): SELECT *
FROM запослени, одељење
WHERE запослени.ОдељењеИД *= одељење.ОдељењеИД
IBM Informix подржава синтаксу: SELECT *
FROM запослени, OUTER одељење
WHERE запослени.ОдељењеИД = одељење.ОдељењеИД
Десно спољашње придруживањеДесно спољашње придруживање (или десно придруживање) личи на лево спољашње придруживање, осим што табеле третира обрнуто. Сваки ред из "десне" табеле (Б) ће се појавити у придруженој табели барем једном. Уколико постоје неповезани редови из "леве" табеле (А), NULL ће се појавити у колони из А за оне податке који нису повезани са Б. Десно спољашње придруживање враћа све вредности из десне табеле и повезане вредности из леве табеле (NULL у случају да није повезан придружује предикат). На пример, ово нам омогућава да нађемо запослене и његово или њено одељење, али и даље показује одељења које немају запослене. Испод је пример десно спољашњег придруживања ( SELECT *
FROM запослени RIGHT OUTER JOIN одељење
ON запослени.ОдељењеИД = одељење.ОдељењеИД;
Десно и лево спољашње придруживање су функционално једнаки. Ни један нема неку функцију коју други нема, тако да десно и лево спољашње придруживање могу да замене једно друго све док је редослед у табели обрнут. Потпуно спољашње придруживањеКонцептуално, потпуно спољашње придруживање комбинује ефекте од примене оба и левог и десног спољашњег придруживања. Где подаци у табели потпуног спољашњег придруживања нису повезани, резултат ће имати NULL вредност за сваку колону у табели где недостсаје повезани ред. За те податке који се поклапају, резултата ће бити једна линија (садржи поља из обе табеле). На пример, ово нам омогућава да видимо сваког запосленог који је у одељењу и свако одељење које има неког запосленог, али и да видимо сваког запосленог који није део одељења и свко одељење које нема запосленог. Пример тоталног спољашњег придруживања ( SELECT *
FROM запослени FULL OUTER JOIN одељење
ON запослени.ОдељењеИД = одељење.ОдељењеИД;
Неке базе података не подржавају функције тоталног спољашњег придруживања директно, али могу да симулирају то кроз употребу унутрашњег придруживања и UNION ALL селектора за "појединачни ред табеле" од леве и десне табеле редом. Исти пример може да се прикаже на следећи начин: SELECT запослени.Презиме, запослени.ОдељењеИД,
одељење.ОдељењеНазив, одељење.ОдељењеИД
FROM запослени
INNER JOIN одељење ON одељење.ОдељењеИД = одељење.ОдељењеИД
UNION ALL
SELECT запослени.Презиме, запослени.ОдељењеИД,
cast(NULL as varchar(20)), cast(NULL as integer)
FROM запослени
WHERE NOT EXISTS (
SELECT * FROM одељење
WHERE запослени.ОдељењеИД = одељење.ОдељењеИД)
UNION ALL
SELECT cast(NULL as varchar(20)), cast(NULL as integer),
одељење.ОдељењеНазив, одељење.ОдељењеИД
FROM одељење
WHERE NOT EXISTS (
SELECT * FROM запослени
WHERE запослени.ОдељењеИД = одељење.ОдељењеИД)
СамопридруживањеСамопридруживање придружује табелу себи.[9] ПримерУколико имамо две одвојене табеле за запослене и питање које захтева запосленог у првој табели који има исту државу као и запослен у другој табели, нормално придруживање може да се користи за налажење одговора. Свакако, све информације за запосленог се налазе у једној великој табели.[10] Размислите о модификовању
Пример решења упита може бити као у наставку: SELECT F.ЗапослениИД, F.Презиме, S.ЗапослениИД, S.Презиме, F.Држава
FROM Запослени F INNER JOIN Запослени S ON F.Држава = S.Држава
WHERE F.ЗапослениИД < S.ЗапослениИД
ORDER BY F.ЗапослениИД, S.ЗапослениИД;
Чији резултат се генерише наредном табелом.
За овај пример:
Само једно од два средња упарења су довољна да задовоље питање, и скроз горња и скроз доња су непотребна за овај пример. АлтернативеЕфекат спољашњег придруживања може се добити коришћењем UNION ALL између INNER JOIN и SELECT од редова у "главној" табели који не употпуњују услове придруживања. На пример, SELECT запослени.Презиме, запослени.ОдељењеИД, одељење.ОдељењеНазив
FROM запослени
LEFT OUTER JOIN одељење ON запослени.ОдељењеИД = одељење.ОдељењеИД;
може се такође записати као SELECT запослени.Презиме, запослени.ОдељењеИД, одељење.ОдељењеНазив
FROM запослени
INNER JOIN одељење ON запослени.ОдељењеИД = одељење.ОдељењеИД
UNION ALL
SELECT запослени.Презиме, запослени.ОдељењеИД, cast(NULL as varchar(20))
FROM запослени
WHERE NOT EXISTS (
SELECT * FROM одељење
WHERE запослени.ОдељењеИД = одељење.ОдељењеИД)
ИмплементацијаДоста посла у систему база података имају за циљ ефикасну имплементацију за придруживање, јер релациони системи обично траже придруживање, али се суочавају са потешкоћама у оптимизацији за ефикасно извршавање. Проблем настаје јер унутрашње повезивање оперишсе са оба Комутативност и Асоцијативност. У пракси, то значи да корисник само снабдева листу табела за придруживање и услове придруживања који се користе, а систем база података има задатак да пронађе најефикаснији начин да изврши операцију. Оптимизација упита одређује како да се изврши упит који садржи придруживање. Оптимизатор упита има две основне слободе:
Многи алгоритми упоређења третирају свој допринос различито. Може се односити на улазе за придруживање као и "спољашње" и "унутрашње" операције придруживања, или "лево" и "десно", редом. У случају груписаних петљи, на пример, систем база података ће скенирати унос унутрашњих релација за сваки ред спољашње релације. Један од њих може сврстати план-упита укључујући придруживање као у наставку:[11]
Ова имена су изведена од појаве План упита нацртано као Стабло (структура података), са релацијом спољашњег придруживања на левој и унутрашњег на десној (како налаже конвенција). Алгоритми придруживањаПостоје три основна алгоритма за операције придруживања: Придруживање укрштене петље, Прудруживање сортирање спајањем and Хеш придруживање. Индекси придруживањаИндекси придруживања су Индекси база података који олакшавају обраду упита придружовања у складишту података: они су тренутно (2012) доступни у имплементацијама Orakl[12] и Teradata.[13] У имплементацији Teradata, наведене колоне, свеобухватна функција за колоне, или компоненте од колоне датума из једне или више табела су наведе коришћењем синтаксе сличне дефиницииј Преглед база података: До 64 колона/колоне израза могу бити наведени у једном индекс придруживању. Опционо, колона која дефинише Примарни кључ композиционог податка може такође да буде наведен: на паралелном хардверу, вредности колоне се користе за поделу садржаја индекса на више дискова. Када се изворне табеле ажурирају интерактивно од стране корисника, садржај индекса придруживања ће бити аутоматски ажурирани. Било који упит чији WHERE клаузула прецизира било коју комбинацију колона или колона израза који је тачно онај подскуп који је дефинисан у индексу придруживања (тзв "прекривени упит") ће довести до индекса придруживања, пре него оригиналне табеле и њихови индекси, да буду консултовани у току извршавања упита. Oracle имплементације су лимитиране да користе bitmap индексе. bitmap индекси се користе за колоне са малим садржајем (тј, колона које садрже мало више од 300 различитих вредности, у складу са Oracle документацијом): она комбинује колоне са малим садржајем од више повезаних табела. Пример употребе Oracle је у систему инвентар, где различити добављачи обезбеђују различите делове. Шема има три повезане табеле: две "мастер табеле", Део и Добављач, и "табела детаља", Инвентар. Последњи је више и више табела повезивања Добављач за Део, и садржи највише редова. Сваки део садржи и тип дела, и сваки добављач ја основан у САД, и има колону Државе. Не постоји више од 60 држава-територија у САД, и не више од 300 типова делова. Bitmap индекси придруживања је дефинисано употребом стандардног придруживања три-табеле на три горње табеле, и дефинише Део_Тип и Добављач_Држава колоне за индексе. Свакако, то је дефинисано на табели Инвентара, иако су колоное Део_Тип и Добављач_Држава "позајмљене" од Добављач и Део. Као и за Teradata, Oracle bitmap индекси придруживања се користе да одговоре на упит када WHERE клаузула прецизира колоне ограничене на оне које су укључене у индексу придруживања. Директно придруживањеНеки системи база података дозвољавају кориснику да натера систем да чита табеле у придруживању у одређеном редоследу. Ово се користи када оптимизатор придруживања изабере да чита табеле и неефикасном редоследу. На пример, у MySQL команда Види јошРеференце
Литература
Спољашње везе |