Syntaxe ms sql. Nastavení hodnot proměnných. Základní klauzule SQL: SELECT, FROM a WHERE

  • Překlad

Nestačí napsat kód, který je snadno čitelný: musí také běžet rychle.

Existují tři základní pravidla pro psaní kódu T-SQL, která budou dobře fungovat. Jsou kumulativní – dodržování všech těchto pravidel bude mít pozitivní dopad na kód. Vynechání nebo změna kteréhokoli z nich bude mít pravděpodobně negativní dopad na výkon vašeho kódu.

  • Zapisujte na základě struktury úložiště dat: pokud ukládáte data datetime, použijte datetime, nikoli varchar nebo cokoli jiného.
  • Pište s ohledem na indexy: Pokud má vaše tabulka indexy a měla by je mít, napište svůj kód, aby mohla tyto indexy plně využít. Ujistěte se, že seskupený index, ze kterého může být pouze jeden na tabulku, je používán nejúčinnějším způsobem.
  • Pište způsobem, který pomáhá optimalizátoru dotazů: Optimalizátor dotazů je skvělou součástí DBMS. Bohužel mu můžete velmi ztížit práci tím, že napíšete dotaz, který se mu bude „obtížně“ analyzovat, například obsahující vnořené pohledy – když jeden pohled přijímá data od druhého, nebo dokonce od třetího – a tak dále. Udělejte si čas, abyste pochopili, jak optimalizátor funguje, a pište dotazy tak, aby vám pomohl a neuškodil.
Je jich několik typické chyby věci, které lidé dělají ve svém T-SQL kódu – nedělejte je.

Používáte nesprávné datové typy

Teoreticky je vyvarování se této chyby velmi jednoduché, ale v praxi k ní dochází poměrně často. Například ve své databázi používáte nějaký datový typ. Použijte jej ve svých parametrech a proměnných! Ano, vím, že SQL Server může implicitně přetypovat jeden datový typ na jiný. Ale když se to stane implicitní konverze nebo sami přetypujete datový typ sloupce na jiný typ, provedete převod na celý sloupec. Když provedete tuto transformaci na sloupci v klauzuli WHERE nebo v podmínce spojení, vždy uvidíte prohledání tabulky. Na tomto sloupci lze vytvořit vynikající index, ale protože provádíte CAST na hodnotách uložených v tomto sloupci, abyste porovnali například datum uložené v tomto sloupci s typ char, který jste použili v podmínce, index nebude použit.

Nevěříš mi? Podívejme se na tento dotaz:

SELECT e.BusinessEntityID, e.NationalIDNumber FROM HumanResources.Employee AS e WHERE e.NationalIDNumber = 112457891;
Dobře napsané a velmi jednoduché. Musí být pokryta indexem vytvořeným v této tabulce. Ale tady je plán realizace:

Tento dotaz je dostatečně rychlý a tabulka je malá, takže ke skenování indexu jsou zapotřebí pouze čtyři čtení. Všimněte si malého vykřičníku v příkazu SELECT. Když se podíváme na jeho vlastnosti, uvidíme:

Právo. Toto je upozornění (nové v SQL Server 2012), že probíhá převod typu, který ovlivňuje plán provádění. Stručně řečeno, je to proto, že požadavek používá nesprávný datový typ:

SELECT e.BusinessEntityID, e.NationalIDNumber FROM HumanResources.Employee AS e WHERE e.NationalIDNumber = "112457891";
A dostaneme tento plán provádění dotazu:

A zde jsou použity pouze dvě operace čtení místo čtyř. A ano, chápu, že jsem již rychle provádějící dotaz trochu zrychlil. Co by se ale stalo, kdyby v tabulce byly uloženy miliony řádků? Jo, pak bych se stal hrdinou.

Použití správné typy data.

Použití funkcí v podmínkách spojení a klauzulích WHERE

Když už mluvíme o funkcích - většina funkcí používaných v podmínkách spojení nebo klauzulích WHERE, kterým předáváte sloupec jako argument, zasahuje správné použití indexy. Uvidíte, jak pomalejší jsou dotazy při použití funkcí, které berou sloupce jako argumenty. Zde je příklad:

SELECT a.AddressLine1, a.AddressLine2, a.City, a.StateProvinceID FROM Person.Address AS a WHERE "4444" = LEFT(a.AddressLine1, 4) ;
Tato funkce, VLEVO, bere sloupec jako argument, což má za následek tento plán provádění:

Výsledkem je 316 čtení k nalezení požadovaných dat a to trvá 9 milisekund (mám velmi rychlé disky). Je to proto, že '4444' musí být porovnáno s každým řetězcem vráceným touto funkcí. SQL Server nemůže ani jen skenovat tabulku, potřebuje udělat LEVÝ na každém řádku. Můžete však udělat něco takového:

SELECT a.AddressLine1, a.AddressLine2, a.City, a.StateProvinceID FROM Person.Address AS a WHERE a.AddressLine1 LIKE "4444%" ;
A nyní vidíme úplně jiný plán provádění:

Dotaz vyžaduje 3 čtení a 0 milisekund k dokončení. No, nebo ať je to 1 milisekunda, pro objektivitu. To je obrovský nárůst výkonu. A to vše proto, že jsem použil funkci, kterou lze použít k vyhledávání podle indexu (dříve se tomu říkalo sargeable - obecně nepřeložitelné slovo: SARG – Search Arguments –able, pokud je funkce SARGeable – můžete jí předat sloupec jako argument a index Seek bude stále použit, pokud ne SARGeable – bohužel, Index Scan bude vždy použité - cca. překladatel). V žádném případě nepoužívejte funkce v klauzulích WHERE nebo podmínkách vyhledávání nebo používejte pouze ty, které lze použít v podmínkách vyhledávání v indexu.

Použití UDF s více příkazy

Vícepříkazové UDF v ruském vydání msdn je přeloženo přibližně jako „Uživatelsky definované funkce skládající se z několika instrukcí, ale to zní podle mého názoru nějak zvláštně, takže v názvu a dále v textu jsem se snažil vyhnout překládání tohoto termín - cca. překladatel

V podstatě vás chytají do pasti. Na první pohled nám tento úžasný mechanismus umožňuje používat T-SQL jako skutečný programovací jazyk. Můžete vytvořit tyto funkce a volat je jedna od druhé a kód lze znovu použít, ne jako tyto staré uložené procedury. To je úžasné. Dokud se nepokusíte spustit tento kód na velkém množství dat.

Problém těchto funkcí je, že jsou postaveny na tabulkových proměnných. Proměnné tabulky jsou velmi skvělá věc, pokud je používáte k zamýšlenému účelu. Mají jeden jasný rozdíl z dočasných tabulek – statistiky na nich nejsou postavené. Tento rozdíl může být velmi užitečný, nebo vás může... zabít. Pokud nemáte statistiku, optimalizátor předpokládá, že jakýkoli dotaz provedený na proměnnou tabulky nebo UDF vrátí pouze jeden řádek. Jeden (1) řádek. To je v pořádku, pokud skutečně vrátí více řádků. Ale jednoho dne vrátí stovky nebo tisíce řádků a vy se rozhodnete připojit jeden UDF k druhému... Výkon klesne velmi, velmi rychle a velmi, velmi silně.

Příklad je poměrně velký. Zde jsou některé UDF:

CREATE FUNCTION dbo.SalesInfo () VRÁTÍ @return_variable TABLE (SalesOrderID INT, OrderDate DATETIME, SalesPersonID INT, PurchaseOrderNumber dbo.OrderNumber, AccountNumber dbo.AccountNumber, ShippingCity30)CHAR
INTO AS soh JOIN Person. Adresa AS a ON soh.ShipToAddressID = a.AddressID ;

NÁVRAT;
KONEC; GO CREATE FUNCTION dbo.SalesDetails () VRACÍ @return_variable TABLE (SalesOrderID INT, SalesOrderDetailID INT, OrderQty SMALLINT, UnitPrice MONEY) JAKO ZAČÁTEK;

INSERT INTO @return_variable (SalesOrderID, SalesOrderDetailId, OrderQty, UnitPrice) SELECT sod.SalesOrderID, sod.SalesOrderDetailID, sod.OrderQty, sod.UnitPrice FROM Sales.SalesOrderDetail AS sod ;

SELECT deqp.query_plan, dest.text, SUBSTRING(cíl.text, (deqs.statement_start_offset / 2) + 1, (deqs.statement_end_offset - deqs.statement_start_offset) / 2 + 1) AS skutečný příkaz FROM sys.dm_exec_CRO_stats ASsys.dm_exec_CRO .dm_exec_query_plan(deqs.plan_handle) AS deqp CROSS APPLY sys.dm_exec_sql_text(deqs.sql_handle) AS dest WHERE deqp.objectid = OBJECT_ID("dbo.CombinedSalesInfo");
A tady je to, co se tam skutečně děje:

Páni, vypadá to, že se tady skrývá několik dalších malých funkcí a skenů tabulek, které téměř, ale ne tak docela, nestojí za nic. Plus operátor spojení Hash Match, který zapisuje do tempdb a jeho spuštění je značné náklady. Podívejme se na plán provádění dalšího UDF:

Zde! A nyní vidíme Clustered Index Scan, který skenuje velký počet linky. Už to není skvělé. Obecně se v celé této situaci jeví UDF stále méně atraktivní. Co kdybychom, no, já nevím, zkusíme získat přímý přístup k tabulkám. Například takto:

SELECT soh.OrderDate, soh.PurchaseOrderNumber, soh.AccountNumber, sod.OrderQty, sod.UnitPrice FROM Sales.SalesOrderHeader AS soh JOIN Sales.SalesOrderDetail AS sod ON soh.Sales.ObjednávkaIDOsobaNa sod.Adresa ID = ba.ID_Adresy JOIN Person.Address AS sa ON soh.ShipToAddressID = sa.AddressID WHERE soh.SalesPersonID = 277 AND sa.City = "Odessa" ;
Nyní spuštěním tohoto dotazu získáme přesně stejná data, ale za pouhých 310 milisekund místo 2170. Navíc SQL Server provede pouze 911 čtení namísto 1456. Upřímně řečeno, je velmi snadné získat problémy s výkonem pomocí UDF

Povolení nastavení Work Faster: Using Dirty Reads

Když se vrátíme do minulosti, ke starým počítačům s 286 procesory na palubě, můžeme si vzpomenout, že z mnoha důvodů měly na předním panelu tlačítko „Turbo“. Pokud jste jej omylem „vymáčkli“, počítač se okamžitě začal šíleně zpomalovat. Takže chápete, že některé věci by měly být vždy zapnuté, aby bylo zajištěno maximum propustnost. Podobně se mnoho lidí dívá na úroveň izolace READ_UNCOMMITTED a nápovědu NO_LOCK jako na turbo tlačítko pro SQL Server. Při jejich používání si buďte jisti, že téměř jakýkoli dotaz a celý systém jako celek se zrychlí. To je způsobeno tím, že během čtení nebudou aplikovány ani kontrolovány žádné zámky. Méně blokování - rychlejší výsledek. Ale…

Když ve svých dotazech použijete READ_UNCOMMITTED nebo NO_LOCK, skončíte se špinavými čteními. Každý chápe, že to znamená, že můžete číst „pes“ spíše než „kočka“, pokud operace aktualizace probíhá, ale ještě není dokončena. Můžete však také skončit s více či méně řádky, než ve skutečnosti máte, a také s duplicitními řádky, protože stránky s daty se mohou během běhu dotazu pohybovat a vy neumisťujete žádné zámky, abyste tomu zabránili. Nevím jak vy, ale ve většině společností, pro které jsem pracoval, bylo toto očekávání většina dotazy na většině systémů vrátí konzistentní data. Stejný dotaz se stejnými parametry, provedený na stejné sadě dat, by měl poskytnout stejný výsledek. Ne, pokud používáte NO_LOCK. Abyste se o tom ujistili, doporučuji vám přečíst si tento příspěvek.

Nerozumné používání nápověd v dotazech

Lidé jsou příliš rychlí na to, aby se rozhodli používat rady. Nejběžnější situace je, když nápověda pomůže vyřešit velmi vzácný problém na jednom z požadavků. Ale když lidé vidí u tohoto dotazu výrazný nárůst výkonu... okamžitě to začnou všude tlačit.

Mnoho lidí například věří, že LOOP JOIN je nejlepší způsob stůl se připojí. Docházejí k tomuto závěru, protože se nejčastěji vyskytuje v malých, rychlých dotazech. Rozhodnou se tedy donutit SQL Server používat LOOP JOIN. Není to vůbec těžké:

SELECT s. AS Název obchodu, p.Příjmení + ", " + p.Jméno Z Prodeje.Obchod AS s PŘIPOJIT SE k prodeji.SalesPerson AS sp ON s.SalesPersonID = sp.ID BusinessEntity PŘIPOJIT SE .Person AS p ON e.BusinessEntityID = VOLBA p.BusinessEntityID (LOOP JOIN);
Tento dotaz běží 101 milisekund a provede 4115 čtení. Obecně to není špatné, ale pokud tuto nápovědu odstraníme, stejný dotaz se provede za 90 milisekund a vytvoří pouze 2370 čtení. Čím více je systém zatížen, tím zřetelnější bude efektivita požadavku bez použití nápovědy.

Zde je další příklad. Lidé často vytvářejí index na tabulce v očekávání, že vyřeší problém. Máme tedy dotaz:

SELECT * FROM Purchasing.PurchaseOrderHeader AS poh WHERE poh.PurchaseOrderID * 2 = 3400;
Problém je opět v tom, že když provedete transformaci sloupců, nebude adekvátně použit žádný index. Výkon se snižuje, protože je skenován seskupený index. Když tedy lidé uvidí, že jejich index není používán, udělají toto:

SELECT * FROM Purchasing.PurchaseOrderHeader AS poh WITH (INDEX (PK_PurchaseOrderHeader_PurchaseOrderID)) WHERE poh.PurchaseOrderID * 2 = 3400;
A teď dostanou sken svého zvoleného indexu, ne toho seskupeného, ​​takže index je "v provozu", že? Mění se ale výkon dotazu - nyní se místo 11 operací čtení provádí 44 (doba provedení u obou je asi 0 milisekund, protože mám opravdu rychlé disky). „K použití“ znamená, že se používá, ale vůbec ne tak, jak bylo zamýšleno. Řešením tohoto problému je přepsat dotaz takto:

SELECT * FROM Purchasing.PurchaseOrderHeader poh WHERE PurchaseOrderID = 3400 / 2;
Nyní počet přečtení klesl na dvě, protože je použito vyhledávání indexu - index je použit správně.

Rady v dotazech by měly být vždy použity jako poslední, po všech ostatních. možné možnosti byly testovány a neposkytly pozitivní výsledek.

Použití zpracování „Row by Agonizing Row“.

Zpracování po řádcích se provádí pomocí kurzorů nebo operací ve smyčce WHILE namísto operací na množinách. Při jejich použití je produktivita velmi, velmi nízká. Kurzory se běžně používají ze dvou důvodů. První z nich jsou vývojáři, kteří jsou zvyklí používat ve svém kódu zpracování po řádcích, a druzí vývojáři pocházející z Oracle, kteří si myslí, že kurzory jsou dobrá věc. Ať už je důvod jakýkoli, kurzory jsou zabijákem produktivity.

Zde je typický příklad neúspěšné použití kurzor. Potřebujeme aktualizovat barvu produktů vybraných podle určitého kritéria. Není to vymyšlené – je to založeno na kódu, který jsem kdysi musel optimalizovat.

ZAČÍT TRANSAKCI DECLARE @Name NVARCHAR(50) , @Color NVARCHAR(15) , @Weight DECIMAL(8, 2) DECLARE BigUpdate CURSOR FOR SELECT str. ,str.Barva ,str. Z Výroba.Produkt AS p ; OTEVŘÍT BigUpdate ; FETCH NEXT Z BigUpdate INTO @Name, @Color, @Weight ; WHILE @@FETCH_STATUS = 0 BEGIN IF @Weight< 3 BEGIN UPDATE Production.Product SET Color = "Blue" WHERE CURRENT OF BigUpdate END FETCH NEXT FROM BigUpdate INTO @Name, @Color, @Weight ; END CLOSE BigUpdate ; DEALLOCATE BigUpdate ; SELECT * FROM Production.Product AS p WHERE Color = "Blue" ; ROLLBACK TRANSACTION
V každé iteraci provedeme dvě operace čtení a počet produktů, které splňují naše kritéria, se pohybuje ve stovkách. Na mém počítači bez zátěže je doba provádění delší než sekunda. To je zcela nepřijatelné, zejména proto, že je velmi jednoduché tento dotaz přepsat:

ZAČÁTEK AKTUALIZACE TRANSAKCE Production.SADA PRODUKTŮ Barva = "MODRÁ" KDE< 3 ; ROLLBACK TRANSACTION
Nyní se provede pouze 15 čtení a doba provedení je pouze 1 milisekunda. Nesměj se. Lidé často píší kód takto a ještě hůř. Kurzory jsou něco, čemu je třeba se vyhnout a používat je pouze tam, kde se bez nich neobejdete – například při údržbě, kdy potřebujete „proběhnout“ různé tabulky nebo databáze.

Nevhodné použití vnořených pohledů

Pohledy odkazující na pohledy připojující se k pohledům odkazující na jiné pohledy připojující se k pohledům... Pohled je pouze dotaz. Ale protože s nimi lze zacházet jako s tabulkami, lidé je mohou začít považovat za tabulky. Ale marně. Co se stane, když propojíte jeden pohled s druhým, propojíte se s třetím pohledem a tak dále? Právě vytváříte zatraceně komplikovaný plán dotazů. Optimalizátor se to pokusí zjednodušit. Vyzkouší plány, které nevyužívají všechny tabulky, ale čas na práci na výběru plánu je omezený a čím složitější plán dostane, tím menší je pravděpodobnost, že skončí u docela jednoduchého plánu realizace. A problémy s výkonem budou téměř nevyhnutelné.

Zde je například sekvence jednoduchých dotazů, které definují pohledy:

