Тази статия е първата от поредицата за основите на табличните изрази в T-SQL. Ще се съсредоточа основно върху четири типа изрази за таблици с имена, които са известни в T-SQL като производни таблици, общи изрази на таблици (CTE), изгледи и вградени функции с стойност на таблица (вградени TVF).
Бях вдъхновен да напиша тази поредица от моя добър приятел Грант Фричи, когото познавам от много години. Както Грант многократно посочва, мнозина, които използват общи изрази на таблици в T-SQL, смятат, че SQL Server запазва вътрешния набор от резултати от заявка и че причината за това убеждение е използването на термина таблица в името на конструкцията. Когато тази тема се появи в дискусиите в общността, често хората твърдят, че използването на термина таблица в името на конструкцията е неподходящо, тъй като всъщност не е таблица. Има дори предложения за стартиране на кампания за именуване с надеждата да видим бъдеща промяна на името на тази конструкция, поне в T-SQL. Някои от предложенията включват израз на заявка , вграден изглед , изглед на ниво оператор , и други.
Може би това ще бъде изненада за някои, но всъщност намирам употребата на термина таблица в израз на обща таблица като много подходящ. Всъщност намирам употребата на термина израз на таблица както е подходящо. За мен най-добрият начин да опиша какво е CTE в T-SQL, това е израз на име на таблица . Същото важи и за това, което T-SQL нарича извлечени таблици (специфичната езикова конструкция за разлика от общата идея), изгледи и вградени TVF. Всички те са наречени таблични изрази.
Ако можете да се търпите малко, ще дам мотивите за моя поглед върху нещата в тази статия. Хрумна ми, че както объркването при именуването, така и объркването относно това дали има аспект на постоянство в табличните изрази, могат да бъдат изчистени с по-добро разбиране на основите на нашата област на системите за управление на релационни бази данни. Тези основи са релационната теория, как SQL (стандартният език) се отнася към нея и как диалектът T-SQL, използван в реализациите на SQL Server и Azure SQL база данни, се отнася и към двете.
Като отправна точка искате да можете да отговорите на следните въпроси:
- Какво означава независимостта на физическите данни принцип в релационния модел означават?
- Какво е таблица в SQL и какво е двойникът в релационния модел?
- Какво е свойството на затваряне на релационната алгебра?
- Какво е табличен израз и какво е двойникът в релационния модел?
След като успеете да отговорите правилно на горните въпроси, много вероятно ще откриете използването на термина именуван табличен израз както е подходящо за гореспоменатите конструкции (това, което T-SQL нарича извлечени таблици, CTE, изгледи и вградени TVF).
Не искам да звучи така, сякаш имам много дълбоко разбиране на теорията на отношенията. Моят опит е T-SQL. Признавам, че има много повече неща, които не знам за релационната теория, отколкото аз, и че някои неща, които мисля, че знам, просто не са така. Когато чета писанията на C. J. Dates по темата, усещам, че едва надрасквам повърхността на това, което трябва да знам, и че бих могъл и трябва да се стремя да го разбера по-добре. Признавам и твърдо вярвам, че доброто разбиране на релационната теория води директно до по-добро разбиране на SQL и T-SQL и до писане на по-добър, по-точен и по-стабилен T-SQL код. За всеки, който избере данни като своя кариера, препоръчвам да прочете SQL и теория на релациите:Как да напишем точен SQL код, 3-то издание от C. J. Date (O'Reilly 2015).
В първата част от тази поредица искам да установя разбиране за моята употреба на термините израз на таблица и именуван табличен израз , което е в съответствие с използването на този термин от Date и за съжаление не е в съответствие с използването на този термин от SQL Standard. За да постигна това, ще предоставя малко предистория от релационната теория и SQL стандарта. Но както казах, препоръчвам да прочетете книгата на Date за наистина подробно отразяване на тази тема.
Ще започна, като обясня какво означава принципът за независимост на физическите данни. След това ще обясня какво представлява таблицата в SQL и нейния аналог в релационната теория. След това ще обясня какво означава свойството на затваряне на релационната алгебра. След като имате разумна представа за това какво е таблица и какво означава свойството за затваряне, става доста лесно да разберете какво представлява табличният израз. След това фокусът ми ще се насочи към спецификата в T-SQL. Имам много да кажа за основите на табличните изрази в T-SQL – както по отношение на концептуалното третиране, така и по отношение на детайлите на внедряването, включително съображения за физическо представяне и настройка на заявката.
Намирам тази тема за увлекателна и много практична, след като се задълбочите в подробностите за прилагането. Всъщност имам толкова много да кажа за това, че не съм сигурен колко части в крайна сметка ще включва тази серия. Това, което мога да ви кажа с голяма степен на увереност, е, че ще има няколко части. Вероятно повече от един и по-малко от 100. В бъдещи части ще се задълбоча в отделните типове изрази на именувани таблици, съображения за модификация, вградени аспекти, аспекти на подреждане, корелации и други.
В моите примери ще използвам примерна база данни, наречена TSQLV5. Тук можете да намерите скрипта, който създава и попълва тази база данни, както и нейната диаграма за ER тук.
Независимост на физическите данни
Физическата независимост на данните е принцип в релационната теория, който казва, че подробностите за физическата реализация трябва да бъдат скрити от или прозрачни за потребителя, подаващ заявките към системата за управление на релационната база данни. В заявките потребителите трябва да се съсредоточат върху какво те трябва да използват логически операции, които се основават на релационна алгебра, за разлика от как за получаване на данните. Те не трябва да се тревожат за това как данните са структурирани, достъпни и обработвани. Такива физически детайли за изпълнение обикновено се различават съществено при различните реализации (RDBMS продукти). Дори при една и съща RDBMS подробностите за физическата реализация понякога се променят между различните версии и компилации. Идеята зад принципа за независимост на физическите данни на теория е да се защитят инвестицията на потребителите чрез премахване на необходимостта от преразглеждане на вашите решения, когато надграждате вашата RDBMS до нова версия или дори когато мигрирате от една RDBMS към друга. Както вероятно добре знаете, на практика нещата не са толкова прости, но това е тема за различна дискусия.
Какво е маса?
Ако работите с T-SQL или друг диалект на SQL от известно време, вие развивате интуитивно разбиране за това какво е таблица. Проблемът е, че без известна основа на релационната теория, често интуитивното разбиране не е много точно. Една типична грешка е, че интуитивно сме склонни да се фокусираме върху детайлите за физическото изпълнение. Например, когато мислите какво е таблица, мислите ли за таблица като логическа структура (набор от редове) или мислите за подробности за физическото изпълнение в платформата, която използвате (в SQL Server , страници, екстенти, купчина срещу клъстериран индекс, неклъстерирани индекси и т.н.)? Като потребител, който пише SQL код за запитване на таблица, следвайки принципа на независимост на физическите данни, вие трябва да мислите за таблицата като за логическа структура и нека RDBMS да се тревожи за подробностите за физическата реализация. Така че, нека да направим крачка назад и да се опитаме да разберем какво е таблица.
Таблицата е аналог на SQL на основната структура в релационната теория - релация. За да опростя нещата и да огранича обхвата на моето покритие, няма да навлизам в разликата между релационна променлива и релационна стойност. Ако следвате моята препоръка и прочетете книгата на Date, много бързо ще имате ясна представа за подобни тънкости.
Връзката има заглавие и тяло.
Заглавието на релацията е набор на атрибути . В математическата теория на множествата множеството няма ред и няма дубликати. Трябва да идентифицирате атрибут по име, а не по някаква позиция. Следователно имената на атрибутите трябва да са уникални.
Можете ли да идентифицирате какво е аналогът на атрибут в SQL? Вероятно сте се досетили, че това е колона . Въпреки това, SQL всъщност има понятие за ред на своите колони въз основа на реда им на поява в оператора CREATE TABLE. Например, ето израза CREATE TABLE за таблицата Sales.Shippers в базата данни TSQLV5:
CREATE TABLE Sales.Shippers ( shipperid INT NOT NULL IDENTITY, companyname NVARCHAR(40) NOT NULL, phone NVARCHAR(24) NOT NULL, CONSTRAINT PK_Shippers PRIMARY KEY(shipperid) );
Направете заявка в таблицата, като използвате прословутия SELECT *
, така:
SELECT * FROM Sales.Shippers;
Когато изпълних тази заявка в моята система, получих следния изход:
shipperid companyname phone ---------- -------------- --------------- 1 Shipper GVSUA (503) 555-0137 2 Shipper ETYNR (425) 555-0136 3 Shipper ZHISN (415) 555-0138
SQL гарантира, че колоните ще бъдат върнати отляво надясно въз основа на реда на дефиниция. Скоро ще обясня какво се случва с редовете. SQL дори ви позволява да се позовавате на порядковата позиция на колоната от списъка SELECT в клаузата ORDER BY, така (не че аз препоръчвам тази практика, нито Аарон Бертран):
SELECT shipperid, companyname, phone FROM Sales.Shippers ORDER BY 2;
Тази заявка генерира следния изход:
shipperid companyname phone ---------- -------------- --------------- 2 Shipper ETYNR (425) 555-0136 1 Shipper GVSUA (503) 555-0137 3 Shipper ZHISN (415) 555-0138
Тялото на релация е набор от кортежи . Отново, припомнете си, че комплектът няма ред и дубликати. Следователно релацията трябва да има поне един кандидат ключ, който ви позволява да идентифицирате уникално кортеж. Двойникът на SQL на кортеж е ред . Въпреки това, в SQL не сте принудени да дефинирате ключ в таблица и ако не го направите, може да се окажете с дублиращи се редове. Дори ако имате дефиниран ключ във вашата таблица, можете да получите дублиращи се редове, върнати от заявка към таблицата. Ето един пример:
SELECT country FROM HR.Employees;
Тази заявка генерира следния изход:
country -------- USA USA USA USA UK UK UK USA UK
Тази заявка не дава релационен резултат поради възможността за дублиране на редове. Докато релационната теория се основава на теорията на множеството, SQL се основава на теорията на множеството. Мултикомплект (известен още като супернабор или чанта) може да има дубликати. SQL ви дава инструмент за премахване на дубликати с клауза DISTINCT, както следва:
SELECT DISTINCT country FROM HR.Employees;
Тази заявка генерира следния изход:
country -------- UK USA
Това, което SQL поддържа от релационната теория по отношение на тялото на таблицата, е свойството no-order. Освен ако не добавите клауза ORDER BY в заявката, нямате никакви гаранции, че резултатът ще има конкретен ред между редовете. Така че тялото на горния резултат от заявка е релационен, поне в смисъл, че няма дубликати и няма гарантиран ред.
Да предположим, че правите заявка към таблица в SQL Server и не включвате клауза ORDER BY в заявката. Очаквате ли SQL Server винаги да връща редовете в определен ред като гарантирано поведение? Много хора го правят. Мнозина смятат, че винаги ще връщате редовете въз основа на клъстериран ред на индекси. Това е добър пример за пренебрегване на принципа за независимост на физическите данни и правене на предположения, базирани на интуиция и може би въз основа на минало наблюдавано поведение. Microsoft знае, че SQL заявка без клауза ORDER BY не гарантира никакъв ред между редовете с резултати и следователно дори ако на физическо ниво данните се намират в структура на индекс, SQL Server не трябва да обработва данните в индекса поръчка. То може да избере, при определени физически условия, да го направи, но може да избере да не го прави при други физически условия. Припомнете си също, че подробностите за физическата реализация могат да се променят между различните версии и компилации на продукта. Ако искате да гарантирате, че заявката ще върне редовете с резултатите в определен ред, единственият ви начин да гарантирате това е да въведете клауза ORDER BY в най-външната заявка.
Както вероятно разбрахте, дизайнерите на SQL всъщност не виждат като приоритет да следват релационната теория. И това, което описах тук, са само няколко примера. Има още много. Както споменахме по-рано, целта ми в тази статия е просто да предоставя достатъчно от критичната теоретична основа, за да изчистя объркването около изразите на таблици, преди да започна да ровя в спецификата на T-SQL в бъдещи статии.
Какво е табличен израз?
Релационната алгебра (алгебрата, която дефинира операциите върху отношенията в релационната теория) има затваряне Имот. Това означава, че операцията върху отношенията води до връзка. Релационният оператор оперира с една или повече релации като вход и дава една релация като изход. Свойството за затваряне ви позволява да гнездите операции. релационен израз е израз, който оперира с релации и връща релация. Следователно може да се използва релационен израз, когато релационната алгебра очаква релация.
Ако се замислите, това не е по-различно от операциите с цели числа, които дават целочислен резултат. Да предположим, че променливата @i е целочислена променлива. Изразът @i + 42 дава цяло число и следователно може да се използва, където се очаква цяло число, както в (@i + 42) * 2.
Като се има предвид, че таблицата в SQL е аналог на релация в релационната теория, макар и не много успешна при това, табличният израз в SQL е двойникът на релационен израз. Както споменахме по-рано, използвам термина табличен израз след използването на този термин от C. J. Dates. SQL стандартът има множество объркващи термини, някои от които се опасявам, че не са много подходящи. Например, SQL стандартът използва термина израз на таблица, за да опише конкретно израз, базиран на клаузите за заявка, започващи със задължителна клауза FROM и включващи по избор клаузите WHERE, GROUP BY, HAVING и WINDOW (последната не се поддържа в T -SQL) и с изключение на клаузата SELECT. Ето спецификацията на стандарта:
7.4 <израз на таблица
Функция
Посочете таблица или групирана таблица.
Формат
<израз на таблица> ::=
<от клауза>
[ <клауза където> ]
[ <група по клауза> ]
[ <имаща клауза> ]
[ <клауза за прозорец> ]
Вярно е, че резултатът от това, което стандартът нарича табличен израз, се счита за таблица, но не можете да използвате такъв израз като самостоятелна заявка. Версията на датата на термина табличен израз всъщност е по-близка до това, което стандартът на SQL нарича израз на заявка . Ето спецификацията на стандарта за това, което той нарича израз на заявка:
7.17 <израз на заявка>
Функция
Посочете таблица.
Формат
<израз на заявка> ::=
[ <с клауза> ] <тело на израза на заявка>
[ <подреждане по клауза> ] [ <клауза за изместване на резултата> ] [ <извличане на първа клауза> ]
<с клауза> ::=
С [ РЕКУРСИВНО ] <със списък>
<със списък> ::=
<с елемент от списък> [ { <запетая> <с елемент от списък> }… ]
<с елемент от списък> ::=
<име на заявка> [ <ляво скоба> <със списък на колони> <дясна скоба> ]
AS <подзаявка на таблица> [ <клауза за търсене или цикъл> ]
<със списък на колони> ::=
<списък с имена на колона>
<тело на израза на заявката> ::=
<термин на заявка>
| <тело на израз на заявка> UNION [ ВСИЧКИ | РАЗЛИЧЕН ]
[ <съответстваща спецификация> ] <термин на заявка
| <тело на израз на заявка> ОСВЕН [ ВСИЧКИ | DISTINCT ]
[ <съответна спецификация> ] <термин на заявка>
<термин на заявка> ::=
<основна заявка>
| <термин на заявка> ПРЕСЕЧИ [ ВСИЧКИ | DISTINCT ]
[ <съответна спецификация> ] <основна заявка>
<основна заявка> ::=
<проста таблица>
| <ляво скоба> <тяло на израза на заявката>
[ <подреждане по клауза> ] [ <клауза за изместване на резултата> ] [ <извличане на първа клауза> ]
<дясна скоба>
<проста таблица> ::=
<заявка спецификация>
| <конструктор на стойност на таблицата
| <изрична таблица>
<изрична таблица> ::=
TABLE <име на таблица или заявка>
<съответна спецификация> ::=
CORRESPONDING [ BY <ляво скоба> <съответстващо списък с колони> <дясна скоба> ]
<съответен списък с колони> ::=
<списък с имена на колони>
<подреждане по клауза> ::=
ORDER BY <спецификация на сортиране списък>
<клауза за изместване на резултата> ::=
OFFSET <брой на изместените редове> { ROW | ROWS }
<извличане на първа клауза> ::=
FETCH { FIRST | СЛЕДВАЩ } [ <извличане на първо количество> ] { РЕД | РЕДОВЕ } {САМО | С ВРЪЗКИ }
<извличане на първо количество> ::=
<извличане на брой на първия ред>
| <извличане на първия процент>
<отместен брой редове> ::=
<спецификация на проста стойност>
<извличане на брой на първия ред> ::=
<спецификация на проста стойност>
<извличане на първи процент> ::=
<проста спецификация на стойност> PERCENT
7.3 <конструктор на стойност на таблица
Функция
Посочете набор от
Формат
<конструктор на стойност на таблицата> ::=
VALUES <списък с изрази за стойност на редове>
<списък с изрази за стойност на редове> ::=
<израз за стойност на редове в таблицата> [ { <запетая> <израз за стойност на ред в таблицата> }… ]
<конструктор на стойност на таблици с контекст> ::=
VALUES <списък с изрази със стойност на контекстно въведен ред>
<списък с изрази за стойности на контекстно въведен ред> ::=
<контекстно въведен израз за стойност на ред>
[ { <запетая> <контекстно въведен израз за стойност на ред> }… ]
Обърнете внимание, че тази спецификация включва това, което T-SQL нарича общ израз на таблица, въпреки че стандартът всъщност не използва този термин, а просто го нарича с елемент на списък . Също така имайте предвид, че така нареченият израз на заявка не трябва да се основава на заявка, а може да се основава на това, което се нарича конструктор на стойност на таблица (използването на клауза VALUES за изграждане на набор от редове). И накрая, въпреки че стандартният израз на заявка се основава на израз, той връща таблица и може да се използва там, където обикновено се очаква таблица. Поради тези причини намирам използването от Date на термина табличен израз за много по-подходящо.
Заключение
Виждам защо някои може да смятат, че спирането на именуването и терминологията е малко педантично и може би дори загуба на време. Чувствам се обаче много различно. Вярвам, че във всяка област стремежът към използване на собствени имена и терминология ви принуждава да изучавате добре основите и отразява знанията ви. С надеждата, че в тази статия не успях да ви отчуждам достатъчно, за да не искате да продължите към предстоящите части от поредицата, започвайки със статията от следващия месец, ще насоча вниманието си към начина, по който различните типове наименовани табличните изрази се обработват с T-SQL в SQL Server и Azure SQL база данни.