MS Sql 70-461: Chapter 10

Les 1

INSERT VALUES

Met het volgende stament kan een rij worden aangemaakt in de MyOrders tabel

INSERT INTO Sales.MyOrders(custid, empid, orderdate, shipcountry, freight) VALUES(2, 19, '20120620', N'USA', 30.00);

Het opgeven van de kolomnamen na de tabel is optioneel, maar wel een best practice. De naam van het identity veld (id) is niet opgegeven omdat deze automatisch wordt gevuld door Sql. Als toch een id moet worden opgegeven, dan moet gebruik gemaakt worden van de IDENTITY_INSERT optie:

SET IDENTITY_INSERT ON;

Na de INSERT moet de identity weer worden uitgezet:

SET IDENTITY_INSERT OFF;

Om deze optie te gebruiken moet de gebruiker eigenaar van de tabel zijn of ALTER permissies hebben op de tabel.

Als bij het toevoegen van een rij geen waarde wordt opgegeven voor een kolom, dan wordt gebruik gemaakt van de DEFAULT constraint, indien aanwezig. Een andere manier is door gebruik te maken van de DEFAULT keyword:

INSERT INTO Sales.MyOrders(custid, empid, orderdate, shipcountry, freight) 
VALUES(3, 17, DEFAULT, N'USA', 30.00);

Als geen waarde wordt opgegeven voor een kolom gaat Sql Server eerst kijken of de kolom zijn waarde automatisch krijgt (IDENTITY property of default constraint). Als dat niet het geval is gaat Sql Server na of de kolom NULLs toestaat, alls dat niet zo is, treedt er een fout op.

Meerdere rijen kunnen als volgt in één statement worden toegevoegd in één transactie:

INSERT INTO Sales.MyOrders(custid, empid, orderdate, shipcountry, freight) 
VALUES (2, 11, '20120620', N'USA', 50.00), 
 (5, 13, '20120620', N'USA', 40.00), 
 (7, 17, '20120620', N'USA', 45.00);

INSERT SELECT

Dit statement voegt het resultaat van een query toe een de opgegeven tabel:

SET IDENTITY_INSERT Sales.MyOrders ON;
INSERT INTO Sales.MyOrders(orderid, custid, empid, orderdate, shipcountry, freight)
 SELECT orderid, custid, empid, orderdate, shipcountry, freight
 FROM Sales.Orders
 WHERE shipcountry = N'Norway';
SET IDENTITY_INSERT Sales.MyOrders OFF;

INSERT EXEC

Met dit statament kan het resultaat van een dynamische batch of SP worden toegevoegd aan een query:

SET IDENTITY_INSERT Sales.MyOrders ON;
INSERT INTO Sales.MyOrders(orderid, custid, empid, orderdate, shipcountry, freight)
 EXEC Sales.OrdersForCountry @country = N'Portugal';
SET IDENTITY_INSERT Sales.MyOrders OFF;

SELECT INTO

Het SELECT INTO statement maakt een tabel aan op basis van de definitie van de brontabel in voegt het resultaat van de query toe aan de nieuwe tabel. Aspecten die worden gekopieerd van de brontabel zijn namen, types, nullability en IDENTITY property. Aspecten die niet worden gekopieerd zijn indexes, triggers, permissions en meer.

SELECT orderid, custid, orderdate, shipcountry, freight
INTO Sales.MyOrders
FROM Sales.Orders
WHERE shipcountry = N'Norway';

De definitie van de kolommen van de nieuwe tabel kan worden gemanipuleerd:

SELECT
 ISNULL(orderid + 0, -1) AS orderid, -- get rid of IDENTITY property
                                                              -- make column NOT NULL
 ISNULL(custid, -1) AS custid, -- make column NOT NULL
 empid,
 ISNULL(CAST(orderdate AS DATE), '19000101') AS orderdate, -- create DATE column instead DATETIME
 shipcountry, freight
INTO Sales.MyOrders
FROM Sales.Orders
WHERE shipcountry = N'Norway';

Een voordeel van SELECT INTO is als het recovery model niet op 'full' staat, er minimaal gelogd wordt en daardoor de insert sneller wordt uitgevoerd.

Les 2

UPDATE statement

Een standaard UPDATE statement ziet er als volgt uit:

UPDATE Sales.MyOrderDetails
 SET discount += 0.05
WHERE orderid = 10251;

UPDATE based on join

Standaard Sql ondersteund geen joins in UPDATE statements, T-Sql wel:

UPDATE OD
 SET OD.discount += 0.05
FROM Sales.MyCustomers AS C
 INNER JOIN Sales.MyOrders AS O
 ON C.custid = O.custid
 INNER JOIN Sales.MyOrderDetails AS OD
 ON O.orderid = OD.orderid
WHERE C.country = N'Norway';

Nondeterministic UPDATE

Een statement in nondeterministic als meerdere rijen van de bron overeenkomen met één doel rij. Als dit voorkomt, dan voert Sql Server toch de update uit en selecteert een willekeurige rij van de brontabel.

UPDATE en Table Expressions