VYTVOŘIT ZOBRAZENÍ dbo.SalesInfoView AS SELECT soh.SalesOrderID, soh.OrderDate, soh.SalesPersonID, soh.PurchaseOrderNumber, soh.AccountNumber, a.City AS ShippingCity OD Sales.SalesOrderJHeader ASh.Header AShIDsoAd. .AddressID ; CREATE VIEW dbo.SalesDetailsView AS SELECT sod.SalesOrderID, sod.SalesOrderDetailID, sod.OrderQty, sod.UnitPrice FROM Sales.SalesOrderDetail AS sod ; VYTVOŘIT ZOBRAZENÍ dbo.CombinedSalesInfoView AS SELECT si.SalesPersonID, si.ShippingCity, si.OrderDate, si.PurchaseOrderNumber, si.AccountNumber, sd.OrderQty, sd.UnitPrice OD dbo ASSalesViewbo.Stail.SalesViewboSales rderID = sd.SalesOrderID;
A zde autor textu zapomněl uvést požadavek, ale uvádí jej v komentářích (poznámka překladatele):
SELECT csi.OrderDate FROM dbo. CominedSalesInfoView csi WHERE csi.SalesPersonID = 277
Výsledkem je, že dokončení našeho dotazu trvá 155 milisekund a používá 965 čtení. Zde je jeho plán provedení:

Vypadá to dobře, zvláště když máme 7000 řádků, takže se zdá být vše v pořádku. Ale co když se pokusíme spustit dotaz takto:

SELECT soh.OrderDate FROM Sales.SalesOrderHeader AS soh WHERE soh.SalesPersonID = 277 ;
Nyní dotaz běží za 3 milisekundy a používá 685 čtení - docela rozdíl. A zde je jeho plán realizace:

Jak vidíte, optimalizátor nemůže vyhodit všechny nadbytečné tabulky jako součást procesu zjednodušení dotazu. Proto jsou v prvním prováděcím plánu dvě operace navíc – Index Scan a Hash Match, které shromažďují data dohromady. Napsáním tohoto dotazu bez použití zobrazení můžete SQL Serveru ušetřit nějakou práci navíc. A pamatujte - tento příklad je velmi jednoduchý, většina dotazů v skutečný život mnohem obtížnější a vede k mnohému velké problémy produktivita.

V komentářích k tomuto článku je malý spor, jehož podstatou je, že Grant (autor článku) zřejmě neprovedl své dotazy na standardní databázi AdventureWorks, ale na podobnou databázi, ale s trochu jinou struktura, což je důvod, proč je plán provádění „suboptimální“ “ dotaz uvedený v poslední sekce, se liší od toho, co můžete vidět při provádění experimentu sami. Poznámka překladatel
Pokud jsem někde byl příliš jazykový (a to mohu být) a text je těžko srozumitelný, případně mi můžete nabídnout lepší znění čehokoli, rád si vyslechnu všechny komentáře.

V prvním díle jsme se již trochu dotkli jazyka DML, a to pomocí téměř celé sady jeho příkazů, s výjimkou příkazu MERGE.

O DML budu hovořit podle své vlastní posloupnosti, vyvinuté z osobní zkušenosti. Po cestě se také pokusím mluvit o „kluzkých“ místech, na která stojí za to se zaměřit;

Protože učebnice je věnována do širokého kruhučtenářů (nejen programátorů), pak bude vysvětlení někdy vhodné, tzn. dlouhé a nudné. To je moje vize materiálu, který jsem získal především v praxi jako výsledek odborné činnosti.

Hlavním cílem tohoto tutoriálu, krok za krokem, je rozvinout úplné pochopení podstaty jazyka SQL a naučit vás, jak správně aplikovat jeho konstrukce. Prolistování tohoto materiálu by mohlo zajímat i profesionály v této oblasti, možná se budou moci dozvědět něco nového pro sebe, nebo možná bude jen užitečné si jej přečíst, aby si osvěžili paměť. Doufám, že to bude pro každého zajímavé.

Protože DML v dialektu databáze MS SQL velmi úzce souvisí se syntaxí konstruktu SELECT, takže o DML začnu mluvit s ním. Podle mého názoru je konstrukt SELECT nejdůležitějším konstruktem v jazyce DML, protože díky němu nebo jeho částem jsou potřebná data načtena z databáze.

Jazyk DML obsahuje následující konstrukce:

  • SELECT – výběr dat
  • INSERT – vložení nových údajů
  • UPDATE – aktualizace dat
  • DELETE – smazání dat
  • MERGE – slučování dat

V této části se budeme zabývat pouze základní syntaxí SELECT příkazy který vypadá takto:

SELECT seznam_sloupců nebo * FROM zdroj WHERE filtr ORDER BY řazení_výrazu
Téma příkazu SELECT je velmi široké, proto se v této části zaměřím pouze na jeho základní konstrukty. Věřím, že bez znalosti základů nemůžete začít studovat složitější struktury, protože pak se vše bude točit kolem tohoto základního designu (poddotazy, spojení atd.).

Také v rámci tohoto dílu budu mluvit i o TOP nabídce. Záměrně jsem tuto větu neuvedl v základní syntaxi, protože... je implementován odlišně v různých dialektech SQL.

Pokud je jazyk DDL více statický, tzn. s jeho pomocí se vytvářejí rigidní struktury (tabulky, vztahy atd.), pak je jazyk DML dynamický, zde můžete různými způsoby získat správné výsledky.

Trénink bude pokračovat i v režimu Krok za krokem, tzn. Při čtení byste se měli okamžitě pokusit dokončit příklad vlastníma rukama. Poté analyzujete získaný výsledek a snažíte se jej intuitivně pochopit. Zůstane-li něco nejasné, například význam funkce, obraťte se o pomoc na internet.

Příklady budou ukázány v databázi Test, která byla vytvořena pomocí DDL+DML v první části.

Pro ty, kteří nevytvářeli databázi v první části (protože ne každého může zajímat jazyk DDL), mohou použít následující skript:

Testovací skript pro vytvoření databáze

Vytvoření databáze CREATE DATABASE Test GO -- nastavte testovací databázi jako aktuální USE Test GO -- vytvořte referenční tabulky CREATE TABLE Positions(ID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_Positions PRIMARY KEY, Name nvarchar(30) NOT NULL) CREATE TABLE Oddělení (ID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_Departments PRIMÁRNÍ KLÍČ, Název nvarchar(30) NOT NULL) GO -- vyplňte referenční tabulky daty SET IDENTITY_INSERT Pozice ON INSERT Pozice(ID,Název)VALUES (1, N"Účetní" ), (2,N"Ředitel"), (3,N"Programátor"), (4,N"Senior programátor") SET IDENTITY_INSERT Pozice OFF GO SET IDENTITY_INSERT Oddělení ZAPNUTO Oddělení (ID,Jméno)VALUES (1,N "Administrace"), (2,N"Účetnictví"), (3,N"IT") NASTAVIT IDENTITY_INSERT Oddělení OFF GO -- vytvořit tabulku se zaměstnanci CREATE TABLE Zaměstnanci(ID int NOT NULL, Name nvarchar( 30), datum narození , e-mail nvarchar(30), PositionID int, DepartmentID int, datum náboru NOT NULL CONSTRAINT DF_Employees_HireDate DEFAULT SYSDATETIME(), ManagerID int, CONSTRAINT PK_Employees PRIMARY KEY (ID), CONSTRAINT CONSTRAINTDepart FKEImGNSTRAINTDepart S oddělení( ID), TRAINT FK_Employees_PositionID CIZÍ KLÍČ(ID pozice) REFERENCES Pozice(ID), OMEZENÍ FK_Employees_ManagerID CIZÍ KLÍČ (ID manažera) REFERENCES Zaměstnanci(ID), CONSTRAINT UQ_Employees_Email BETIDINCHEEmail(e-mail) CONSTRAINT_CONTRAINCKy1 00 A 1999), INDEX IDX_Emplo yes_Name (Jméno)) GO - - vyplňte jej údaji INSERT Zaměstnanci (ID,Jméno,Narozeniny,E-mail,ID pozice,ID oddělení,ID manažera)VALUES (1000,N"Ivanov I.I.","19550219"," [e-mail chráněný]",2,1,NULL), (1001,N"Petrov P.P.","19831203"," [e-mail chráněný]",3,3,1003), (1002,N"Sidorov S.S.","19760607"," [e-mail chráněný]",1,2,1000), (1003,N"Andreev A.A.","19820417"," [e-mail chráněný]",4,3,1000)

To je vše, nyní jsme připraveni začít se učit jazyk DML.

SELECT – operátor výběru dat

Nejprve pro aktivní editor dotazů udělejme test aktuální databáze výběrem z rozevíracího seznamu nebo pomocí příkazu „USE Test“.

Začněme nejzákladnější formou SELECT:

VYBERTE * OD zaměstnanců
V tomto dotazu požadujeme vrátit všechny sloupce (označené "*") z tabulky Zaměstnanci - můžete to číst jako "VYBRAT všechna_pole Z tabulky zaměstnanců." Pokud existuje seskupený index, budou vrácená data s největší pravděpodobností řazena podle něj, v tomto případě podle sloupce ID (to ale není důležité, protože ve většině případů si řazení explicitně určíme sami pomocí ORDER BY ...) :

ID Jméno Narozeniny E-mail ID pozice ID oddělení Datum pronájmu ManagerID
1000 Ivanov I.I. 1955-02-19 [e-mail chráněný] 2 1 2015-04-08 NULL
1001 Petrov P.P. 1983-12-03 [e-mail chráněný] 3 3 2015-04-08 1003
1002 Sidorov S.S. 1976-06-07 [e-mail chráněný] 1 2 2015-04-08 1000
1003 Andreev A.A. 1982-04-17 [e-mail chráněný] 4 3 2015-04-08 1000

Obecně stojí za to říci, že v dialektu MS SQL nejjednodušší forma SELECT dotazu nemusí obsahovat blok FROM, v takovém případě jej můžete použít k získání některých hodnot:

SELECT 5550/100*15, SYSDATETIME(), -- získání databázového systému data SIN(0)+COS(0)

(Žádný název sloupce) (Žádný název sloupce) (Žádný název sloupce)
825 2015-04-11 12:12:36.0406743 1

Vezměte prosím na vědomí, že výraz (5550/100*15) dal výsledek 825, i když pokud počítáme na kalkulačce, bude hodnota (832,5). Výsledek 825 byl získán z toho důvodu, že v našem výrazu jsou všechna čísla celá čísla, proto je výsledkem celé číslo, tzn. (5550/100) nám dává 55, nikoli (55,5).

Pamatujte, že v MS SQL funguje následující logika:

  • Celek / Celek = Celek (tj. v tomto případě existuje celočíselné dělení)
  • Skutečné / Celé číslo = Skutečné
  • Celé číslo / Skutečné = Skutečné
Tito. výsledek se převede na větší typ, takže v posledních 2 případech dostaneme reálné číslo (myšleno jako v matematice - rozsah reálná čísla je větší než rozsah celých čísel, takže výsledek se převede na něj):

SELECT 123/10, -- 12 123./10, -- 12,3 123/10. -- 12.3
Zde (123.) = (123.0) jde jen o to, že v tomto případě lze zahodit 0 a ponechat pouze bod.

Stejná logika platí pro ostatní aritmetické operace, ale v případě dělení je tato nuance relevantnější.

Pozor tedy na datový typ číselné sloupce. Pokud je to celé číslo a potřebujete získat skutečný výsledek, použijte transformaci nebo jednoduše vložte tečku za číslo označené jako konstanta (123.).

K převodu polí můžete použít funkci CAST nebo CONVERT. Použijme například pole ID, je typu int:

SELECT ID, ID/100, -- zde dojde k dělení celým číslem CAST(ID AS float)/100, -- pomocí funkce CAST převedete na typ float CONVERT(float,ID)/100, -- použijete funkci CONVERT převést na typ float ID/100. -- použijte transformaci zadáním, že jmenovatelem je skutečné číslo OD Zaměstnanců

ID (Žádný název sloupce) (Žádný název sloupce) (Žádný název sloupce) (Žádný název sloupce)
1000 10 10 10 10.000000
1001 10 10.01 10.01 10.010000
1002 10 10.02 10.02 10.020000
1003 10 10.03 10.03 10.030000

Jen poznámka. V databázi ORACLE je syntaxe bez bloku FROM nepřijatelná, k tomuto účelu se používá systémová tabulka DUAL, která obsahuje jeden řádek:

SELECT 5550/100*15, -- a v ORACLE bude výsledek roven 832,5 sysdate, sin(0)+cos(0) FROM DUAL


Poznámka. Před názvem tabulky v mnoha RDB může předcházet název schématu:

SELECT * FROM dbo.Employees -- dbo – název schématu

Schéma je logická jednotka databáze, která má své jméno a umožňuje v sobě seskupovat databázové objekty, jako jsou tabulky, pohledy atd.

Definice schématu v různých databázích se může v některých případech lišit, schéma přímo souvisí s uživatelem databáze, tzn. v tomto případě můžeme říci, že schéma a uživatel jsou synonyma a všechny objekty vytvořené ve schématu jsou v podstatě objekty daný uživatel. V M.S. SQL schéma je nezávislá logická jednotka, kterou lze vytvořit samostatně (viz VYTVOŘENÍ SCHÉMATU).

Standardně se v databázi MS SQL vytvoří jedno schéma s názvem dbo (Database Owner) a je to. vytvořené objekty ve výchozím nastavení jsou vytvořeny v tomto schématu. Pokud tedy jednoduše zadáme název tabulky v dotazu, bude prohledávána ve schématu dbo aktuální databáze. Pokud chceme vytvořit objekt v konkrétním schématu, budeme muset před název objektu přidat název schématu, například „CREATE TABLE název_schématu.název_tabulky(...)“.

V případě MS SQL může před názvem schématu také předcházet název databáze, ve které se schéma nachází:

SELECT * FROM Test.dbo.Employees -- název_databáze.název_schematu.tabulka
Toto objasnění může být užitečné, například pokud:

  • v jednom požadavku přistupujeme k objektům umístěným v různých schématech nebo databázích
  • potřebujete přenést data z jednoho schématu nebo databáze do jiného
  • pokud jste v jedné databázi, musíte si vyžádat data z jiné databáze
  • atd.
Schéma je velmi pohodlný nástroj, který je užitečné použít při vývoji databázové architektury, zejména velkých databází.

Nezapomeňte také, že v textu požadavku můžeme použít jak jednořádkové komentáře „-- ...“, tak víceřádkové „/* ... */“. Pokud je požadavek velký a složitý, pak komentáře mohou vám nebo někomu jinému po nějaké době velmi pomoci zapamatovat si nebo pochopit jeho strukturu.

Pokud je v tabulce mnoho sloupců a zejména pokud je v tabulce stále mnoho řádků, plus pokud provádíme dotazy do databáze přes síť, pak by bylo vhodnější vybrat s přímým výpisem pole, která potřebujete, oddělená čárkami:

SELECT ID,Jméno FROM Zaměstnanci

Tito. zde říkáme, že potřebujeme vrátit pouze pole ID a Name z tabulky. Výsledek bude následující (mimochodem, optimalizátor se zde rozhodl použít index vytvořený polem Name):

ID Jméno
1003 Andreev A.A.
1000 Ivanov I.I.
1001 Petrov P.P.
1002 Sidorov S.S.

Jen poznámka. Někdy může být užitečné podívat se, jak se data načítají, například zjistit, které indexy se používají. To lze provést kliknutím na tlačítko „Zobrazit odhadovaný plán provedení“ nebo nastavením „Zahrnout skutečný plán provedení“ (v tomto případě budeme moci vidět skutečný plán, respektive až po provedení požadavku):

Analýza prováděcího plánu je velmi užitečná při optimalizaci dotazu, umožňuje zjistit, které indexy chybí nebo které indexy nejsou vůbec použity a lze je odstranit.

Pokud jste se právě začali učit DML, pak už to pro vás není tak důležité, vezměte to na vědomí a můžete na to klidně zapomenout (možná to nikdy nebudete potřebovat) – naším prvotním cílem je naučit se základy jazyka DML a naučit se je správně používat a optimalizace je již samostatným uměním. Někdy je důležitější, abyste měli jednoduše správně napsaný dotaz, který vrací správný výsledek z hlediska předmětu, a jednotliví lidé jej již optimalizují. Nejprve se musíte naučit, jak jednoduše správně psát dotazy, pomocí jakýchkoli prostředků k dosažení cíle. Hlavním cílem, kterého nyní musíte dosáhnout, je, aby váš dotaz vrátil správné výsledky.

Nastavení aliasů tabulek

Při výpisu sloupců jim může předcházet název tabulky umístěné v bloku FROM:

SELECT Employees.ID,Employees.Name FROM Employees

Ale použití této syntaxe je obvykle nepohodlné, protože název tabulky může být dlouhý. Pro tyto účely se obvykle uvádějí a používají kratší názvy - aliasy:

VYBERTE ID zam., jméno zam. FROM Zaměstnanci JAKO zam
nebo

SELECT emp.ID,emp.Name FROM Zaměstnanci emp -- klíčové slovo AS lze uvolnit (preferuji tuto možnost)

Zde emp je alias pro tabulku Zaměstnanci, který lze použít v kontextu tohoto příkazu SELECT. Tito. můžeme říci, že v kontextu tohoto příkazu SELECT dáváme tabulce nový název.

Samozřejmě, že v tomto případě budou výsledky dotazu přesně stejné jako pro „SELECT ID, Name FROM Employees“. Proč je to potřeba, bude jasné později (ani v této části), zatím jen připomeňme, že před názvem sloupce může být (objasněno) buď přímo název tabulky, nebo pomocí aliasu. Zde můžete použít jednu ze dvou věcí, tzn. Pokud nastavíte alias, budete jej muset použít, ale nemůžete již používat název tabulky.

Jen poznámka. V ORACLE je povolena pouze možnost zadat alias tabulky bez klíčového slova AS.

DISTINCT – zahození duplicitních řádků

Klíčové slovo DISTINCT se používá k vyřazení duplicitních řádků z výsledku dotazu. Zhruba řečeno, představte si, že nejprve provedete dotaz bez možnosti DISTINCT a poté z výsledku zahodíte všechny duplikáty. Ukažme si to pro větší názornost na příkladu:

