VALUES DEFAULT, ‘From Default’;-- GUID from function INSERT dbo.ProductCategory ProductCategoryID, ProductCategoryName VALUES NewID, ‘From Function’; -- GUID in variable DECLARE @NewGUID
Trang 1VALUES (DEFAULT, ‘From Default’);
GUID from function INSERT dbo.ProductCategory (ProductCategoryID, ProductCategoryName)
VALUES (NewID(), ‘From Function’);
GUID in variable DECLARE @NewGUID UniqueIdentifier;
SET @NewGUID = NewID();
INSERT dbo.ProductCategory (ProductCategoryID, ProductCategoryName)
VALUES (@NewGUID, ‘From Variable’);
To view the results of the previous three methods of inserting a GUID, the followingSELECTstatement
is filtered to those rows that arelike `From %´:
SELECT ProductCategoryID, ProductCategoryName FROM dbo.ProductCategory
WHERE ProductCategoryName like ‘From %’;
Result:
ProductCategoryID ProductCategoryName - -25894DA7-B5BB-435D-9540-6B9207C6CF8F From Default
393414DC-8611-4460-8FD3-4657E4B49373 From Function FF868338-DF9A-4B8D-89B6-9C28293CA25F From Variable ThisINSERTstatement uses theNEWID()function to insert multiple GUIDs:
INSERT dbo.ProductCategory (ProductCategoryID, ProductCategoryName)
Select NewID(), LastName
From CHA2.dbo.Guide;
The followingSELECTstatement retrieves the new GUIDs:
SELECT ProductCategoryID, ProductCategoryName
FROM dbo.ProductCategory;
Result:
ProductCategoryID ProductCategoryName - -1B2BBE15-B415-43ED-BCA2-293050B7EFE4 Kite
23FC5D45-8B60-4800-A505-D2F556F863C9 Accessory 3889671A-F2CD-4B79-8DCF-19F4F4703693 Video
.
Trang 25471F896-A414-432B-A579-0880757ED097 Fletcher
428F29B3-111B-4ECE-B6EB-E0913A9D34DC Atlas
E4B7D325-8122-48D7-A61B-A83E258D8729 Bistier
The final GUID insert example features my recommended method,NEWSEQUENTIALID() The function
is defined as the default for the primary key column Three rows are inserted and then selected:
USE tempdb;
CREATE TABLE GUIDtable (
GUIDtableID UNIQUEIDENTIFIER NOT NULL
DEFAULT (NewSequentialID())
PRIMARY KEY,
Col1 CHAR(1),
);
INSERT GUIDtable (Col1)
VALUES (’a’),
(’b’),
(’c’);
SELECT GUIDtableID, Col1
FROM GUIDtable;
Result:
748040E1-210D-DE11-8196-002170BF2EB9 a
758040E1-210D-DE11-8196-002170BF2EB9 b
768040E1-210D-DE11-8196-002170BF2EB9 c
SQL Server provides the flexibility of two excellent candidates for surrogate key generation Whether the
database relies on identity columns or GUIDs may be based on other factors Either way, there are
mul-tiple methods for inserting new rows You, as the SQL developer or DBA, are in control
If a column has a unique index (even if it’s not a key), then attempting to insert a new
value, or an update to a new value that’s already in use, will fail.
Typically, the entire transaction, including all the inserted or updated rows, will fail However, there’s
an index option, IGNORE DUP KEY , that enables the transaction to succeed with only a warning, and just
skips any duplicate rows This should only be used for staging tables in a scenario where an external
application may accidentally include the same data more than once.
Deleting Duplicate Rows
A common question on the newsgroups is ‘‘How can I delete a single row when I don’t have a
primary key?’’
Trang 3< rant>The first order of business is to question why the table doesn’t have a primary key.
Without a primary key, it’s not a legitimate table My beef with SQL is that it even allows
a table without a primary key Horrors! One reason I like policy-based management is that it can be
configured to require a primary key on every table As soon as the duplicates are deleted, be sure to
apply a primary key to the table.</rant>
Fortunately, there are several methods to clean up duplicate data The following sections include the
windowing, surrogate key, andSELECT DISTINCT INTOmethods
To experiment with duplicate data, the following script sets up a poorly designed (no primary key) table
and inserts some duplicate data:
USE tempdb ; go
CREATE TABLE DupsNoPK ( Col1 INT NULL, Col2 CHAR(5) NULL );
go Insert multiple dup rows (can be executed mulitple times) INSERT DupsNoPK (Col1, Col2)
VALUES (1, ‘abc’),
(2, ‘abc’), (2, ‘abc’), (2, ‘abc’), (7, ‘xyz’), (7, ‘xyz’) ;
To verify that the table does in fact have duplicate data, the following query uses aGROUP BYand
HAVINGclause to return only the duplicated rows, with a count of the number of duplicates:
SELECT Col1, Col2, COUNT(*) AS DupCount FROM DupsNoPK
GROUP BY Col1, Col2 HAVING COUNT(*) > 1;
Result:
Col1 Col2 DupCount -
Deleting duplicate rows using windowing
Of the three methods to remove duplicate rows, this method is the most straightforward because it
doesn’t need to alter the table or generate a second table
Trang 4The key to this method is using the windowing’sOVER()clause with aROW_NUMBER()function and
a partition The partition will begin renumbering with every new partition Set theOVER()clause to
PARTITION BYevery column to be checked for duplicate data In this case, every column is being
checked
Running the windowing query first shows how it applies the row number:
SELECT Col1, Col2,
ROW_NUMBER() OVER (PARTITION BY Col1, Col2 ORDER BY Col1) AS rn
FROM DupsNoPK
Result:
- -
Every duplicate row has anrnvalue of greater than 1, so it’s now easy to delete the duplicates:
WITH DupsNumbered
AS (
SELECT Col1, Col2,
ROW_NUMBER() OVER (PARTITION BY Col1, Col2 ORDER BY Col1) AS rn
FROM DupsNoPK
)
DELETE DupsNumbered
WHERE rn > 1;
The nextSELECTtests the effect of the windowing remove duplicates query:
SELECT Col1, Col2
FROM DupsNoPK;
Result:
-
Deleting duplicate rows using a surrogate key
A traditional method of removing duplicate rows uses a surrogate key to uniquely identify each row
This means the table itself must be altered to add the surrogate key column
Trang 5Assuming theDupsNoPKtable is reset with the original rows, the following script applies anIDENTITY
surrogate key and looks at the altered table:
ALTER TABLE dbo.DupsNoPK ADD
PK INT IDENTITY
NOT NULL CONSTRAINT PK_DupsNoPK PRIMARY KEY;
SELECT * FROM DupsNoPK;
Result:
-
To search and destroy the duplicate data, the next query finds and deletes all the rows with matching
Col1andCol2data but higher primary key values:
DELETE DupsNoPK WHERE EXISTS ( SELECT *
FROM DupsNoPK AS D1 WHERE D1.Col1 = DupsNoPK.Col1 AND D1.Col2 = DupsNoPK.Col2 AND D1.PK > DupsNoPK.PK );
SELECT * FROM DupsNoPK;
Result:
-
Deleting duplicate rows using select distant into
The third method of removing duplicate data may seem crude, but if the goal is to remove duplicates
while creating a new table — perhaps as part of an ETL process — it may be the best choice
Trang 6ASELECT DISTINCTwill automatically pass the data through a filter that eliminates duplicate rows.
TheINTOoption causes the results of the select to be placed into a new table instead of going to the
client application Mix the two options together and you have an instant duplicate row remover
Again, assuming theDupsNoPKtable is reset with its original duplicate data, the following query
gener-ates a new table without duplicgener-ates and then examines the contents of the new table:
SELECT distinct Col1, Col2 INTO NoDups
FROM DupsNoPK;
SELECT Col1, Col2
FROM NoDups;
Result:
-
Foreign Key Constraints
Foreign keys may affectINSERT,UPDATE, andDELETEcommands by blocking those operations
Inserting a new secondary table row with a foreign key value that doesn’t match an existing primary key
will cause the secondary row insert to fail
In the following insert example, theProductCategoryIDsupplied does not exist in the
ProductCategorytable This causes the foreign key constraint to block theINSERToperation,
as the error message indicates:
Foreign Key: Insert Obstacle
INSERT Product (ProductID, Code,
ProductCategoryID, ProductName)
VALUES (’9562C1A5-4499-4626-BB33-E5E140ACD2AC’,
‘999’
‘DB8D8D60-76F4-46C3-90E6-A8648F63C0F0’,
‘Basic Box Kite 21"’);
Result:
Server: Msg 547, Level 16, State 1, Line 1
INSERT statement conflicted with COLUMN FOREIGN KEY
constraint ‘FK Product Product 7B905C75’
The conflict occurred in database ‘OBXKites’,
table ‘ProductCategory’, column ‘ProductCategoryID’
The statement has been terminated
Note that because every GUID is unique, the GUIDs you use on your system will be different
Trang 7Foreign key constraints can also block updates to either the primary or the secondary table If the
pri-mary key is updated and a foreign key is pointed to that pripri-mary key, then the update will fail
In the following sample code, the update is blocked because the secondary table update is trying to set
the foreign key,ProductCategoryID, to a value that does not exist in theProductCategorytable:
Foreign Key: Secondary table Update Obstacle UPDATE Product
SET ProductCategoryID =
‘DB8D8D60-76F4-46C3-90E6-A8648F63C0F0’
WHERE ProductID = ‘67804443-7E7C-4769-A41C-3DD3CD3621D9’;
Result:
Server: Msg 547, Level 16, State 1, Line 1 UPDATE statement conflicted with COLUMN FOREIGN KEY Constraint ‘FK Product Product 7B905C75’
The conflict occurred in database ‘OBXKites’, table ‘ProductCategory’, column ‘ProductCategoryID’
The statement has been terminated
If foreign keys are pointing to a primary key, updating the primary key to a new value has the same
effect as deleting a primary table row with an existing secondary table row referring to it In both cases
the error is caused not by the primary key but by the foreign key referencing the primary key
In the following code, the error is generated not by theProductCategorytable, even though it is the
table being updated, but by theProducttable This is because theProducttable has both the row
and the foreign key reference constraint that will be violated if the primary key value no longer exists:
Foreign Key: Primary table Update Obstacle UPDATE ProductCategory
SET ProductCategoryID =
‘DB8D8D60-76F4-46C3-90E6-A8648F63C0F0’
WHERE ProductCategoryID =
‘1B2BBE15-B415-43ED-BCA2-293050B7EFE4’;
Result:
Server: Msg 547, Level 16, State 1, Line 1 UPDATE statement conflicted with COLUMN REFERENCE constraint
’FK Product Product 7B905C75’ The conflict occurred
in database ‘OBXKites’, table ‘Product’, column ‘ProductCategoryID’
The statement has been terminated
For more information about creating unique index constraints, refer to Chapter 20, ‘‘Creat-ing the Physical Database Schema.’’
Trang 8Null and Default Constraints
Column nullability and defaults may affectINSERTandUPDATEoperations AnINSERTorUPDATE
operation can send one of four possible values to a table column: data values,null,default, or
noth-ing at all The table column can be configured with a default value and nullability
Table 16-2 indicates the result of the operation according to the column configuration, and the new
value to be inserted or updated For example, if the column properties are set so that the column has a
default and does not accept nulls (see the far-right column) and the SQL insert or update sends a null,
then the result is an error
TABLE 16-2
Data Modifications, Defaults, and Nulls
Column Properties
No default, allow null
No default, not allow null
Has default, allow null
Has default, not allow null
nothing sent null most common
error
default default
By far, the most common error in the table is submitting nothing when no default exists and nulls are
not permitted
For more information about dealing with nulls when retrieving data, see Chapter 9, ‘‘Data
Types, Expressions, and Scalar Functions.’’
Check Constraints
Check constraints may affectINSERTandUPDATEoperations
Each table column may have multiple check constraints These are fast Boolean operations that
deter-mine whether the update will pass or fail
Trang 9The following check constraint permits Dr Johnson’s insert but blocks Greg’s insert (note that the check
constraint is already applied to the database by theCreate_CHA2.sqlscript):
USE CHA2;
go ALTER TABLE dbo.Guide ADD CONSTRAINT CK_Guide_Age21 CHECK (DateDiff(yy,DateOfBirth, DateHire)
>= 21);
The following query inserts Dr Johnson’s data Because she was 26 years old at the time of hire, her
row is accepted by the check constraint:
INSERT Guide(LastName, FirstName, Qualifications, DateOfBirth, DateHire) VALUES (’Johnson’, ‘Mary’,
‘E.R Physician’, ‘19710114’, ‘19970601’);
Greg, conversely, was only 18 at the time he applied, so his insert is rejected by the check constraint:
INSERT Guide (LastName, FirstName, Qualifications, DateOfBirth, DateHire) VALUES (’Franklin’, ‘Greg’,
‘Guide’, ‘19831212’, ‘20020101’);
Result:
Server: Msg 547, Level 16, State 1, Line 1 INSERT statement conflicted with TABLE CHECK constraint
’CK_Guide_Age21’
The conflict occurred in database ‘CHA2’, table ‘Guide’
The statement has been terminated
Instead of Triggers
INSTEAD OFtriggers may affectINSERT,UPDATE, andDELETEoperations
Triggers are special stored procedures that are attached to a table and fire when certain
data-modification operations hit that table Two types of triggers exist:INSTEAD OFandAFTER They differ
both in their timing and in how they handle the data-modification operation
AnINSTEAD OFtrigger always causes theINSERT,UPDATE, orDELETEoperation to be canceled
The SQL command submitted to SQL Server is discarded by theINSTEAD OFtrigger; the code within
theINSTEAD OFtrigger is executed instead of the submitted SQL command, hence the name The
INSTEAD OFtrigger might be programmed to repeat the requested operation so that it looks like it
went through, or it could do something else altogether
The problem with theINSTEAD OFtrigger is that it reports back ‘‘n row(s) affected’’ when in fact
noth-ing is written to the database There is no error warnnoth-ing because theINSTEAD OFtrigger works
prop-erly; however, the operation doesn’t go through
Trang 10In the following code sample, theInsteadOfDemotrigger causes theINSERToperation to disappear
into thin air:
USE CHA2;
go
CREATE TRIGGER InsteadOfDemo
ON Guide
INSTEAD OF INSERT
AS
Print ‘Instead of trigger demo’;
With theINSTEAD OFtrigger in place, the following query inserts a test row:
INSERT Guide(lastName, FirstName,
Qualifications, DateOfBirth, DateHire)
VALUES (’Jamison’, ‘Tom’,
‘Biologist, Adventurer’, ‘19560114’, ‘19990109’);
Result:
Instead of trigger demo
(1 row(s) affected)
TheINSERToperation appears to have worked, but is the row in the table?
SELECT GuideID
FROM Guide
WHERE LastName = ‘Jamison’;
Result:
GuideID
-(0 row(s) affected)
Building triggers is explained in detail in Chapter 26, ‘‘Creating DML Triggers.’’ The flow of
data-modification transactions and the timing of triggers are also discussed in Chapter 66,
‘‘Managing Transactions, Locking, and Blocking.’’
Note that the sample code for this chapter drops theInsteadOfDemotrigger before moving on
After Triggers
AFTERtriggers may affectINSERT,UPDATE, andDELETEoperations
AFTERtriggers are often used for complex data validation These triggers can roll back, or undo,
the insert, update, or delete if the code inside the trigger doesn’t like the operation in question The
code can then do something else, or it can just fail the transaction However, if the trigger doesn’t