Het is ook mogelijk om een update uit te voeren middels een table expressie zoals CTEs en derived tables. Het voordeel hiervan is dat in SSMS de SELECT statement geselecteerd kan worden zodat het resultaat getoond wordt van datgaan dat wordt bijgewerkt zonder de update uit te voeren:

WITH C AS
(
 SELECT 
   TGT.custid,
   TGT.country AS tgt_country, 
   SRC.country AS src_country,
   TGT.postalcode AS tgt_postalcode, 
   SRC.postalcode AS src_postalcode
 FROM Sales.MyCustomers AS TGT
 INNER JOIN Sales.Customers AS SRC
 ON TGT.custid = SRC.custid
)
UPDATE C
 SET tgt_country = src_country,
 tgt_postalcode = src_postalcode;

Ditzelfde kan ook met een derived table:

UPDATE D
 SET tgt_country = src_country,
 tgt_postalcode = src_postalcode
FROM (
 SELECT TGT.custid,
   TGT.country AS tgt_country, 
   SRC.country AS src_country,
   TGT.postalcode AS tgt_postalcode, 
   SRC.postalcode AS src_postalcode
 FROM Sales.MyCustomers AS TGT
 INNER JOIN Sales.Customers AS SRC
   ON TGT.custid = SRC.custid
 ) AS D;

UPDATE based on a variable

Het resultaat van een waarde die wordt bijgewerkt kan opgeslagen worden in een variabele:

DECLARE @newdiscount AS NUMERIC(4, 3) = NULL;

UPDATE Sales.MyOrderDetails
 SET @newdiscount = discount += 0.05
WHERE orderid = 10250
 AND productid = 51;

SELECT @newdiscount;

Deze query update eerst de kolom discount met 5 procent en zet vervolgens de nieuwe waarde in de variabele @newdiscount.

UPDATE all-at-once

Alle kolommen die in de SET worden bijgewerkt, worden conceptueel op hetzelfde moment uitgevoerd. 

DECLARE @add AS INT = 10;

UPDATE dbo.T1
 SET col1 += @add, col2 = col1
WHERE keycol = 1;

SELECT * FROM dbo.T1;

Deze query zal niet de nieuwe waarde van col1 (waarde col1 + 10) in col2 plaatsen, maar de originele waarde van col1.

Les 3

In Sql Server kunnen op twee manieren rijen verwijderd worden uit een tabel, namelijk met het DELETE statement en het TRUNCATE statement.

DELETE statement

DELETE FROM Sales.MyOrderDetails
WHERE productid = 11;

Bovenstaand statement verwijderd alle order details met product i 11. De WHERE clause is optioneel. Zonder deze clause worden alle rijen verwijderd in de tabel.
Een DELETE statement wordt volledig gelogd, dus bij het verwijderen van heel veel data kan het verwijderen lang duren. Bijkomend nadeel is dat hij transaction log erg toeneemt in grootte. Om dit probleem te verhelpen kan gebruik gemaakt worden van een loop:

WHILE 1 = 1
BEGIN
 DELETE TOP (1000) FROM Sales.MyOrderDetails
 WHERE productid = 12;
 IF @@rowcount < 1000 BREAK;
END

TRUNCATE statement

TRUNCATE verwijderd alle rijen van een tabel en ondersteund niet de WHERE clause.

TRUNCATE TABLE Sales.MyOrderDetails;

Belangrijke verschillen tussen DELETE en TRUNCATE zijn:
- TRUNCATE schrijft veel minder weg in het log dan DELETE. TRUNCATE logt enkel welke pages zijn gedealloceerd
- DELETE reset de IDENTITY kolom niet, terwijl TRUNCATE dit wel doet. Als de identity value toch bewaard moet blijven bij een truncate, dan kan dit met een variabele icm de IDENT_CURRENT function.
- Het DELETE statement kan rijen verwijderen met een FK. TRUNCATE kan dit niet, ook al verwijzen de rijen niet naar rijen in de base table. 
- Het DELETE statement kan worden toegepast op een indexed view, TRUNCATE niet.
- Het DELETE statement heeft DELETE permissies nodig om te worden uitgevoerd en TRUNCATE ALTER permissies.

DELETE based in a join

Het DELETE statement ondersteund het gebruik van joins:

DELETE FROM O
FROM Sales.MyOrders AS O
 INNER JOIN Sales.MyCustomers AS C
 ON O.custid = C.custid
WHERE C.country = N'USA';

Een subquery is ook toegestaan:

DELETE FROM Sales.MyOrders
WHERE EXISTS
 (SELECT *
 FROM Sales.MyCustomers
 WHERE MyCustomers.custid = MyOrders.custid
 AND MyCustomers.country = N'USA');

Beide statements kennen geen verschil que performance omdat ze beide op dezelfde manier worden geoptimaliseerd. De subquery wordt wel als standaard beschouwd.

DELETE using Table Expression

Ook worden CTEs en derived tables ondersteund om rijen te verwijderen:

WITH OldestOrders AS
(
 SELECT TOP (100) *
 FROM Sales.MyOrders
 ORDER BY orderdate, orderid
)
DELETE FROM OldestOrders;

Reacties

Populaire posts van deze blog

[SQL Server] varchar vs nvarchar

MS Sql 70-461: Chapter 5

[C#] Class serialiseren en deserialiseren