Vytvořme dočasnou tabulku pro demonstraci CREATE TABLE #Trash(ID int NOT NULL PRIMARY KEY, Col1 varchar(10), Col2 varchar(10), Col3 varchar(10)) - vyplnit tento stůl všechny druhy odpadků INSERT #Trash(ID,Sloupec1,Sloupec2,Sloupec3)HODNOTY (1,"A","A","A"), (2,"A","B","C"), ( 3, "C", "A","B"), (4,"A","A","B"), (5,"B","B","B"), (6, "A ","A","B"), (7,"A","A","A"), (8,"C","A","B"), (9,"C ", "A","B"), (10,"A","A","B"), (11,"A",NULL,"B"), (12,"A",NULL, "B") -- podívejme se, co dotaz vrátí bez možnosti DISTINCT SELECT Col1,Col2,Col3 FROM #Trash -- podívejme se, co dotaz vrátí s volbou DISTINCT SELECT DISTINCT Col1,Col2,Col3 FROM #Trash -- smazat dočasnou tabulku DROP TABLE #Trash

Vizuálně to bude vypadat takto (všechny duplikáty jsou označeny stejnou barvou):

Nyní se podívejme, kde to lze použít, na praktičtějším příkladu - vrátíme se pouze jedinečné identifikátory oddělení (tzn. zjistíme ID oddělení, ve kterých jsou zaměstnanci registrováni):

VYBERTE DISTINCT ID oddělení OD zaměstnanců

Tady máme 4 řádky, protože... V naší tabulce nejsou žádné opakující se kombinace (DepartmentID, PositionID).

Vraťme se na chvíli k DDL.

Protože nám začínají docházet data pro ukázkové příklady a chceme mluvit obšírněji a jasněji, rozšiřme trochu naši tabulku Zaměstnanci. Kromě toho si připomeňme trochu DDL, jak se říká, „opakování je matka učení“ a plus, pojďme znovu trochu poskočit a použít příkaz UPDATE:

Vytváříme nové sloupce ALTER TABLE Zaměstnanci PŘIDAT Příjmení nvarchar(30), -- příjmení Jméno nvarchar(30), -- jméno Prostřední jméno nvarchar(30), -- prostřední jméno Plovoucí plat, -- a samozřejmě plat v některých jednotkách BonusPercent float -- procento pro výpočet bonusu ze mzdy GO -- vyplňte je údaji (některé údaje jsou záměrně vynechány) AKTUALIZACE Zaměstnanci SET Příjmení=N"Ivanov", Jméno=N"Ivan", Prostřední jméno=N"Ivanovich", Plat=5000,BonusPercent= 50 KDE ID=1000 -- Ivanov I.I. AKTUALIZACE Zaměstnanci SET Příjmení=N"Petrov",Jméno=N"Petr",MiddleName=N"Petrovich", Plat=1500,BonusPercent= 15 WHERE ID=1001 -- Petrov P.P. AKTUALIZACE Zaměstnanci SET Příjmení=N"Sidor",Jméno=N"Sidor",MiddleName=NULL, Plat=2500,BonusPercent=NULL WHERE ID=1002 -- Sidorov S.S. AKTUALIZACE Zaměstnanci SET Příjmení=N"Andreev",Jméno=N"Andrey",MiddleName=NULL, Plat=2000,BonusPercent= 30 WHERE ID=1003 -- Andreev A.A.

Ujistíme se, že data byla úspěšně aktualizována:

VYBERTE * OD zaměstnanců

ID Jméno Příjmení Jméno Prostřední jméno Plat Bonusové procento
1000 Ivanov I.I. Ivanov Ivane Ivanovič 5000 50
1001 Petrov P.P. Petrov Petr Petrovič 1500 15
1002 Sidorov S.S. Sidorov Sidor NULL 2500 NULL
1003 Andreev A.A. Andrejev Andrey NULL 2000 30

Nastavení aliasů pro sloupce dotazu

Myslím, že zde bude jednodušší ukázat, než napsat:

SELECT -- zadejte název vypočítanému sloupci Příjmení+" "+Jméno+" "+MiddleName AS Celé jméno, -- použijte dvojité uvozovky, protože se používá mezera HireDate AS "Datum přijetí", -- použití hranatých závorek, protože místo je využito Narozeniny AS [ Datum narození], -- slovo AS není nutné Mzda ZP OD Zaměstn

Celé jméno Datum přijetí Datum narození ZP
Ivanov Ivan Ivanovič 2015-04-08 1955-02-19 5000
Petrov Petr Petrovič 2015-04-08 1983-12-03 1500
NULL 2015-04-08 1976-06-07 2500
NULL 2015-04-08 1982-04-17 2000

Jak vidíme, námi zadané aliasy sloupců se projeví v záhlaví výsledné tabulky. Ve skutečnosti je to hlavní účel aliasů sloupců.

Vezměte prosím na vědomí, protože poslední 2 zaměstnanci neměli zadané prostřední jméno (hodnota NULL), pak nám výsledek výrazu „Příjmení+“ „+Jméno+“ „+MiddleName“ také vrátil NULL.

Pro spojení (přidání, zřetězení) řetězců v MS SQL se používá symbol „+“.

Pamatujte, že všechny výrazy, které obsahují hodnotu NULL (například dělení hodnotou NULL, sčítání s hodnotou NULL), vrátí hodnotu NULL.

Jen poznámka.
V případě ORACLE se ke zřetězení řetězců používá operátor „||“. a zřetězení by vypadalo jako "Příjmení||" "||Jméno||" "||MiddleName". Pro ORACLE stojí za zmínku, že má výjimku pro typy řetězců, pro ně jsou NULL a prázdný řetězec "" to samé, takže v ORACLE se takový výraz vrátí pro poslední 2 zaměstnance "Sidor Sidor" a "Andrey Andrejev“. V době ORACLE 12c, pokud vím, neexistuje žádná možnost, která by toto chování změnila (pokud se mýlím, opravte mě). Tady je pro mě těžké posoudit, jestli je to dobře nebo špatně, protože... V některých případech je chování NULL řetězce pohodlnější, jako v MS SQL, a v jiných, jako v ORACLE.

V ORACLE jsou také platné všechny aliasy sloupců uvedené výše, kromě [...].


Abychom neoplotili stavbu pomocí funkce ISNULL, v MS SQL můžeme použít funkci CONCAT. Zvažme a porovnejme 3 možnosti:

SELECT LastName+" "+FirstName+" "+MiddleName FullName1, -- 2 možnosti pro nahrazení NULL prázdnéřádky "" (dostaneme chování jako v ORACLE) ISNULL(Příjmení,"")+" "+ISNULL(Jméno,"")+" "+ISNULL(MiddleName,"") CeléJméno2, CONCAT(Příjmení," ", Jméno ," ",MiddleName) CeléJméno3 OD Zaměstnanců

Celé jméno1 Celé jméno2 Celé jméno3
Ivanov Ivan Ivanovič Ivanov Ivan Ivanovič Ivanov Ivan Ivanovič
Petrov Petr Petrovič Petrov Petr Petrovič Petrov Petr Petrovič
NULL Sidorov Sidor Sidorov Sidor
NULL Andrejev Andrej Andrejev Andrej

V MS SQL lze aliasy zadat také pomocí rovnítka:

SELECT "Datum přijetí"=Datum přijetí, -- kromě "..." a […] můžete použít "..." [Datum narození]=Narozeniny, ZP=Plat OD zaměstnanců

Použití klíčového slova AS nebo rovnítka k určení aliasu je pravděpodobně spíše věcí vkusu. Ale při analýze požadavků jiných lidí mohou být tyto znalosti užitečné.

Nakonec řeknu, že je lepší nastavit jména pro aliasy pouze pomocí latinských znaků a čísel, vyhnout se použití „…“, „…“ a […], tedy použít stejná pravidla, která jsme použili při pojmenovávání tabulek. . Dále v příkladech budu používat pouze taková jména a žádné „…“, „…“ a […].

Základní SQL aritmetické operátory


Priorita provádění aritmetických operátorů je stejná jako v matematice. V případě potřeby lze změnit pořadí aplikace operátorů pomocí závorek - (a+b)*(x/(y-z)).

A ještě jednou zopakuji, že jakákoli operace s NULL vygeneruje NULL, například: 10+NULL, NULL*15/3, 100/NULL - z toho všeho bude NULL. Tito. jednoduše řečeno, nedefinovaná hodnota nemůže přinést jednoznačný výsledek. Vezměte to v úvahu při sestavování dotazu a v případě potřeby zpracujte hodnoty NULL pomocí funkcí ISNULL a COALESCE:

SELECT ID,Jméno, Plat/100*BonusPercent AS Výsledek1, -- bez zpracování hodnot NULL ​​Mzda/100*ISNULL(BonusPercent,0) AS Výsledek2, -- použijte funkci ISNULL Plat/100*COALESCE(BonusPercent,0) AS Výsledek3 - - použijte funkci COALESCE FROM Zaměstnanců

Řeknu vám něco o funkci COALESCE:

COALESCE (expr1, expr2, ..., exprn) - Vrátí první neNULL hodnotu ze seznamu hodnot.

SELECT COALESCE(f1, f1*f2, f2*f3) val -- v tomto případě bude vrácena třetí hodnota FROM (SELECT null f1, 2 f2, 3 f3) q

Většinou se zaměřím na povídání o konstrukcích DML a z větší části nebudu mluvit o funkcích, které se objeví v příkladech. Pokud nerozumíte, co konkrétní funkce dělá, vyhledejte si její popis na internetu, můžete dokonce vyhledávat informace podle skupiny funkcí najednou, například dotazem v vyhledávání Google"PANÍ. SQL řetězce funkce", "Matematické funkce MS SQL" nebo "MS SQL funkce NULL zpracování." Existuje mnoho informací o funkcích a můžete je snadno najít. Například v knihovně MSDN se můžete dozvědět více o funkci COALESCE:

Výstřižek z MSDN Srovnání COALESCE a CASE

Výraz COALESCE je syntaktická zkratka pro výraz CASE. To znamená, že kód COALESCE(výraz1,...n) je přepsán optimalizátorem dotazů jako další výraz VĚC:

CASE WHEN (výraz1 NENÍ NULL) THEN výraz1 WHEN (výraz2 NENÍ NULL) THEN výraz2 ... ELSE výrazN END

Podívejme se například, jak můžete použít zbytek dělení (%). Tento operátor velmi užitečné, když potřebujete rozdělit záznamy do skupin. Vytáhněte například všechny zaměstnance, kteří mají sudá osobní čísla (ID), tzn. ta ID, která jsou dělitelná 2:

VYBERTE ID,Jméno FROM Zaměstnanci WHERE ID%2=0 -- zbytek po vydělení 2 je 0

ORDER BY – řazení výsledku dotazu

Klauzule ORDER BY se používá k řazení výsledku dotazu.

VYBERTE Příjmení, Jméno, Plat OD zaměstnanců ORDER BY LastName,FirstName -- výsledek seřaďte podle 2 sloupců - podle příjmení a poté podle jména

Pro poznámku. Existuje klíčové slovo ASC pro řazení ve vzestupném pořadí, ale protože vzestupné řazení je výchozí, můžete na tuto možnost zapomenout (nepamatuji si, kdy jsem tuto možnost použil).

Stojí za zmínku, že v doložka ORDER BY lze použít i pro pole, která nejsou uvedena v klauzuli SELECT (kromě případu, kdy je použit DISTINCT, kterému se budu věnovat níže). Jako příklad trochu předběhnu pomocí možnosti TOP a ukážu, jak si například můžete vybrat 3 zaměstnance, kteří mají nejvyšší plat, s ohledem na to, že z důvodu zachování důvěrnosti bych neměl ukazovat samotný plat:

SELECT TOP 3 -- vrátit pouze první 3 záznamy z celého výsledku ID,Příjmení,Jméno FROM Zaměstnanci ORDER BY Plat DESC -- seřadit výsledek v sestupném pořadí Plat

ID Příjmení Jméno
1000 Ivanov Ivane
1002 Sidorov Sidor

Samozřejmě zde nastává případ, že více zaměstnanců může mít stejný plat a je těžké říci, kterým třem zaměstnancům se tento požadavek vrátí, to je nutné řešit s vedoucím úkolu. Řekněme, že po projednání tohoto úkolu s vedoucím jste souhlasili a rozhodli jste se využít následující možnost - provést dodatečné třídění podle pole data narození (tj. vážíme si mladých lidí), a pokud se datum narození více zaměstnanců může shodovat (ostatně to také není vyloučeno), pak můžete provést třetí řazení v sestupném pořadí hodnot ID (poslední ve vzorku budou ti s nejvyšším ID - například ti, kteří byli přijati jako poslední, řekněme personální čísla jsou vydávána postupně):

SELECT TOP 3 -- vrátit pouze první 3 záznamy z celého výsledku ID,Příjmení,Jméno FROM Zaměstnanci ORDER BY Plat DESC, -- 1. Seřadit výsledek v sestupném pořadí podle Narozeniny platu, -- 2. poté podle Datum narození ID DESC -- 3 a pro úplnou přehlednost výsledku přidáváme řazení podle ID.

Tito. měli byste se snažit, aby byl výsledek žádosti předvídatelný, abyste v případě debriefingu mohli vysvětlit, proč byli tito konkrétní lidé zařazeni na „černou listinu“, tzn. vše bylo vybráno poctivě, podle stanovených pravidel.

Můžete také třídit pomocí různých výrazů v klauzuli ORDER BY:

SELECT LastName,FirstName FROM Zaměstnanci ORDER BY CONCAT(LastName," ",FirstName) -- použijte výraz

Můžete také použít aliasy určené pro sloupce v ORDER BY:

SELECT CONCAT(LastName," ",FirstName) fi FROM Zaměstnanci ORDER BY fi -- použijte alias

Stojí za zmínku, že při použití klauzule DISTINCT lze v klauzuli ORDER BY použít pouze sloupce uvedené v bloku SELECT. Tito. po aplikaci operace DISTINCT dostaneme nová sada data s novou sadou sloupců. Z tohoto důvodu nebude následující příklad fungovat:

SELECT DISTINCT Příjmení,Jméno,Plat OD Zaměstnanci ORDER BY ID -- ID není ve výsledné sadě, kterou jsme získali pomocí DISTINCT

Tito. klauzule ORDER BY je aplikována na výslednou sadu předtím, než je výsledek vrácen uživateli.

Poznámka 1. Můžete také použít čísla sloupců uvedených v SELECT v klauzuli ORDER BY:

VYBERTE Příjmení,Jméno,Plat FROM Zaměstnanci ORDER BY -- řazení v pořadí 3 DESC, -- 1. sestupně Plat 1, -- 2. podle příjmení 2 -- 3. podle jména

Pro začátečníky to vypadá pohodlně a lákavě, ale je lepší zapomenout a nikdy tuto možnost třídění nepoužívat.

Pokud je v tomto případě (když jsou pole explicitně uvedena), tato možnost stále přijatelná, pak v případě použití „*“ je lepší tuto možnost nikdy nepoužívat. Proč - protože pokud někdo například změní pořadí sloupců v tabulce, nebo sloupce smaže (a to je normální situace), váš dotaz může stále fungovat, ale špatně, protože řazení již lze provádět podle jiných sloupců a to je záludné v tom, že tato chyba nemusí být odhalena velmi brzy.

Pokud by byly sloupce explicitně uvedeny, pak by ve výše uvedené situaci dotaz buď nadále fungoval, ale také správně (protože je vše explicitně definováno), nebo by jednoduše vyhodilo chybu, že tento sloupec neexistuje.

Na řazení podle čísel sloupců tak můžete klidně zapomenout.

Poznámka 2
V MS SQL při řazení ve vzestupném pořadí hodnoty NULL se zobrazí jako první.

VYBERTE procento bonusu OD zaměstnanců OBJEDNEJTE PODLE procenta bonusu

Při použití DESC tedy budou na konci

VYBERTE procento bonusu OD zaměstnanců OBJEDNEJTE PODLE BonusPercent DESC

Pokud potřebujete změnit logiku pro řazení hodnot NULL, použijte výrazy, například:

VYBERTE procento bonusu od zaměstnanců ORDER BY ISNULL(procento bonusu,100)

ORACLE poskytuje pro tento účel dvě možnosti: NULLS FIRST a NULLS LAST (používá se ve výchozím nastavení). Například:

VYBERTE procento bonusu OD zaměstnanců OBJEDNEJTE PODLE BonusPercent DESC NULLS LAST

Věnujte tomu pozornost při přechodu na konkrétní databázi.

TOP – vrátí zadaný počet záznamů

Výpis z MSDN. TOP – Omezuje počet řádků vrácených v sadě výsledků dotazu na zadaný počet nebo procento. Když je klauzule TOP použita ve spojení s klauzulí ORDER BY, je výsledná sada omezena na prvních N řádků seřazeného výsledku. V opačném případě bude prvních N řádků vráceno v nespecifikovaném pořadí.

Obvykle se tento výraz používá s klauzulí ORDER BY a již jsme se podívali na příklady, kdy bylo nutné vrátit prvních N řádků z výsledné sady.

Obvykle bez ORDER BY tento návrh používá se, když se potřebujeme jen podívat na nám neznámou tabulku, která může mít hodně záznamů, v tomto případě můžeme například požádat o vrácení pouze prvních 10 řádků, ale pro přehlednost řekneme jen 2:

VYBERTE NEJLEPŠÍ 2 * ZE ZAMĚSTNANCŮ

Můžete také zadat slovo PERCENT, abyste vrátili odpovídající procento řádků ze sady výsledků:

VYBERTE NEJLEPŠÍCH 25 PROCENT * ZE ZAMĚSTNANCŮ

V mé praxi se nejčastěji používá vzorkování podle počtu řádků.

Můžete také použít možnost S TIES s TOP, která pomůže vrátit všechny řádky v případě nejednoznačného řazení, tzn. tato věta vrátí všechny řádky, které se svým složením shodují s řádky, které spadají do výběru TOP N, v důsledku toho lze vybrat více než N řádků pro demonstraci.

INSERT Zaměstnanci(ID,Jméno,E-mail,ID pozice,ID oddělení,ID manažera,Plat) VALUES(1004,N"Nikolaev N.N."," [e-mail chráněný]",3,3,1003,1500)

A přidáme dalšího zaměstnance bez uvedení pozice a oddělení s platem 2000:

INSERT Zaměstnanci(ID,Jméno,E-mail,ID pozice,ID oddělení,ID manažera,Plat) VALUES(1005,N"Alexandrov A.A."," [e-mail chráněný]",NULL,NULL,1000,2000)

Nyní vybereme pomocí možnosti S VAZBAMI všechny zaměstnance, jejichž mzda se shoduje s platy 3 zaměstnanců, s nejnižší mzdou (doufám, že bude dále jasné, o co mi jde):

VYBERTE NEJLEPŠÍ 3 S VAZBAMI ID,Jméno,Mzda OD Zaměstnanců OBJEDNÁVKA PODLE Mzd

Zde, ačkoli je uvedeno TOP 3, požadavek vrátil 4 záznamy, protože hodnota platu, která vrátila TOP 3 (1500 a 2000) byla zjištěna u 4 zaměstnanců. Vizuálně to funguje asi takto:

Jen poznámka.
TOP je implementován v různých databázích různými způsoby, v MySQL je na to klauzule LIMIT, ve které lze dodatečně nastavit počáteční offset.

V ORACLE 12c také představili svůj vlastní analog, kombinující funkcionalitu TOP a LIMIT - hledejte slova „ORACLE OFFSET FETCH“. Před verzí 12c se pro tento účel obvykle používal pseudosloupec ROWNUM.


Co se stane, když použijete klauzule DISTINCT a TOP současně? Takové otázky lze snadno zodpovědět prováděním experimentů. Obecně se nebojte a nebuďte líní experimentovat, protože... Většina se toho naučí praxí. Slovosled v příkazu SELECT je následující: DISTINCT je na prvním místě, následuje TOP, tzn. Pokud uvažujete logicky a čtete zleva doprava, použije se první, kdo zahodí duplikáty, a poté se na základě této sady vytvoří TOP. No, podívejme se a ujistěte se, že je to tento případ:

VYBERTE ODLIŠIT TOP 2 Mzda OD Zaměstnanců ŘADÍTE PODLE Mzd

Plat
1500
2000

Tito. v důsledku toho jsme dostali 2 nejmenší platy ze všech. Samozřejmě může nastat případ, že mzda u některých zaměstnanců nemusí být uvedena (NULL), protože Schéma nám to umožňuje. Proto se v závislosti na úloze rozhodneme buď zpracovat hodnoty NULL v klauzuli ORDER BY, nebo jednoduše vyřadit všechny záznamy, pro které je Plat NULL, a za tímto účelem přistoupíme ke studiu klauzule WHERE.

KDE – podmínka výběru řádku

Tato věta slouží k filtrování záznamů podle dané podmínky. Vyberme například všechny zaměstnance pracující v oddělení „IT“ (jeho ID=3):

VYBERTE ID,Příjmení,Jméno,Plat od zaměstnanců WHERE DepartmentID=3 -- IT ORDER BY LastName,FirstName

ID Příjmení Jméno Plat
1004 NULL NULL 1500
1003 Andrejev Andrey 2000
1001 Petrov Petr 1500

Klauzule WHERE se zapisuje před příkaz ORDER BY.

Pořadí použití příkazů na počáteční sadu Zaměstnanci je následující:

  1. KDE – pokud je zadáno, pak prvním krokem z celé množiny zaměstnanců je vybrat pouze záznamy, které splňují podmínku
  2. DISTINCT – pokud je zadáno, všechny duplikáty jsou zahozeny
  3. ORDER BY – pokud je zadáno, je výsledek seřazen
  4. TOP – pokud je zadáno, z setříděného výsledku se vrátí pouze zadaný počet záznamů

Pro názornost se podívejme na příklad:

VYBERTE DISTINCT TOP 1 Mzda OD Zaměstnanců KDE ID oddělení=3 OBJEDNAT PODLE Mzdy

Vizuálně to bude vypadat takto:

Za zmínku stojí, že kontrola NULL se neprovádí se znaménkem rovná se, ale pomocí operátorů IS NULL a IS NOT NULL. Pamatujte, že nemůžete porovnávat hodnotu NULL pomocí operátoru „=“ (rovná se), protože výsledek výrazu bude také roven NULL.

Vyberme například všechny zaměstnance, kteří nemají zadané oddělení (tj. DepartmentID IS NULL):

VYBERTE ID,Jméno FROM Zaměstnanci WHERE DepartmentID JE NULL

Nyní jako příklad vypočítejme bonus pro všechny zaměstnance, kteří mají zadanou hodnotu BonusPercent (tj. BonusPercent NENÍ NULL):

VYBERTE ID,Jméno,Plat/100*Procento bonusu JAKO bonus OD ZAMĚSTNANCŮ, KDE NENÍ procento bonusu NULL

Ano, mimochodem, pokud se nad tím zamyslíte, hodnota BonusPercent se může rovnat nule (0) a hodnotu lze zadat i se znaménkem mínus, protože jsme tomuto poli neuložili žádná omezení.

Když jsme o problému řekli, bylo nám prozatím řečeno, abychom zvážili, že pokud (BonusPercent<=0 или BonusPercent IS NULL), то это означает что у сотрудника так же нет бонуса. Для начала, как нам сказали, так и сделаем, реализуем это при помощи логического оператора OR и NOT:

VYBERTE ID,Jméno,Plat/100*Procento bonusu JAKO bonus OD ZAMĚSTNANCŮ, KDE NE (BonusPercent<=0 OR BonusPercent IS NULL)

Tito. Zde jsme se začali učit o booleovských operátorech. Výraz v závorkách „(BonusPercent<=0 OR BonusPercent IS NULL)» проверяет на то что у сотрудника нет бонуса, а NOT инвертирует это значение, т.е. говорит «верни всех сотрудников которые не сотрудники у которых нет бонуса».

Tento výraz lze také přepsat tak, že okamžitě řeknete „vrátit všechny zaměstnance, kteří mají bonus“ tím, že to vyjádříte výrazem (BonusPercent>0 a BonusPercent NENÍ NULL):

VYBERTE ID,Jméno,Plat/100*Procento bonusu JAKO bonus OD zaměstnanců, KDE BonusPercent>0 A BonusPercent NENÍ NULL

Také v bloku WHERE můžete kontrolovat různé druhy výrazů pomocí aritmetických operátorů a funkcí. Podobnou kontrolu lze například provést pomocí výrazu s funkcí ISNULL:

VYBERTE ID,Jméno,Plat/100*Procento bonusu JAKO Bonus OD zaměstnanců WHERE ISNULL(BonusPercent,0)>0

Booleovské operátory a jednoduché porovnávací operátory

Ano, bez matematiky to nejde, tak to udělejme malá exkurze pomocí booleovských a jednoduchých porovnávacích operátorů.

Booleovské operátory v jazyk SQL pouze 3 – A, NEBO a NE:

Pro každý booleovský operátor můžete poskytnout pravdivostní tabulky, které navíc ukazují, jaký bude výsledek, když podmínky mohou být NULL:

Existují následující jednoduché operátory srovnání, která se používají k vytváření podmínek:

Navíc existují 2 operátory pro kontrolu hodnoty/výrazu pro NULL:

JE NULL Testování rovnosti NULL
NENÍ NULL Testování NULL nerovnosti

Priorita: 1) Všechny operátory porovnání; 2) NE; 3) AND; 4) NEBO.

Při konstrukci složitých logických výrazů se používají závorky:

((podmínka1 AND podmínka2) NEBO NE(podmínka3 AND podmínka4 AND podmínka5)) NEBO (…)

Pomocí závorek můžete také změnit standardní posloupnost výpočtů.

Zde jsem se pokusil poskytnout představu o Booleově algebře v objemu dostatečném pro práci. Jak vidíte, pro psaní složitějších podmínek se bez logiky neobejdete, ale moc jí tu není (AND, OR a NE) a vymysleli ji lidé, takže je vše celkem logické.

Pojďme na konec druhého dílu

Jak vidíte, i o základní syntaxi operátoru SELECT můžeme mluvit velmi dlouho, ale abychom zůstali v rozsahu článku, ukážu nakonec další logické operátory– MEZI, V A LIKE.

BETWEEN – kontrola zařazení do rozsahu

Test_value BETWEEN počáteční_hodnota A koncová_hodnota

Výrazy mohou fungovat jako hodnoty.

Podívejme se na příklad:

VYBERTE ID,Jméno,Plat od zaměstnanců, KDE Mzda MEZI 2000 A 3000 -- kdo má plat v rozmezí 2000-3000

BETWEEN je ve skutečnosti zjednodušený zápis formuláře:

VYBERTE ID,Jméno,Plat od zaměstnanců WHERE Plat>=2000 A Plat<=3000 -- все у кого ЗП в диапозоне 2000-3000

Slovo NOT lze použít před slovem BETWEEN, které zkontroluje, zda hodnota není v určeném rozsahu:

VYBERTE ID,Jméno,Plat OD Zaměstn<=3000)

Pokud tedy použijete BETWEEN, IN, LIKE, můžete je také kombinovat s dalšími podmínkami pomocí AND a OR:

VYBERTE ID,Jméno,Plat OD Zaměstnanci WHERE Plat MEZI 2000 A 3000 -- kdo má plat v rozmezí 2000-3000 A DepartmentID=3 -- zohledněte pouze zaměstnance oddělení 3

IN – kontrola zařazení do seznamu hodnot

Tento operátor má následující tvar:

Test_value IN (hodnota1, hodnota2, ...)

Myslím, že je jednodušší ukázat na příkladu:

SELECT ID,Jméno,Mzda FROM Zaměstnanci WHERE PositionID IN(3,4) -- jejichž pozice je 3 nebo 4

Tito. to je v podstatě stejné jako následující výraz:

SELECT ID,Jméno,Plat od zaměstnanců WHERE PositionID=3 OR PositionID=4 – jejichž pozice je 3 nebo 4

V případě NOT to bude podobné (dostaneme všechny kromě těch z oddělení 3 a 4):

VYBERTE ID,Jméno,Plat od zaměstnanců WHERE PositionID NOT IN(3,4) -- podobné jako NOT(PositionID=3 OR PositionID=4)

Dotaz s NOT IN lze také vyjádřit pomocí AND:

VYBERTE ID,Jméno,Plat od zaměstnanců WHERE PositionID<>3AND PositionID<>4 – ekvivalentní PositionID NOT IN(3,4)

Upozorňujeme, že hledání hodnot NULL pomocí konstrukce IN nebude fungovat, protože kontrola NULL=NULL také vrátí NULL, nikoli True:

SELECT ID,Name,DepartmentID FROM Zaměstnanci WHERE DepartmentID IN(1,2,NULL) -- NULL záznamy nebudou zahrnuty do výsledku

V tomto případě rozdělte kontrolu na několik podmínek:

SELECT ID,Name,DepartmentID FROM Zaměstnanci WHERE DepartmentID IN(1,2) -- 1 nebo 2 OR DepartmentID IS NULL -- or NULL

Nebo můžete napsat něco jako:

SELECT ID,Name,DepartmentID FROM Zaměstnanci WHERE ISNULL(DepartmentID,-1) IN(1,2,-1) -- pokud jste si jisti, že neexistuje žádné oddělení s ID=-1

Myslím, že v tomto případě bude správnější a spolehlivější první možnost. Dobře, toto je jen příklad pro demonstraci toho, jaké další stavby lze postavit.

Za zmínku také stojí ještě zákeřnější chyba spojená s NULL, kterou lze udělat při použití konstruktu NOT IN. Zkusme například vybrat všechny zaměstnance kromě těch, jejichž oddělení je 1 nebo jejichž oddělení není uvedeno vůbec, tzn. rovná se NULL. Jako řešení se nabízí následující možnost:

VYBERTE ID,Jméno,ID oddělení FROM Zaměstnanci WHERE DepartmentID NOT IN(1,NULL)

Po provedení dotazu však neobdržíme jediný řádek, ačkoli jsme očekávali, že uvidíme následující:

Vtip zde opět zahrál NULL zadaný v seznamu hodnot.

Podívejme se, proč v tomto případě došlo k logické chybě. Rozšiřme dotaz pomocí AND:

VYBERTE ID,Jméno,ID oddělení FROM Zaměstnanci WHERE ID oddělení<>1 AND ID oddělení<>NULL -- problém je kvůli této kontrole NULL - tato podmínka vždy vrátí hodnotu NULL

Správný stav (ID oddělení<>NULL) nám zde vždy poskytne nejistotu, tzn. NULL. Nyní si zapamatujte pravdivostní tabulku pro operátor AND, kde (TRUE AND NULL) dává NULL. Tito. když je splněna levá podmínka (DepartmentID<>1) kvůli nedefinované správné podmínce skončíme s nedefinovanou hodnotou pro celý výraz (DepartmentID<>1 AND ID oddělení<>NULL), takže řetězec nebude zahrnut do výsledku.

Podmínku lze správně přepsat takto:

VYBERTE ID,Jméno,ID oddělení FROM Zaměstnanci, KDE NENÍ ID oddělení V(1) -- nebo v tomto případě pouze ID oddělení<>1 AND DepartmentID NENÍ NULL -- a samostatně zkontrolujte NOT NULL

IN lze také použít s poddotazy, ale k tomuto formuláři se vrátíme v dalších částech tohoto tutoriálu.

LIKE – kontrola řetězce pomocí vzoru

O tomto operátoru budu mluvit pouze v jeho nejjednodušší podobě, která je standardem a je podporována většinou dialektů jazyka SQL. I v této podobě jej lze použít k řešení mnoha problémů, které vyžadují kontrolu obsahu řetězce.

Tento operátor má následující tvar:

Testovací_řetězec LIKE vzor_řetězce

V „řetězec_vzoru“ lze použít následující speciální znaky:

  1. Podtržítko „_“ znamená, že jeho místo může zaujmout jakýkoli jednotlivý znak
  2. Znak procenta „%“ – říká, že jej lze nahradit libovolným počtem znaků, včetně žádných
Podívejme se na příklady se symbolem „%“ (v praxi se mimochodem používá častěji):

SELECT ID,Jméno FROM Zaměstnanci WHERE Jméno LIKE "Pet%" -- jehož jméno začíná písmeny "Pet" SELECT ID,LastName FROM Zaměstnanci WHERE Příjmení LIKE "%ov" -- jehož příjmení končí "ov" SELECT ID, Příjmení FROM Zaměstnanci WHERE Příjmení LIKE "%re%" -- jejichž příjmení obsahuje kombinaci "re"

Podívejme se na příklady se symbolem „_“:

SELECT ID,Příjmení FROM Zaměstnanci WHERE Příjmení LIKE "_etrov" -- jehož příjmení se skládá z libovolného prvního znaku a následujících písmen "etrov" SELECT ID,Příjmení FROM Zaměstnanci WHERE Příjmení LIKE "____ov" -- jehož příjmení se skládá z libovolných čtyř znaků a následující písmena "ov"

Pomocí ESCAPE můžete zadat znak escape, který zruší kontrolní efekt speciálních znaků "_" a "%". Tato klauzule se používá, když chcete přímo zkontrolovat znak procenta nebo podtržítko v řetězci.

Abychom předvedli ESCAPE, vložme odpadky do jednoho záznamu:

UPDATE Employees SET FirstName="Toto je koš obsahující %" WHERE ID=1005

A podívejme se, co vrátí následující dotazy:

SELECT * FROM Zaměstnanci WHERE Jméno LIKE "%!%%" ESCAPE "!" -- řádek obsahuje znak "%" SELECT * FROM Zaměstnanci WHERE Jméno LIKE "%!_%" ESCAPE "!" -- řádek obsahuje znak "_".

Pokud potřebujete zkontrolovat řetězec pro úplnou shodu, pak místo LIKE je lepší jednoduše použít znak „=“:

SELECT * FROM Zaměstnanci WHERE FirstName="Peter"

Jen poznámka.
V MS SQL si v šabloně operátoru LIKE můžete určit i hledání pomocí regulárních výrazů, přečtěte si o tom na internetu, pokud vám standardní možnosti tohoto operátoru nestačí.

ORACLE používá funkci REGEXP_LIKE k vyhledávání pomocí regulárních výrazů.

Něco málo o strunách

V případě kontroly řetězce na přítomnost znaků Unicode budete muset před uvozovky umístit znak N, tzn. N"…". Ale protože všechna pole znaků v naší tabulce jsou ve formátu Unicode (typ nvarchar), můžete pro tato pole vždy použít tento formát. Příklad:

SELECT ID,Jméno FROM Zaměstnanci WHERE Jméno LIKE N"Pet%" SELECT ID,Příjmení FROM Zaměstnanci WHERE Příjmení=N"Petrov"

Když to uděláte správně, při porovnávání s polem typu varchar (ASCII), měli byste zkusit použít testy pomocí "..." a při porovnávání pole s typem nvarchar (Unicode), měli byste zkusit použít testy pomocí N" ......". To se provádí, aby se zabránilo implicitním převodům typů během provádění dotazu. Stejné pravidlo používáme při vkládání (INSERT) hodnot do pole nebo jejich aktualizaci (UPDATE).

Při porovnávání řetězců stojí za zvážení toho, že v závislosti na nastavení databáze (kolování) může být porovnávání řetězců buď bez ohledu na malá a velká písmena (když "Petrov" = "PETROV"), nebo rozlišuje malá a velká písmena (když "Petrov"<>"PETROV").
V případě nastavení citlivého na velká a malá písmena, pokud chcete provést vyhledávání bez ohledu na malá a velká písmena, můžete například předběžně převést pravý a levý výraz na jeden případ – horní nebo dolní:

SELECT ID,Jméno FROM Zaměstnanci WHERE UPPER(Jméno) LIKE UPPER(N"Pet%") -- nebo LOWER(Jméno) LIKE LOWER(N"Pet%") SELECT ID,LastName FROM Zaměstnanci WHERE UPPER(LastName)=UPPER( N"Petrov") -- nebo LOWER(Příjmení)=LOWER(N"Petrov")

Něco málo o datech

Při kontrole data můžete použít, stejně jako u řetězců, jednoduché uvozovky „...“.

Bez ohledu na místní nastavení v MS SQL můžete použít následující syntaxi data "RRRRMMDD" (rok, měsíc, den společně bez mezer). MS SQL bude vždy rozumět tomuto formátu data:

VYBERTE ID,Jméno,Narozeniny FROM Zaměstnanci WHERE Birthday BETWEEN "19800101" A "19891231" -- zaměstnanci 80. let OBJEDNAT PODLE NAROZENÍ

V některých případech je výhodnější nastavit datum pomocí funkce DATEFROMPARTS:

VYBERTE ID,Jméno,Narozeniny FROM Zaměstnanci WHERE Birthday BETWEEN DATEFROMPARTS(1980,1,1) A DATEFROMPARTS(1989,12,31) OBJEDNAT DLE NAROZENÍ

Existuje také podobná funkce DATETIMEFROMPARTS, která slouží k nastavení Date a Time (pro typ datetime).

Funkci CONVERT můžete také použít, pokud potřebujete převést řetězec na hodnotu data nebo datetime:

SELECT CONVERT(datum,"12.03.2015"104); CONVERT(datumčas,"2014-11-30 17:20:15"120)

Hodnoty 104 a 120 udávají, který formát data je v řetězci použit. Popis všech platných formátů v knihovně MSDN naleznete vyhledáním „MS SQL CONVERT“.

V MS SQL je spousta funkcí pro práci s daty, hledejte „ms sql funkce pro práci s daty“.

Poznámka. Všechny dialekty jazyka SQL mají vlastní sadu funkcí pro práci s daty a uplatňují vlastní přístup k práci s nimi.

Něco málo o číslech a jejich proměnách

Informace v této části budou pravděpodobně užitečnější pro IT specialisty. Pokud nejste jedním z nich a vaším cílem je jednoduše naučit se psát dotazy, abyste získali informace, které potřebujete z databáze, pak možná nebudete potřebovat takové jemnosti, ale v každém případě můžete rychle procházet text a dělat si poznámky , protože . Pokud jste se dali na studium SQL, pak se již připojujete k IT.

Na rozdíl od konverzní funkce CAST může funkce CONVERT specifikovat třetí parametr, který je zodpovědný za převodní styl (formát). Různé datové typy mohou mít vlastní sadu stylů, což může ovlivnit vrácený výsledek. O použití stylů jsme se již dotkli při zvažování převodu řetězce pomocí funkce CONVERT na typy date a datetime.

Více o funkcích CAST, CONVERT a stylech si můžete přečíst v MSDN – „Funkce CAST a CONVERT (Transact-SQL)“: msdn.microsoft.com/ru-ru/library/ms187928.aspx

Pro zjednodušení příkladů zde budou použity příkazy jazyka Transact-SQL DECLARE a SET.

Samozřejmě, že v případě převodu celého čísla na reálné číslo (který jsem uvedl na začátku této lekce, abych demonstroval rozdíl mezi celým číslem a skutečným dělením), znalost nuancí převodu není tak kritická, protože tam jsme provedli převod celého čísla na skutečný (jehož rozsah je mnohem větší než rozsah celých čísel):

DECLARE @min_int int SET @min_int=-2147483648 DECLARE @max_int int SET @max_int=2147483647 SELECT -- (-2147483648) @min_int,CAST(@min_int AS float),CONVERT(float,@31478), -- ,CAST(@max_int AS float),CONVERT(float,@max_int), -- numeric(16,6) @min_int/1., -- (-2147483648,000000) @max_int/1. -- 2147483647,000000

Snad nemělo cenu upřesňovat způsob implicitní konverze získané dělením (1.), protože Je vhodné pokusit se provést explicitní převody pro větší kontrolu nad typem získaného výsledku. I když, pokud chceme získat výsledek typu numeric, se zadaným počtem číslic za desetinnou čárkou, pak můžeme použít trik v MS SQL, abychom vynásobili celočíselnou hodnotu (1., 1.0, 1.00 atd.) :

DECLARE @int int SET @int=123 SELECT @int*1., -- numeric(12, 0) - 0 desetinných míst @int*1.0, -- numeric(13, 1) - 1 desetinné místo @int*1.00, -- numeric(14, 2) - 2 znaky -- i když někdy je lepší provést explicitní převod CAST(@int AS numeric(20, 0)), -- 123 CAST(@int AS numeric(20, 1) ), -- 123,0 CAST(@int AS numeric(20, 2)) -- 123,00

V některých případech mohou být detaily konverze opravdu důležité, protože... ovlivňují správnost získaného výsledku např. v případě, kdy se provádí převod z číselné hodnoty na řetězec (varchar). Podívejme se na příklady převodu peněz a plovoucích hodnot na varchar:

Chování při převodu peněz na varchar DECLARE @money money SET @money = 1025,123456789 -- dojde k implicitní konverzi na 1025,1235, protože peněžní typ ukládá pouze 4 číslice za desetinnou čárkou SELECT @money, -- 1025.1235 -- ve výchozím nastavení se CAST a CONVERT chovají stejně (tj. zhruba řečeno je použit styl 0) CAST(@money as varchar(20)) , -- 1025,12 CONVERT(varchar(20), @peníze), -- 1025,12 CONVERT(varchar(20), @peníze, 0), -- 1025,12 (styl 0 - bez oddělovače tisícin a 2 desetinná místa (výchozí formát)) CONVERT( varchar(20), @peníze, 1), -- 1.025.12 (styl 1 – používá oddělovač tisícin a 2 desetinná místa) CONVERT(varchar(20), @peníze, 2) -- 1025.1235 (styl 2 – žádný oddělovač a 4 čísla za desetinnou čárkou)

Chování při převodu float na varchar DECLARE @float1 float SET @float1 = 1025,123456789 DECLARE @float2 float SET @float2 = 1231025,123456789 SELECT @float1, -- 1025,123452918 --4float 1025,123452918 --4 výchozí se CAST a CONVERT chovají stejně (tj. zhruba řečeno, používá se styl 0) -- styl 0 – ne více než 6 číslic. Exponenciální zápis se používá z nutnosti -- při převodu na varchar se zde stávají opravdu děsivé věci CAST(@float1 jako varchar(20)), -- 1025.12 CONVERT(varchar(20), @float1), -- 1025.12 CONVERT(varchar( 20), @float1, 0), -- 1025,12 CAST(@float2 jako varchar(20)), -- 1,23103e+006 CONVERT(varchar(20), @float2), -- 1,23103e+006 CONVERT(varchar( 20 ), @float2, 0), -- 1,23103e+006 -- styl 1 - Vždy 8 číslic. Vždy se používá vědecký zápis čísel.

-- tento styl pro float také není příliš přesný CONVERT(varchar(20), @float1, 1), -- 1.0251235e+003 CONVERT(varchar(20), @float2, 1), -- 1.2310251e+006 - - styl 2 - Vždy 16 bitů. Vždy se používá vědecký zápis čísel.

Pokud potřebujete explicitně řídit přesnost až do určitého znaménka, více než 4, pak je někdy lepší použít pro ukládání dat typ desítkové/číselné. Pokud stačí 4 znaky, pak můžete použít peněžní typ - přibližně odpovídá numerické (20,4).

Desetinná a numerická DECLARE @money money SET @money = 1025,123456789 -- 1025,1235 DECLARE @float1 float SET @float1 = 1025,123456789 DECLARE @float2 float SET @float2 = 10292 numerický (1231) ,9) SET @numeric = 1025,123456789 SELECT CAST ( @numeric jako varchar(20)), -- 1025,12345679 CONVERT(varchar(20), @numeric), -- 1025,12345679 CAST(@money jako numerické(28,9)), -- 1025,123500000 CAST(@float1 jako numerické 28 ,9)), -- 1025,123456789 CAST(@float2 jako numeric(28,9)) -- 1231025,123456789

Poznámka.
Od verze MS SQL 2008 můžete místo konstrukce použít: Přidat popisky

Poslední aktualizace: 24.06.2017

SQL Server je jedním z nejpopulárnějších systémů pro správu databází (DBMS) na světě. Tento DBMS je vhodný pro širokou škálu projektů: od malých aplikací po velké, vysoce zatížené projekty.

SQL Server byl vytvořen společností Microsoft. První verze byla vydána v roce 1987. A aktuální verze je verze 16, která vyšla v roce 2016 a bude použita v aktuální příručce.

SQL Server je již dlouho výhradně systémem správy databází pro Windows, ale počínaje verzí 16 je dostupný také na Linuxu.

SQL Server se vyznačuje takovými funkcemi, jako jsou:

    Výkon. SQL Server je velmi rychlý.

    Spolehlivost a bezpečnost. SQL Server poskytuje šifrování dat.

    Jednoduchost. S tímto DBMS je relativně snadné pracovat a spravovat.

Ústředním aspektem v MS SQL Server, stejně jako v každém DBMS, je databáze. Databáze je úložiště dat organizovaných specifickým způsobem. Databáze často fyzicky představuje soubor na pevném disku, i když tato korespondence není nutná. K ukládání a správě databází se používají systémy správy databází nebo DBMS. A právě MS SQL Server je jedním z takových DBMS.

MS SQL Server používá k organizaci databází relační model. Tento databázový model byl vyvinut již v roce 1970 Edgarem Coddem. A dnes je to vlastně standard pro organizaci databází.

Relační model zahrnuje ukládání dat ve formě tabulek, z nichž každá se skládá z řádků a sloupců. Každý řádek ukládá samostatný objekt a sloupce obsahují atributy tohoto objektu.

Primární klíč se používá k identifikaci každého řádku v tabulce. Primárním klíčem může být jeden nebo více sloupců. Pomocí primárního klíče můžeme odkazovat na konkrétní řádek v tabulce. Proto dva řádky nemohou mít stejný primární klíč.

Prostřednictvím klíčů lze jednu tabulku propojit s jinou, to znamená, že mezi dvěma tabulkami lze organizovat vztahy. A samotná tabulka může být reprezentována jako vztah.

Pro interakci s databází se používá jazyk SQL (Structured Query Language). Klient (například externí program) odešle požadavek v SQL pomocí speciálního API. DBMS správně interpretuje a provede požadavek a poté odešle výsledek provedení klientovi.

SQL byl původně vyvinut společností IBM pro databázový systém s názvem System/R. Samotný jazyk se přitom jmenoval SEQUEL (Structured English Query Language). Přestože databáze ani jazyk jako takový nebyly následně oficiálně publikovány, tradičně se termín SQL sám o sobě často vyslovuje jako „pokračování“.

V roce 1979, Relational Software Inc. vyvinul první systém správy databází s názvem Oracle, který používal jazyk SQL. Vzhledem k úspěchu tohoto produktu byla společnost přejmenována na Oracle.

Následně se začaly objevovat další databázové systémy, které SQL využívaly. Výsledkem je, že v roce 1989 americký národní standardizační institut (ANSI) kodifikoval jazyk a zveřejnil svůj první standard. Poté byla norma pravidelně aktualizována a doplňována. Jeho poslední aktualizace proběhla v roce 2011. Ale navzdory existenci standardu výrobci DBMS často používají své vlastní implementace jazyka SQL, které se od sebe mírně liší.

Existují dva druhy jazyka SQL: PL-SQL a T-SQL. PL-SQL se používá v DBMS, jako je Oracle a MySQL. V SQL Server se používá T-SQL (Transact-SQL). Ve skutečnosti to je důvod, proč bude T-SQL zvažován v aktuální příručce.

V závislosti na úloze, kterou příkaz T-SQL provádí, může jít o jeden z následujících typů:

    DDL (Data Definition Language). Tento typ zahrnuje různé příkazy, které vytvářejí databázi, tabulky, indexy, uložené procedury atd. Obecně se určují data.

    K tomuto typu můžeme klasifikovat zejména následující příkazy:

    • CREATE : vytváří databázové objekty (samotnou databázi, tabulky, indexy atd.)

      ALTER: upravuje databázové objekty

      DROP: Odebere databázové objekty

      TRUNCATE: odstraní všechna data z tabulek

    DML (Data Manipulation Language). Tento typ zahrnuje příkazy pro výběr dat, jejich aktualizaci, přidání, mazání - obecně všechny ty příkazy, pomocí kterých můžeme data spravovat.

    K tomuto typu patří následující příkazy:

    • SELECT: načte data z databáze

      UPDATE: aktualizuje data

      INSERT: přidá nová data

      DELETE: vymaže data

    DCL (Data Control Language / Data Access Control Language). Tento typ zahrnuje příkazy, které spravují přístupová práva k datům. Konkrétně se jedná o následující příkazy:

    • GRANT: uděluje oprávnění k přístupu k datům

      REVOKE: ruší přístupová práva k datům

V prvním díle jsme se již trochu dotkli jazyka DML, a to pomocí téměř celé sady jeho příkazů, s výjimkou příkazu MERGE.

O DML budu hovořit podle své vlastní posloupnosti, vyvinuté z osobní zkušenosti. Po cestě se také pokusím mluvit o „kluzkých“ místech, na která stojí za to se zaměřit;

Protože učebnice je věnována širokému okruhu čtenářů (nejen programátorům), pak bude výklad někdy vhodný, tzn. dlouhé a nudné. To je moje vize materiálu, který jsem získal především v praxi jako výsledek odborné činnosti.

Hlavním cílem tohoto tutoriálu, krok za krokem, je rozvinout úplné pochopení podstaty jazyka SQL a naučit vás, jak správně aplikovat jeho konstrukce. Prolistování tohoto materiálu by mohlo zajímat i profesionály v této oblasti, možná se budou moci dozvědět něco nového pro sebe, nebo možná bude jen užitečné si jej přečíst, aby si osvěžili paměť. Doufám, že to bude pro každého zajímavé.

Protože DML v dialektu databáze MS SQL velmi úzce souvisí se syntaxí konstruktu SELECT, takže o DML začnu mluvit s ním. Podle mého názoru je konstrukt SELECT nejdůležitějším konstruktem v jazyce DML, protože díky němu nebo jeho částem jsou potřebná data načtena z databáze.

Jazyk DML obsahuje následující konstrukce:

  • SELECT – výběr dat
  • INSERT – vložení nových údajů
  • UPDATE – aktualizace dat
  • DELETE – smazání dat
  • MERGE – slučování dat

V tomto díle se podíváme pouze na základní syntaxi příkazu SELECT, která vypadá takto:

SELECT seznam_sloupců nebo * FROM zdroj WHERE filtr ORDER BY řazení_výrazu
Téma příkazu SELECT je velmi široké, proto se v této části zaměřím pouze na jeho základní konstrukty. Věřím, že bez znalosti základů nemůžete začít studovat složitější struktury, protože pak se vše bude točit kolem tohoto základního designu (poddotazy, spojení atd.).

Také v rámci tohoto dílu budu mluvit i o TOP nabídce. Záměrně jsem tuto větu neuvedl v základní syntaxi, protože... je implementován odlišně v různých dialektech SQL.

Pokud je jazyk DDL více statický, tzn. s jeho pomocí se vytvářejí rigidní struktury (tabulky, vztahy atd.), pak je jazyk DML dynamický, zde můžete různými způsoby získat správné výsledky.

Trénink bude pokračovat i v režimu Krok za krokem, tzn. Při čtení byste se měli okamžitě pokusit dokončit příklad vlastníma rukama. Poté analyzujete získaný výsledek a snažíte se jej intuitivně pochopit. Zůstane-li něco nejasné, například význam funkce, obraťte se o pomoc na internet.

Příklady budou ukázány v databázi Test, která byla vytvořena pomocí DDL+DML v první části.

Pro ty, kteří nevytvářeli databázi v první části (protože ne každého může zajímat jazyk DDL), mohou použít následující skript:

Testovací skript pro vytvoření databáze

Vytvoření databáze CREATE DATABASE Test GO -- nastavte testovací databázi jako aktuální USE Test GO -- vytvořte referenční tabulky CREATE TABLE Positions(ID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_Positions PRIMARY KEY, Name nvarchar(30) NOT NULL) CREATE TABLE Oddělení (ID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_Departments PRIMÁRNÍ KLÍČ, Název nvarchar(30) NOT NULL) GO -- vyplňte referenční tabulky daty SET IDENTITY_INSERT Pozice ON INSERT Pozice(ID,Název)VALUES (1, N"Účetní" ), (2,N"Ředitel"), (3,N"Programátor"), (4,N"Senior programátor") SET IDENTITY_INSERT Pozice OFF GO SET IDENTITY_INSERT Oddělení ZAPNUTO Oddělení (ID,Jméno)VALUES (1,N "Administrace"), (2,N"Účetnictví"), (3,N"IT") NASTAVIT IDENTITY_INSERT Oddělení OFF GO -- vytvořit tabulku se zaměstnanci CREATE TABLE Zaměstnanci(ID int NOT NULL, Name nvarchar( 30), datum narození , e-mail nvarchar(30), PositionID int, DepartmentID int, datum náboru NOT NULL CONSTRAINT DF_Employees_HireDate DEFAULT SYSDATETIME(), ManagerID int, CONSTRAINT PK_Employees PRIMARY KEY (ID), CONSTRAINT CONSTRAINTDepart FKEImGNSTRAINTDepart S oddělení( ID), TRAINT FK_Employees_PositionID CIZÍ KLÍČ(ID pozice) REFERENCES Pozice(ID), OMEZENÍ FK_Employees_ManagerID CIZÍ KLÍČ (ID manažera) REFERENCES Zaměstnanci(ID), CONSTRAINT UQ_Employees_Email BETIDINCHEEmail(e-mail) CONSTRAINT_CONTRAINCKy1 00 A 1999), INDEX IDX_Emplo yes_Name (Jméno)) GO - - vyplňte jej údaji INSERT Zaměstnanci (ID,Jméno,Narozeniny,E-mail,ID pozice,ID oddělení,ID manažera)VALUES (1000,N"Ivanov I.I.","19550219"," [e-mail chráněný]",2,1,NULL), (1001,N"Petrov P.P.","19831203"," [e-mail chráněný]",3,3,1003), (1002,N"Sidorov S.S.","19760607"," [e-mail chráněný]",1,2,1000), (1003,N"Andreev A.A.","19820417"," [e-mail chráněný]",4,3,1000)

To je vše, nyní jsme připraveni začít se učit jazyk DML.

SELECT – operátor výběru dat

Nejprve pro aktivní editor dotazů udělejme test aktuální databáze výběrem z rozevíracího seznamu nebo pomocí příkazu „USE Test“.

Začněme nejzákladnější formou SELECT:

VYBERTE * OD zaměstnanců
V tomto dotazu požadujeme vrátit všechny sloupce (označené "*") z tabulky Zaměstnanci - můžete to číst jako "VYBRAT všechna_pole Z tabulky zaměstnanců." Pokud existuje seskupený index, budou vrácená data s největší pravděpodobností řazena podle něj, v tomto případě podle sloupce ID (to ale není důležité, protože ve většině případů si řazení explicitně určíme sami pomocí ORDER BY ...) :

ID Jméno Narozeniny E-mail ID pozice ID oddělení Datum pronájmu ManagerID
1000 Ivanov I.I. 1955-02-19 [e-mail chráněný] 2 1 2015-04-08 NULL
1001 Petrov P.P. 1983-12-03 [e-mail chráněný] 3 3 2015-04-08 1003
1002 Sidorov S.S. 1976-06-07 [e-mail chráněný] 1 2 2015-04-08 1000
1003 Andreev A.A. 1982-04-17 [e-mail chráněný] 4 3 2015-04-08 1000

Obecně stojí za to říci, že v dialektu MS SQL nejjednodušší forma SELECT dotazu nemusí obsahovat blok FROM, v takovém případě jej můžete použít k získání některých hodnot:

SELECT 5550/100*15, SYSDATETIME(), -- získání databázového systému data SIN(0)+COS(0)

(Žádný název sloupce) (Žádný název sloupce) (Žádný název sloupce)
825 2015-04-11 12:12:36.0406743 1

Vezměte prosím na vědomí, že výraz (5550/100*15) dal výsledek 825, i když pokud počítáme na kalkulačce, bude hodnota (832,5). Výsledek 825 byl získán z toho důvodu, že v našem výrazu jsou všechna čísla celá čísla, proto je výsledkem celé číslo, tzn. (5550/100) nám dává 55, nikoli (55,5).

Pamatujte, že v MS SQL funguje následující logika:

  • Integer / Integer = Integer (tj. v tomto případě dojde k celočíselnému dělení)
  • Skutečné / Celé číslo = Skutečné
  • Celé číslo / Skutečné = Skutečné
Tito. výsledek se převede na větší typ, takže v posledních 2 případech dostaneme reálné číslo (přemýšlejte jako v matematice - rozsah reálných čísel je větší než rozsah celých čísel, takže výsledek se převede na něj):

SELECT 123/10, -- 12 123./10, -- 12,3 123/10. -- 12.3
Zde (123.) = (123.0) jde jen o to, že v tomto případě lze zahodit 0 a ponechat pouze bod.

Stejná logika platí pro ostatní aritmetické operace, ale v případě dělení je tato nuance relevantnější.

Pozor proto na datový typ číselných sloupců. Pokud je to celé číslo a potřebujete získat skutečný výsledek, použijte transformaci nebo jednoduše vložte tečku za číslo označené jako konstanta (123.).

K převodu polí můžete použít funkci CAST nebo CONVERT. Použijme například pole ID, je typu int:

SELECT ID, ID/100, -- zde dojde k dělení celým číslem CAST(ID AS float)/100, -- pomocí funkce CAST převedete na typ float CONVERT(float,ID)/100, -- použijete funkci CONVERT převést na typ float ID/100. -- použijte transformaci zadáním, že jmenovatelem je skutečné číslo OD Zaměstnanců

ID (Žádný název sloupce) (Žádný název sloupce) (Žádný název sloupce) (Žádný název sloupce)
1000 10 10 10 10.000000
1001 10 10.01 10.01 10.010000
1002 10 10.02 10.02 10.020000
1003 10 10.03 10.03 10.030000

Jen poznámka. V databázi ORACLE je syntaxe bez bloku FROM nepřijatelná, k tomuto účelu se používá systémová tabulka DUAL, která obsahuje jeden řádek:

SELECT 5550/100*15, -- a v ORACLE bude výsledek roven 832,5 sysdate, sin(0)+cos(0) FROM DUAL


Poznámka. Před názvem tabulky v mnoha RDB může předcházet název schématu:

SELECT * FROM dbo.Employees -- dbo – název schématu

Schéma je logická jednotka databáze, která má své jméno a umožňuje v sobě seskupovat databázové objekty, jako jsou tabulky, pohledy atd.

Definice schématu v různých databázích se může v některých případech lišit, schéma přímo souvisí s uživatelem databáze, tzn. v tomto případě můžeme říci, že schéma a uživatel jsou synonyma a všechny objekty vytvořené ve schématu jsou v podstatě objekty tohoto uživatele. V MS SQL je schéma nezávislá logická jednotka, kterou lze vytvořit samostatně (viz VYTVOŘENÍ SCHÉMATU).

Standardně je v databázi MS SQL vytvořeno jedno schéma s názvem dbo (Database Owner) a všechny vytvořené objekty jsou standardně vytvořeny v tomto schématu. Pokud tedy jednoduše zadáme název tabulky v dotazu, bude prohledávána ve schématu dbo aktuální databáze. Pokud chceme vytvořit objekt v konkrétním schématu, budeme muset před název objektu přidat název schématu, například „CREATE TABLE název_schématu.název_tabulky(...)“.

V případě MS SQL může před názvem schématu také předcházet název databáze, ve které se schéma nachází:

SELECT * FROM Test.dbo.Employees -- název_databáze.název_schematu.tabulka
Toto objasnění může být užitečné, například pokud:

  • v jednom požadavku přistupujeme k objektům umístěným v různých schématech nebo databázích
  • potřebujete přenést data z jednoho schématu nebo databáze do jiného
  • pokud jste v jedné databázi, musíte si vyžádat data z jiné databáze
  • atd.
Schéma je velmi pohodlný nástroj, který je užitečné použít při vývoji databázové architektury, zejména velkých databází.

Nezapomeňte také, že v textu požadavku můžeme použít jak jednořádkové komentáře „-- ...“, tak víceřádkové „/* ... */“. Pokud je požadavek velký a složitý, pak komentáře mohou vám nebo někomu jinému po nějaké době velmi pomoci zapamatovat si nebo pochopit jeho strukturu.

Pokud je v tabulce mnoho sloupců a zejména pokud je v tabulce stále mnoho řádků, plus pokud provádíme dotazy do databáze přes síť, pak by bylo vhodnější vybrat s přímým výpisem pole, která potřebujete, oddělená čárkami:

SELECT ID,Jméno FROM Zaměstnanci

Tito. zde říkáme, že potřebujeme vrátit pouze pole ID a Name z tabulky. Výsledek bude následující (mimochodem, optimalizátor se zde rozhodl použít index vytvořený polem Name):

ID Jméno
1003 Andreev A.A.
1000 Ivanov I.I.
1001 Petrov P.P.
1002 Sidorov S.S.

Jen poznámka. Někdy může být užitečné podívat se, jak se data načítají, například zjistit, které indexy se používají. To lze provést kliknutím na tlačítko „Zobrazit odhadovaný plán provedení“ nebo nastavením „Zahrnout skutečný plán provedení – do výsledku zahrnout skutečný plán provedení dotazu“ (v tomto případě budeme moci vidět skutečný plán, resp. po provedení požadavku):

Analýza prováděcího plánu je velmi užitečná při optimalizaci dotazu, umožňuje zjistit, které indexy chybí nebo které indexy nejsou vůbec použity a lze je odstranit.

Pokud jste se právě začali učit DML, pak už to pro vás není tak důležité, vezměte to na vědomí a můžete na to klidně zapomenout (možná to nikdy nebudete potřebovat) – naším prvotním cílem je naučit se základy jazyka DML a naučit se je správně používat a optimalizace je již samostatným uměním. Někdy je důležitější, abyste měli jednoduše správně napsaný dotaz, který vrací správný výsledek z hlediska předmětu, a jednotliví lidé jej již optimalizují. Nejprve se musíte naučit, jak jednoduše správně psát dotazy, pomocí jakýchkoli prostředků k dosažení cíle. Hlavním cílem, kterého nyní musíte dosáhnout, je, aby váš dotaz vrátil správné výsledky.

Nastavení aliasů tabulek

Při výpisu sloupců jim může předcházet název tabulky umístěné v bloku FROM:

SELECT Employees.ID,Employees.Name FROM Employees

Ale použití této syntaxe je obvykle nepohodlné, protože název tabulky může být dlouhý. Pro tyto účely se obvykle uvádějí a používají kratší názvy - aliasy:

VYBERTE ID zam., jméno zam. FROM Zaměstnanci JAKO zam
nebo

SELECT emp.ID,emp.Name FROM Zaměstnanci emp -- klíčové slovo AS lze vynechat (preferuji tuto možnost)

Zde emp je alias pro tabulku Zaměstnanci, který lze použít v kontextu tohoto příkazu SELECT. Tito. můžeme říci, že v kontextu tohoto příkazu SELECT dáváme tabulce nový název.

Samozřejmě, že v tomto případě budou výsledky dotazu přesně stejné jako pro „SELECT ID, Name FROM Employees“. Proč je to potřeba, bude jasné později (ani v této části), zatím jen připomeňme, že před názvem sloupce může být (objasněno) buď přímo název tabulky, nebo pomocí aliasu. Zde můžete použít jednu ze dvou věcí, tzn. Pokud nastavíte alias, budete jej muset použít, ale nemůžete již používat název tabulky.

Jen poznámka. V ORACLE je povolena pouze možnost zadat alias tabulky bez klíčového slova AS.

DISTINCT – zahození duplicitních řádků

Klíčové slovo DISTINCT se používá k vyřazení duplicitních řádků z výsledku dotazu. Zhruba řečeno, představte si, že nejprve provedete dotaz bez možnosti DISTINCT a poté z výsledku zahodíte všechny duplikáty. Ukažme si to pro větší názornost na příkladu:

Vytvořme dočasnou tabulku pro ukázku CREATE TABLE #Trash(ID int NOT NULL PRIMARY KEY, Col1 varchar(10), Col2 varchar(10), Col3 varchar(10)) -- vyplňte tuto tabulku nejrůznějšími odpadky INSERT #Trash (ID,Sloupec1, Sloupec2,Sloupec3)HODNOTY (1,"A","A","A"), (2,"A","B","C"), (3,"C"," A","B"), (4,"A","A","B"), (5,"B","B","B"), (6,"A","A" "B"), (7,"A","A","A"), (8,"C","A","B"), (9,"C","A"," B"), ( 10,"A","A","B"), (11,"A",NULL,"B"), (12,"A",NULL,"B") - podívejme se co požadavek vrátí bez možnosti DISTINCT SELECT Col1,Col2,Col3 FROM #Trash -- podívejme se, co dotaz vrátí s volbou DISTINCT SELECT DISTINCT Col1,Col2,Col3 FROM #Trash -- smažte dočasnou tabulku DROP TABLE #Trash

Vizuálně to bude vypadat takto (všechny duplikáty jsou označeny stejnou barvou):

Nyní se podívejme, kde to lze uplatnit, na praktičtějším příkladu – z tabulky Zaměstnanci vrátíme pouze unikátní identifikátory oddělení (tj. zjistíme ID oddělení, ve kterých jsou zaměstnanci evidováni):

VYBERTE DISTINCT ID oddělení OD zaměstnanců

Tady máme 4 řádky, protože... V naší tabulce nejsou žádné opakující se kombinace (DepartmentID, PositionID).

Vraťme se na chvíli k DDL.

Protože nám začínají docházet data pro ukázkové příklady a chceme mluvit obšírněji a jasněji, rozšiřme trochu naši tabulku Zaměstnanci. Kromě toho si připomeňme trochu DDL, jak se říká, „opakování je matka učení“ a plus, pojďme znovu trochu poskočit a použít příkaz UPDATE:

Vytváříme nové sloupce ALTER TABLE Zaměstnanci PŘIDAT Příjmení nvarchar(30), -- příjmení Jméno nvarchar(30), -- jméno Prostřední jméno nvarchar(30), -- prostřední jméno Plovoucí plat, -- a samozřejmě plat v některých jednotkách BonusPercent float -- procento pro výpočet bonusu ze mzdy GO -- vyplňte je údaji (některé údaje jsou záměrně vynechány) AKTUALIZACE Zaměstnanci SET Příjmení=N"Ivanov", Jméno=N"Ivan", Prostřední jméno=N"Ivanovich", Plat=5000,BonusPercent= 50 KDE ID=1000 -- Ivanov I.I. AKTUALIZACE Zaměstnanci SET Příjmení=N"Petrov",Jméno=N"Petr",MiddleName=N"Petrovich", Plat=1500,BonusPercent= 15 WHERE ID=1001 -- Petrov P.P. AKTUALIZACE Zaměstnanci SET Příjmení=N"Sidor",Jméno=N"Sidor",MiddleName=NULL, Plat=2500,BonusPercent=NULL WHERE ID=1002 -- Sidorov S.S. AKTUALIZACE Zaměstnanci SET Příjmení=N"Andreev",Jméno=N"Andrey",MiddleName=NULL, Plat=2000,BonusPercent= 30 WHERE ID=1003 -- Andreev A.A.

Ujistíme se, že data byla úspěšně aktualizována:

VYBERTE * OD zaměstnanců

ID Jméno Příjmení Jméno Prostřední jméno Plat Bonusové procento
1000 Ivanov I.I. Ivanov Ivane Ivanovič 5000 50
1001 Petrov P.P. Petrov Petr Petrovič 1500 15
1002 Sidorov S.S. Sidorov Sidor NULL 2500 NULL
1003 Andreev A.A. Andrejev Andrey NULL 2000 30

Nastavení aliasů pro sloupce dotazu

Myslím, že zde bude jednodušší ukázat, než napsat:

SELECT -- zadejte název vypočítanému sloupci Příjmení+" "+Jméno+" "+MiddleName AS Celé jméno, -- použijte dvojité uvozovky, protože se používá mezera HireDate AS "Datum přijetí", -- použití hranatých závorek, protože místo je využito Narozeniny AS [Datum narození], -- slovo AS není nutné Mzda ZP OD Zaměstn.

Celé jméno Datum přijetí Datum narození ZP
Ivanov Ivan Ivanovič 2015-04-08 1955-02-19 5000
Petrov Petr Petrovič 2015-04-08 1983-12-03 1500
NULL 2015-04-08 1976-06-07 2500
NULL 2015-04-08 1982-04-17 2000

Jak vidíme, námi zadané aliasy sloupců se projeví v záhlaví výsledné tabulky. Ve skutečnosti je to hlavní účel aliasů sloupců.

Vezměte prosím na vědomí, protože poslední 2 zaměstnanci neměli zadané prostřední jméno (hodnota NULL), pak nám výsledek výrazu „Příjmení+“ „+Jméno+“ „+MiddleName“ také vrátil NULL.

Pro spojení (přidání, zřetězení) řetězců v MS SQL se používá symbol „+“.

Pamatujte, že všechny výrazy, které obsahují hodnotu NULL (například dělení hodnotou NULL, sčítání s hodnotou NULL), vrátí hodnotu NULL.

Jen poznámka.
V případě ORACLE se ke zřetězení řetězců používá operátor „||“. a zřetězení by vypadalo jako "Příjmení||" "||Jméno||" "||MiddleName". Pro ORACLE stojí za zmínku, že má výjimku pro typy řetězců, pro ně jsou NULL a prázdný řetězec "" to samé, takže v ORACLE se takový výraz vrátí pro poslední 2 zaměstnance "Sidor Sidor" a "Andrey Andrejev“. V době ORACLE 12c, pokud vím, neexistuje žádná možnost, která by toto chování změnila (pokud se mýlím, opravte mě). Tady je pro mě těžké posoudit, jestli je to dobře nebo špatně, protože... V některých případech je chování NULL řetězce pohodlnější, jako v MS SQL, a v jiných, jako v ORACLE.

V ORACLE jsou také platné všechny aliasy sloupců uvedené výše, kromě [...].


Abychom neoplotili stavbu pomocí funkce ISNULL, v MS SQL můžeme použít funkci CONCAT. Zvažme a porovnejme 3 možnosti:

SELECT LastName+" "+FirstName+" "+MiddleName FullName1, -- 2 možnosti pro nahrazení NULL prázdné řádky"" (dostaneme stejné chování jako v ORACLE) ISNULL(Příjmení,"")+" "+ISNULL(Jméno,"")+" "+ISNULL(MiddleName,"") CeléJméno2, CONCAT(Příjmení," ", Jméno, " ",MiddleName) CeléJméno3 OD Zaměstnanců

Celé jméno1 Celé jméno2 Celé jméno3
Ivanov Ivan Ivanovič Ivanov Ivan Ivanovič Ivanov Ivan Ivanovič
Petrov Petr Petrovič Petrov Petr Petrovič Petrov Petr Petrovič
NULL Sidorov Sidor Sidorov Sidor
NULL Andrejev Andrej Andrejev Andrej

V MS SQL lze aliasy zadat také pomocí rovnítka:

SELECT "Datum přijetí"=Datum přijetí, -- kromě "..." a […] můžete použít "..." [Datum narození]=Narozeniny, ZP=Plat OD zaměstnanců

Použití klíčového slova AS nebo rovnítka k určení aliasu je pravděpodobně spíše věcí vkusu. Ale při analýze požadavků jiných lidí mohou být tyto znalosti užitečné.

Nakonec řeknu, že je lepší nastavit jména pro aliasy pouze pomocí latinských znaků a čísel, vyhnout se použití „…“, „…“ a […], tedy použít stejná pravidla, která jsme použili při pojmenovávání tabulek. . Dále v příkladech budu používat pouze taková jména a žádné „…“, „…“ a […].

Základní SQL aritmetické operátory


Priorita provádění aritmetických operátorů je stejná jako v matematice. V případě potřeby lze změnit pořadí aplikace operátorů pomocí závorek - (a+b)*(x/(y-z)).

A ještě jednou zopakuji, že jakákoli operace s NULL vygeneruje NULL, například: 10+NULL, NULL*15/3, 100/NULL - z toho všeho bude NULL. Tito. jednoduše řečeno, nedefinovaná hodnota nemůže přinést jednoznačný výsledek. Vezměte to v úvahu při sestavování dotazu a v případě potřeby zpracujte hodnoty NULL pomocí funkcí ISNULL a COALESCE:

SELECT ID,Jméno, Plat/100*BonusPercent AS Výsledek1, -- bez zpracování hodnot NULL ​​Mzda/100*ISNULL(BonusPercent,0) AS Výsledek2, -- použijte funkci ISNULL Plat/100*COALESCE(BonusPercent,0) AS Výsledek3 - - použijte funkci COALESCE FROM Zaměstnanců

Řeknu vám něco o funkci COALESCE:

COALESCE (expr1, expr2, ..., exprn) - Vrátí první neNULL hodnotu ze seznamu hodnot.

SELECT COALESCE(f1, f1*f2, f2*f3) val -- v tomto případě bude vrácena třetí hodnota FROM (SELECT null f1, 2 f2, 3 f3) q

Většinou se zaměřím na povídání o konstrukcích DML a z větší části nebudu mluvit o funkcích, které se objeví v příkladech. Pokud nerozumíte tomu, co konkrétní funkce dělá, hledejte její popis na internetu, informace můžete vyhledávat i podle skupin funkcí najednou, např. hledáním v Google “MS SQL string functions”, “MS SQL matematické funkce“ nebo „funkce MS SQL“ zpracování NULL." Existuje mnoho informací o funkcích a můžete je snadno najít. Například v knihovně MSDN se můžete dozvědět více o funkci COALESCE:

Výstřižek z MSDN Srovnání COALESCE a CASE

Výraz COALESCE je syntaktická zkratka pro výraz CASE. To znamená, že COALESCE(výraz1,...n) je přepsán optimalizátorem dotazů jako následující výraz CASE:

CASE WHEN (výraz1 NENÍ NULL) THEN výraz1 WHEN (výraz2 NENÍ NULL) THEN výraz2 ... ELSE výrazN END

Podívejme se například, jak můžete použít zbytek dělení (%). Tento operátor je velmi užitečný, když potřebujete rozdělit záznamy do skupin. Vytáhněte například všechny zaměstnance, kteří mají sudá osobní čísla (ID), tzn. ta ID, která jsou dělitelná 2:

VYBERTE ID,Jméno FROM Zaměstnanci WHERE ID%2=0 -- zbytek po vydělení 2 je 0

ORDER BY – řazení výsledku dotazu

Klauzule ORDER BY se používá k řazení výsledku dotazu.

VYBERTE Příjmení, Jméno, Plat OD zaměstnanců ORDER BY LastName,FirstName -- výsledek seřaďte podle 2 sloupců - podle příjmení a poté podle jména

Pro poznámku. Existuje klíčové slovo ASC pro řazení ve vzestupném pořadí, ale protože vzestupné řazení je výchozí, můžete na tuto možnost zapomenout (nepamatuji si, kdy jsem tuto možnost použil).

Za zmínku stojí, že klauzule ORDER BY může používat i pole, která nejsou uvedena v klauzuli SELECT (kromě případu, kdy je použit DISTINCT, o kterém pojednám níže). Jako příklad trochu předběhnu pomocí možnosti TOP a ukážu, jak si například můžete vybrat 3 zaměstnance, kteří mají nejvyšší plat, s ohledem na to, že z důvodu zachování důvěrnosti bych neměl ukazovat samotný plat:

SELECT TOP 3 -- vrátit pouze první 3 záznamy z celého výsledku ID,Příjmení,Jméno FROM Zaměstnanci ORDER BY Plat DESC -- seřadit výsledek v sestupném pořadí podle Plat

ID Příjmení Jméno
1000 Ivanov Ivane
1002 Sidorov Sidor

Samozřejmě zde nastává případ, že více zaměstnanců může mít stejný plat a je těžké říci, kterým třem zaměstnancům se tento požadavek vrátí, to je nutné řešit s vedoucím úkolu. Řekněme, že po projednání tohoto úkolu s vedoucím jste souhlasili a rozhodli jste se využít následující možnost - provést dodatečné třídění podle pole data narození (tj. vážíme si mladých lidí), a pokud se datum narození více zaměstnanců může shodovat (ostatně to také není vyloučeno), pak můžete provést třetí řazení v sestupném pořadí hodnot ID (poslední ve vzorku budou ti s nejvyšším ID - například ti, kteří byli přijati jako poslední, řekněme personální čísla jsou vydávána postupně):

SELECT TOP 3 -- vrátit pouze první 3 záznamy z celého výsledku ID,Příjmení,Jméno FROM Zaměstnanci ORDER BY Plat DESC, -- 1. Seřadit výsledek v sestupném pořadí podle Narozeniny platu, -- 2. poté podle Datum narození ID DESC -- 3 a pro úplnou přehlednost výsledku přidáváme řazení podle ID.

Tito. měli byste se snažit, aby byl výsledek žádosti předvídatelný, abyste v případě debriefingu mohli vysvětlit, proč byli tito konkrétní lidé zařazeni na „černou listinu“, tzn. vše bylo vybráno poctivě, podle stanovených pravidel.

Můžete také třídit pomocí různých výrazů v klauzuli ORDER BY:

SELECT LastName,FirstName FROM Zaměstnanci ORDER BY CONCAT(LastName," ",FirstName) -- použijte výraz

Můžete také použít aliasy určené pro sloupce v ORDER BY:

SELECT CONCAT(LastName," ",FirstName) fi FROM Zaměstnanci ORDER BY fi -- použijte alias

Stojí za zmínku, že při použití klauzule DISTINCT lze v klauzuli ORDER BY použít pouze sloupce uvedené v bloku SELECT. Tito. po aplikaci operace DISTINCT získáme novou sadu dat s novou sadou sloupců. Z tohoto důvodu nebude následující příklad fungovat:

SELECT DISTINCT Příjmení,Jméno,Plat OD Zaměstnanci ORDER BY ID -- ID není ve výsledné sadě, kterou jsme získali pomocí DISTINCT

Tito. klauzule ORDER BY je aplikována na výslednou sadu předtím, než je výsledek vrácen uživateli.

Poznámka 1. Můžete také použít čísla sloupců uvedených v SELECT v klauzuli ORDER BY:

VYBERTE Příjmení,Jméno,Plat FROM Zaměstnanci ORDER BY -- řazení v pořadí 3 DESC, -- 1. sestupně Plat 1, -- 2. podle příjmení 2 -- 3. podle jména

Pro začátečníky to vypadá pohodlně a lákavě, ale je lepší zapomenout a nikdy tuto možnost třídění nepoužívat.

Pokud je v tomto případě (když jsou pole explicitně uvedena), tato možnost stále přijatelná, pak v případě použití „*“ je lepší tuto možnost nikdy nepoužívat. Proč - protože pokud někdo například změní pořadí sloupců v tabulce, nebo sloupce smaže (a to je normální situace), váš dotaz může stále fungovat, ale špatně, protože řazení již lze provádět podle jiných sloupců a to je záludné v tom, že tato chyba nemusí být odhalena velmi brzy.

Pokud by byly sloupce explicitně uvedeny, pak by ve výše uvedené situaci dotaz buď nadále fungoval, ale také správně (protože je vše explicitně definováno), nebo by jednoduše vyhodilo chybu, že tento sloupec neexistuje.

Na řazení podle čísel sloupců tak můžete klidně zapomenout.

Poznámka 2
V MS SQL se při vzestupném řazení nejprve zobrazí hodnoty NULL.

VYBERTE procento bonusu OD zaměstnanců OBJEDNEJTE PODLE procenta bonusu

Při použití DESC tedy budou na konci

VYBERTE procento bonusu OD zaměstnanců OBJEDNEJTE PODLE BonusPercent DESC

Pokud potřebujete změnit logiku pro řazení hodnot NULL, použijte výrazy, například:

VYBERTE procento bonusu od zaměstnanců ORDER BY ISNULL(procento bonusu,100)

ORACLE poskytuje pro tento účel dvě možnosti: NULLS FIRST a NULLS LAST (používá se ve výchozím nastavení). Například:

VYBERTE procento bonusu OD zaměstnanců OBJEDNEJTE PODLE BonusPercent DESC NULLS LAST

Věnujte tomu pozornost při přechodu na konkrétní databázi.

TOP – vrátí zadaný počet záznamů

Výpis z MSDN. TOP – Omezuje počet řádků vrácených v sadě výsledků dotazu na zadaný počet nebo procento. Když je klauzule TOP použita ve spojení s klauzulí ORDER BY, je výsledná sada omezena na prvních N řádků seřazeného výsledku. V opačném případě bude prvních N řádků vráceno v nespecifikovaném pořadí.

Obvykle se tento výraz používá s klauzulí ORDER BY a již jsme se podívali na příklady, kdy bylo nutné vrátit prvních N řádků z výsledné sady.

Bez ORDER BY se tato klauzule obvykle používá, když se potřebujeme jen podívat na nám neznámou tabulku, která může mít spoustu záznamů, v tomto případě můžeme např. požádat o vrácení pouze prvních 10 řádků, ale např. srozumitelnost řekneme pouze 2:

VYBERTE NEJLEPŠÍ 2 * ZE ZAMĚSTNANCŮ

Můžete také zadat slovo PERCENT, abyste vrátili odpovídající procento řádků ze sady výsledků:

VYBERTE NEJLEPŠÍCH 25 PROCENT * ZE ZAMĚSTNANCŮ

V mé praxi se nejčastěji používá vzorkování podle počtu řádků.

Můžete také použít možnost S TIES s TOP, která pomůže vrátit všechny řádky v případě nejednoznačného řazení, tzn. tato věta vrátí všechny řádky, které se svým složením shodují s řádky, které spadají do výběru TOP N, v důsledku toho lze vybrat více než N řádků pro demonstraci.

INSERT Zaměstnanci(ID,Jméno,E-mail,ID pozice,ID oddělení,ID manažera,Plat) VALUES(1004,N"Nikolaev N.N."," [e-mail chráněný]",3,3,1003,1500)

A přidáme dalšího zaměstnance bez uvedení pozice a oddělení s platem 2000:

INSERT Zaměstnanci(ID,Jméno,E-mail,ID pozice,ID oddělení,ID manažera,Plat) VALUES(1005,N"Alexandrov A.A."," [e-mail chráněný]",NULL,NULL,1000,2000)

Nyní vybereme pomocí možnosti S VAZBAMI všechny zaměstnance, jejichž mzda se shoduje s platy 3 zaměstnanců, s nejnižší mzdou (doufám, že bude dále jasné, o co mi jde):

VYBERTE NEJLEPŠÍ 3 S VAZBAMI ID,Jméno,Mzda OD Zaměstnanců OBJEDNÁVKA PODLE Mzd

Zde, ačkoli je uvedeno TOP 3, požadavek vrátil 4 záznamy, protože hodnota platu, která vrátila TOP 3 (1500 a 2000) byla zjištěna u 4 zaměstnanců. Vizuálně to funguje asi takto:

Jen poznámka.
TOP je implementován různými způsoby v různých databázích v MySQL na to existuje klauzule LIMIT, ve které lze navíc nastavit počáteční offset.

V ORACLE 12c také představili svůj vlastní analog, kombinující funkcionalitu TOP a LIMIT - hledejte slova „ORACLE OFFSET FETCH“. Před verzí 12c se pro tento účel obvykle používal pseudosloupec ROWNUM.


Co se stane, když použijete klauzule DISTINCT a TOP současně? Takové otázky lze snadno zodpovědět prováděním experimentů. Obecně se nebojte a nebuďte líní experimentovat, protože... Většina se toho naučí praxí. Slovosled v příkazu SELECT je následující: DISTINCT je na prvním místě, následuje TOP, tzn. Pokud uvažujete logicky a čtete zleva doprava, použije se první, kdo zahodí duplikáty, a poté se na základě této sady vytvoří TOP. No, podívejme se a ujistěte se, že je to tento případ:

VYBERTE ODLIŠIT TOP 2 Mzda OD Zaměstnanců ŘADÍTE PODLE Mzd

Plat
1500
2000

Tito. v důsledku toho jsme dostali 2 nejmenší platy ze všech. Samozřejmě může nastat případ, že mzda u některých zaměstnanců nemusí být uvedena (NULL), protože Schéma nám to umožňuje. Proto se v závislosti na úloze rozhodneme buď zpracovat hodnoty NULL v klauzuli ORDER BY, nebo jednoduše vyřadit všechny záznamy, pro které je Plat NULL, a za tímto účelem přistoupíme ke studiu klauzule WHERE.

KDE – podmínka výběru řádku

Tato věta slouží k filtrování záznamů podle dané podmínky. Vyberme například všechny zaměstnance pracující v oddělení „IT“ (jeho ID=3):

VYBERTE ID,Příjmení,Jméno,Plat od zaměstnanců WHERE DepartmentID=3 -- IT ORDER BY LastName,FirstName

ID Příjmení Jméno Plat
1004 NULL NULL 1500
1003 Andrejev Andrey 2000
1001 Petrov Petr 1500

Klauzule WHERE se zapisuje před příkaz ORDER BY.

Pořadí použití příkazů na počáteční sadu Zaměstnanci je následující:

  1. KDE – pokud je zadáno, pak prvním krokem z celé množiny zaměstnanců je vybrat pouze záznamy, které splňují podmínku
  2. DISTINCT – pokud je zadáno, všechny duplikáty jsou zahozeny
  3. ORDER BY – pokud je zadáno, je výsledek seřazen
  4. TOP – pokud je zadáno, z setříděného výsledku se vrátí pouze zadaný počet záznamů

Pro názornost se podívejme na příklad:

VYBERTE DISTINCT TOP 1 Mzda OD Zaměstnanců KDE ID oddělení=3 OBJEDNAT PODLE Mzdy

Vizuálně to bude vypadat takto:

Za zmínku stojí, že kontrola NULL se neprovádí se znaménkem rovná se, ale pomocí operátorů IS NULL a IS NOT NULL. Pamatujte, že nemůžete porovnávat hodnotu NULL pomocí operátoru „=“ (rovná se), protože výsledek výrazu bude také roven NULL.

Vyberme například všechny zaměstnance, kteří nemají zadané oddělení (tj. DepartmentID IS NULL):

VYBERTE ID,Jméno FROM Zaměstnanci WHERE DepartmentID JE NULL

Nyní jako příklad vypočítejme bonus pro všechny zaměstnance, kteří mají zadanou hodnotu BonusPercent (tj. BonusPercent NENÍ NULL):

VYBERTE ID,Jméno,Plat/100*Procento bonusu JAKO bonus OD ZAMĚSTNANCŮ, KDE NENÍ procento bonusu NULL

Ano, mimochodem, pokud se nad tím zamyslíte, hodnota BonusPercent se může rovnat nule (0) a hodnotu lze zadat i se znaménkem mínus, protože jsme tomuto poli neuložili žádná omezení.

Když jsme o problému řekli, bylo nám prozatím řečeno, abychom zvážili, že pokud (BonusPercent<=0 или BonusPercent IS NULL), то это означает что у сотрудника так же нет бонуса. Для начала, как нам сказали, так и сделаем, реализуем это при помощи логического оператора OR и NOT:

VYBERTE ID,Jméno,Plat/100*Procento bonusu JAKO bonus OD ZAMĚSTNANCŮ, KDE NE (BonusPercent<=0 OR BonusPercent IS NULL)

Tito. Zde jsme se začali učit o booleovských operátorech. Výraz v závorkách „(BonusPercent<=0 OR BonusPercent IS NULL)» проверяет на то что у сотрудника нет бонуса, а NOT инвертирует это значение, т.е. говорит «верни всех сотрудников которые не сотрудники у которых нет бонуса».

Tento výraz lze také přepsat tak, že okamžitě řeknete „vrátit všechny zaměstnance, kteří mají bonus“ tím, že to vyjádříte výrazem (BonusPercent>0 a BonusPercent NENÍ NULL):

VYBERTE ID,Jméno,Plat/100*Procento bonusu JAKO bonus OD zaměstnanců, KDE BonusPercent>0 A BonusPercent NENÍ NULL

Také v bloku WHERE můžete kontrolovat různé druhy výrazů pomocí aritmetických operátorů a funkcí. Podobnou kontrolu lze například provést pomocí výrazu s funkcí ISNULL:

VYBERTE ID,Jméno,Plat/100*Procento bonusu JAKO Bonus OD zaměstnanců WHERE ISNULL(BonusPercent,0)>0

Booleovské operátory a jednoduché porovnávací operátory

Ano, bez matematiky se zde neobejdeme, takže si udělejme krátkou exkurzi do booleovských a jednoduchých porovnávacích operátorů.

V SQL jsou pouze 3 booleovské operátory - AND, OR a NOT:

Pro každý booleovský operátor můžete poskytnout pravdivostní tabulky, které navíc ukazují, jaký bude výsledek, když podmínky mohou být NULL:

K vytvoření podmínek se používají následující jednoduché porovnávací operátory:

Navíc existují 2 operátory pro kontrolu hodnoty/výrazu pro NULL:

JE NULL Testování rovnosti NULL
NENÍ NULL Testování NULL nerovnosti

Priorita: 1) Všechny operátory porovnání; 2) NE; 3) AND; 4) NEBO.

Při konstrukci složitých logických výrazů se používají závorky:

((podmínka1 AND podmínka2) NEBO NE(podmínka3 AND podmínka4 AND podmínka5)) NEBO (…)

Pomocí závorek můžete také změnit standardní posloupnost výpočtů.

Zde jsem se pokusil poskytnout představu o Booleově algebře v objemu dostatečném pro práci. Jak vidíte, pro psaní složitějších podmínek se bez logiky neobejdete, ale moc jí tu není (AND, OR a NE) a vymysleli ji lidé, takže je vše celkem logické.

Pojďme na konec druhého dílu

Jak vidíte, i o základní syntaxi operátoru SELECT se dá mluvit velmi dlouho, ale abychom zůstali v rozsahu článku, ukážu nakonec další logické operátory - BETWEEN, IN a LIKE.

BETWEEN – kontrola zařazení do rozsahu

Test_value BETWEEN počáteční_hodnota A koncová_hodnota

Výrazy mohou fungovat jako hodnoty.

Podívejme se na příklad:

VYBERTE ID,Jméno,Plat od zaměstnanců, KDE Mzda MEZI 2000 A 3000 -- kdo má plat v rozmezí 2000-3000

BETWEEN je ve skutečnosti zjednodušený zápis formuláře:

VYBERTE ID,Jméno,Plat od zaměstnanců WHERE Plat>=2000 A Plat<=3000 -- все у кого ЗП в диапозоне 2000-3000

Slovo NOT lze použít před slovem BETWEEN, které zkontroluje, zda hodnota není v určeném rozsahu:

VYBERTE ID,Jméno,Plat OD Zaměstn<=3000)

Pokud tedy použijete BETWEEN, IN, LIKE, můžete je také kombinovat s dalšími podmínkami pomocí AND a OR:

VYBERTE ID,Jméno,Plat OD Zaměstnanci WHERE Plat MEZI 2000 A 3000 -- kdo má plat v rozmezí 2000-3000 A DepartmentID=3 -- zohledněte pouze zaměstnance oddělení 3

IN – kontrola zařazení do seznamu hodnot

Tento operátor má následující tvar:

Test_value IN (hodnota1, hodnota2, ...)

Myslím, že je jednodušší ukázat na příkladu:

SELECT ID,Jméno,Mzda FROM Zaměstnanci WHERE PositionID IN(3,4) -- jejichž pozice je 3 nebo 4

Tito. to je v podstatě stejné jako následující výraz:

SELECT ID,Jméno,Plat od zaměstnanců WHERE PositionID=3 OR PositionID=4 – jejichž pozice je 3 nebo 4

V případě NOT to bude podobné (dostaneme všechny kromě těch z oddělení 3 a 4):

VYBERTE ID,Jméno,Plat od zaměstnanců WHERE PositionID NOT IN(3,4) -- podobné jako NOT(PositionID=3 OR PositionID=4)

Dotaz s NOT IN lze také vyjádřit pomocí AND:

VYBERTE ID,Jméno,Plat od zaměstnanců WHERE PositionID<>3AND PositionID<>4 – ekvivalentní PositionID NOT IN(3,4)

Upozorňujeme, že hledání hodnot NULL pomocí konstrukce IN nebude fungovat, protože kontrola NULL=NULL také vrátí NULL, nikoli True:

SELECT ID,Name,DepartmentID FROM Zaměstnanci WHERE DepartmentID IN(1,2,NULL) -- NULL záznamy nebudou zahrnuty do výsledku

V tomto případě rozdělte kontrolu na několik podmínek:

SELECT ID,Name,DepartmentID FROM Zaměstnanci WHERE DepartmentID IN(1,2) -- 1 nebo 2 OR DepartmentID IS NULL -- or NULL

Nebo můžete napsat něco jako:

SELECT ID,Name,DepartmentID FROM Zaměstnanci WHERE ISNULL(DepartmentID,-1) IN(1,2,-1) -- pokud jste si jisti, že neexistuje žádné oddělení s ID=-1

Myslím, že v tomto případě bude správnější a spolehlivější první možnost. Dobře, toto je jen příklad pro demonstraci toho, jaké další stavby lze postavit.

Za zmínku také stojí ještě zákeřnější chyba spojená s NULL, kterou lze udělat při použití konstruktu NOT IN. Zkusme například vybrat všechny zaměstnance kromě těch, jejichž oddělení je 1 nebo jejichž oddělení není uvedeno vůbec, tzn. rovná se NULL. Jako řešení se nabízí následující možnost:

VYBERTE ID,Jméno,ID oddělení FROM Zaměstnanci WHERE DepartmentID NOT IN(1,NULL)

Po provedení dotazu však neobdržíme jediný řádek, ačkoli jsme očekávali, že uvidíme následující:

Vtip zde opět zahrál NULL zadaný v seznamu hodnot.

Podívejme se, proč v tomto případě došlo k logické chybě. Rozšiřme dotaz pomocí AND:

VYBERTE ID,Jméno,ID oddělení FROM Zaměstnanci WHERE ID oddělení<>1 AND ID oddělení<>NULL -- problém je kvůli této kontrole NULL - tato podmínka vždy vrátí hodnotu NULL

Správný stav (ID oddělení<>NULL) nám zde vždy poskytne nejistotu, tzn. NULL. Nyní si zapamatujte pravdivostní tabulku pro operátor AND, kde (TRUE AND NULL) dává NULL. Tito. když je splněna levá podmínka (DepartmentID<>1) kvůli nedefinované správné podmínce skončíme s nedefinovanou hodnotou pro celý výraz (DepartmentID<>1 AND ID oddělení<>NULL), takže řetězec nebude zahrnut do výsledku.

Podmínku lze správně přepsat takto:

VYBERTE ID,Jméno,ID oddělení FROM Zaměstnanci, KDE NENÍ ID oddělení V(1) -- nebo v tomto případě pouze ID oddělení<>1 AND DepartmentID NENÍ NULL -- a samostatně zkontrolujte NOT NULL

IN lze také použít s poddotazy, ale k tomuto formuláři se vrátíme v dalších částech tohoto tutoriálu.

LIKE – kontrola řetězce pomocí vzoru

O tomto operátoru budu mluvit pouze v jeho nejjednodušší podobě, která je standardem a je podporována většinou dialektů jazyka SQL. I v této podobě jej lze použít k řešení mnoha problémů, které vyžadují kontrolu obsahu řetězce.

Tento operátor má následující tvar:

Testovací_řetězec LIKE vzor_řetězce

V „řetězec_vzoru“ lze použít následující speciální znaky:

  1. Podtržítko „_“ znamená, že jeho místo může zaujmout jakýkoli jednotlivý znak
  2. Znak procenta „%“ – říká, že jej lze nahradit libovolným počtem znaků, včetně žádných
Podívejme se na příklady se symbolem „%“ (v praxi se mimochodem používá častěji):

SELECT ID,Jméno FROM Zaměstnanci WHERE Jméno LIKE "Pet%" -- jehož jméno začíná písmeny "Pet" SELECT ID,LastName FROM Zaměstnanci WHERE Příjmení LIKE "%ov" -- jehož příjmení končí "ov" SELECT ID, Příjmení FROM Zaměstnanci WHERE Příjmení LIKE "%re%" -- jejichž příjmení obsahuje kombinaci "re"

Podívejme se na příklady se symbolem „_“:

SELECT ID,Příjmení FROM Zaměstnanci WHERE Příjmení LIKE "_etrov" -- jehož příjmení se skládá z libovolného prvního znaku a následujících písmen "etrov" SELECT ID,Příjmení FROM Zaměstnanci WHERE Příjmení LIKE "____ov" -- jehož příjmení se skládá z libovolných čtyř znaků a následující písmena "ov"

Pomocí ESCAPE můžete zadat znak escape, který zruší kontrolní efekt speciálních znaků "_" a "%". Tato klauzule se používá, když chcete přímo zkontrolovat znak procenta nebo podtržítko v řetězci.

Abychom předvedli ESCAPE, vložme odpadky do jednoho záznamu:

UPDATE Employees SET FirstName="Toto je koš obsahující %" WHERE ID=1005

A podívejme se, co vrátí následující dotazy:

SELECT * FROM Zaměstnanci WHERE Jméno LIKE "%!%%" ESCAPE "!" -- řádek obsahuje znak "%" SELECT * FROM Zaměstnanci WHERE Jméno LIKE "%!_%" ESCAPE "!" -- řádek obsahuje znak "_".

Pokud potřebujete zkontrolovat řetězec pro úplnou shodu, pak místo LIKE je lepší jednoduše použít znak „=“:

SELECT * FROM Zaměstnanci WHERE FirstName="Peter"

Jen poznámka.
V MS SQL si v šabloně operátoru LIKE můžete určit i hledání pomocí regulárních výrazů, přečtěte si o tom na internetu, pokud vám standardní možnosti tohoto operátoru nestačí.

ORACLE používá funkci REGEXP_LIKE k vyhledávání pomocí regulárních výrazů.

Něco málo o strunách

V případě kontroly řetězce na přítomnost znaků Unicode budete muset před uvozovky umístit znak N, tzn. N"…". Ale protože všechna pole znaků v naší tabulce jsou ve formátu Unicode (typ nvarchar), můžete pro tato pole vždy použít tento formát. Příklad:

SELECT ID,Jméno FROM Zaměstnanci WHERE Jméno LIKE N"Pet%" SELECT ID,Příjmení FROM Zaměstnanci WHERE Příjmení=N"Petrov"

Když to uděláte správně, při porovnávání s polem typu varchar (ASCII), měli byste zkusit použít testy pomocí "..." a při porovnávání pole s typem nvarchar (Unicode), měli byste zkusit použít testy pomocí N" ......". To se provádí, aby se zabránilo implicitním převodům typů během provádění dotazu. Stejné pravidlo používáme při vkládání (INSERT) hodnot do pole nebo jejich aktualizaci (UPDATE).

Při porovnávání řetězců stojí za zvážení toho, že v závislosti na nastavení databáze (kolování) může být porovnávání řetězců buď bez ohledu na malá a velká písmena (když "Petrov" = "PETROV"), nebo rozlišuje malá a velká písmena (když "Petrov"<>"PETROV").
V případě nastavení citlivého na velká a malá písmena, pokud chcete provést vyhledávání bez ohledu na malá a velká písmena, můžete například předběžně převést pravý a levý výraz na jeden případ – horní nebo dolní:

SELECT ID,Jméno FROM Zaměstnanci WHERE UPPER(Jméno) LIKE UPPER(N"Pet%") -- nebo LOWER(Jméno) LIKE LOWER(N"Pet%") SELECT ID,LastName FROM Zaměstnanci WHERE UPPER(LastName)=UPPER( N"Petrov") -- nebo LOWER(Příjmení)=LOWER(N"Petrov")

Něco málo o datech

Při kontrole data můžete použít, stejně jako u řetězců, jednoduché uvozovky „...“.

Bez ohledu na místní nastavení v MS SQL můžete použít následující syntaxi data "RRRRMMDD" (rok, měsíc, den společně bez mezer). MS SQL bude vždy rozumět tomuto formátu data:

VYBERTE ID,Jméno,Narozeniny FROM Zaměstnanci WHERE Birthday BETWEEN "19800101" A "19891231" -- zaměstnanci 80. let OBJEDNAT PODLE NAROZENÍ

V některých případech je výhodnější nastavit datum pomocí funkce DATEFROMPARTS:

VYBERTE ID,Jméno,Narozeniny FROM Zaměstnanci WHERE Birthday BETWEEN DATEFROMPARTS(1980,1,1) A DATEFROMPARTS(1989,12,31) OBJEDNAT DLE NAROZENÍ

Existuje také podobná funkce DATETIMEFROMPARTS, která slouží k nastavení Date a Time (pro typ datetime).

Funkci CONVERT můžete také použít, pokud potřebujete převést řetězec na hodnotu data nebo datetime:

SELECT CONVERT(datum,"12.03.2015"104); CONVERT(datumčas,"2014-11-30 17:20:15"120)

Hodnoty 104 a 120 udávají, který formát data je v řetězci použit. Popis všech platných formátů v knihovně MSDN naleznete vyhledáním „MS SQL CONVERT“.

V MS SQL je spousta funkcí pro práci s daty, hledejte „ms sql funkce pro práci s daty“.

Poznámka. Všechny dialekty jazyka SQL mají vlastní sadu funkcí pro práci s daty a uplatňují vlastní přístup k práci s nimi.

Něco málo o číslech a jejich proměnách

Informace v této části budou pravděpodobně užitečnější pro IT specialisty. Pokud nejste jedním z nich a vaším cílem je jednoduše naučit se psát dotazy, abyste získali informace, které potřebujete z databáze, pak možná nebudete potřebovat takové jemnosti, ale v každém případě můžete rychle procházet text a dělat si poznámky , protože . Pokud jste se dali na studium SQL, pak se již připojujete k IT.

Na rozdíl od konverzní funkce CAST může funkce CONVERT specifikovat třetí parametr, který je zodpovědný za převodní styl (formát). Různé datové typy mohou mít vlastní sadu stylů, což může ovlivnit vrácený výsledek. O použití stylů jsme se již dotkli při zvažování převodu řetězce pomocí funkce CONVERT na typy date a datetime.

Více o funkcích CAST, CONVERT a stylech si můžete přečíst v MSDN – „Funkce CAST a CONVERT (Transact-SQL)“: msdn.microsoft.com/ru-ru/library/ms187928.aspx

Pro zjednodušení příkladů zde budou použity příkazy jazyka Transact-SQL DECLARE a SET.

Samozřejmě, že v případě převodu celého čísla na reálné číslo (který jsem uvedl na začátku této lekce, abych demonstroval rozdíl mezi celým číslem a skutečným dělením), znalost nuancí převodu není tak kritická, protože tam jsme provedli převod celého čísla na skutečný (jehož rozsah je mnohem větší než rozsah celých čísel):

DECLARE @min_int int SET @min_int=-2147483648 DECLARE @max_int int SET @max_int=2147483647 SELECT -- (-2147483648) @min_int,CAST(@min_int AS float),CONVERT(float,@31478), -- ,CAST(@max_int AS float),CONVERT(float,@max_int), -- numeric(16,6) @min_int/1., -- (-2147483648,000000) @max_int/1. -- 2147483647,000000

Snad nemělo cenu upřesňovat způsob implicitní konverze získané dělením (1.), protože Je vhodné pokusit se provést explicitní převody pro větší kontrolu nad typem získaného výsledku. I když, pokud chceme získat výsledek typu numeric, se zadaným počtem číslic za desetinnou čárkou, pak můžeme použít trik v MS SQL, abychom vynásobili celočíselnou hodnotu (1., 1.0, 1.00 atd.) :

DECLARE @int int SET @int=123 SELECT @int*1., -- numeric(12, 0) - 0 desetinných míst @int*1.0, -- numeric(13, 1) - 1 desetinné místo @int*1.00, -- numeric(14, 2) - 2 znaky -- i když někdy je lepší provést explicitní převod CAST(@int AS numeric(20, 0)), -- 123 CAST(@int AS numeric(20, 1) ), -- 123,0 CAST(@int AS numeric(20, 2)) -- 123,00

V některých případech mohou být detaily konverze opravdu důležité, protože... ovlivňují správnost získaného výsledku např. v případě, kdy se provádí převod z číselné hodnoty na řetězec (varchar). Podívejme se na příklady převodu peněz a plovoucích hodnot na varchar:

Chování při převodu peněz na varchar DECLARE @money money SET @money = 1025,123456789 -- dojde k implicitní konverzi na 1025,1235, protože peněžní typ ukládá pouze 4 číslice za desetinnou čárkou SELECT @money, -- 1025.1235 -- ve výchozím nastavení se CAST a CONVERT chovají stejně (tj. zhruba řečeno je použit styl 0) CAST(@money as varchar(20)) , -- 1025,12 CONVERT(varchar(20), @peníze), -- 1025,12 CONVERT(varchar(20), @peníze, 0), -- 1025,12 (styl 0 - bez oddělovače tisícin a 2 desetinná místa (výchozí formát)) CONVERT( varchar(20), @peníze, 1), -- 1.025.12 (styl 1 – používá oddělovač tisícin a 2 desetinná místa) CONVERT(varchar(20), @peníze, 2) -- 1025.1235 (styl 2 – žádný oddělovač a 4 čísla za desetinnou čárkou)

Chování při převodu float na varchar DECLARE @float1 float SET @float1 = 1025,123456789 DECLARE @float2 float SET @float2 = 1231025,123456789 SELECT @float1, -- 1025,123452918 --4float 1025,123452918 --4 výchozí se CAST a CONVERT chovají stejně (tj. zhruba řečeno, používá se styl 0) -- styl 0 – ne více než 6 číslic. Exponenciální zápis se používá z nutnosti -- při převodu na varchar se zde stávají opravdu děsivé věci CAST(@float1 jako varchar(20)), -- 1025.12 CONVERT(varchar(20), @float1), -- 1025.12 CONVERT(varchar( 20), @float1, 0), -- 1025,12 CAST(@float2 jako varchar(20)), -- 1,23103e+006 CONVERT(varchar(20), @float2), -- 1,23103e+006 CONVERT(varchar( 20 ), @float2, 0), -- 1,23103e+006 -- styl 1 - Vždy 8 číslic. Vždy se používá vědecký zápis čísel.

-- tento styl pro float také není příliš přesný CONVERT(varchar(20), @float1, 1), -- 1.0251235e+003 CONVERT(varchar(20), @float2, 1), -- 1.2310251e+006 - - styl 2 - Vždy 16 bitů. Vždy se používá vědecký zápis čísel.

Pokud potřebujete explicitně řídit přesnost až do určitého znaménka, více než 4, pak je někdy lepší použít pro ukládání dat typ desítkové/číselné. Pokud stačí 4 znaky, pak můžete použít peněžní typ - přibližně odpovídá numerické (20,4).

Desetinná a numerická DECLARE @money money SET @money = 1025,123456789 -- 1025,1235 DECLARE @float1 float SET @float1 = 1025,123456789 DECLARE @float2 float SET @float2 = 10292 numerický (1231) ,9) SET @numeric = 1025,123456789 SELECT CAST ( @numeric jako varchar(20)), -- 1025,12345679 CONVERT(varchar(20), @numeric), -- 1025,12345679 CAST(@money jako numerické(28,9)), -- 1025,123500000 CAST(@float1 jako numerické 28 ,9)), -- 1025,123456789 CAST(@float2 jako numeric(28,9)) -- 1231025,123456789

Poznámka.
Od verze MS SQL 2008 můžete místo toho použít následující konstrukci:
  • ms sql server
  • Přidejte značky


    
    Nahoru