🎯 Mục tiêu bài học
Sau bài học này, bạn sẽ:
- ✅ Nắm vững các Numeric Types: INT, DECIMAL, FLOAT, MONEY
- ✅ Biết chọn đúng String Types: CHAR, VARCHAR, NVARCHAR
- ✅ Hiểu Date/Time Types và cách sử dụng
- ✅ Biết về Binary, Special Types và Computed Columns
- ✅ Thành thạo Data Type Conversion
🔍 Tổng quan Data Types
Chọn đúng Data Type rất quan trọng vì ảnh hưởng đến:
- Storage - Dung lượng lưu trữ
- Performance - Hiệu năng query
- Data Integrity - Ngăn chặn dữ liệu không hợp lệ
- Functionality - Các phép toán có thể thực hiện
SQL Server Data Types
Checkpoint
Chọn sai Data Type có thể gây ra những vấn đề gì về Storage, Performance và Data Integrity?
📊 Numeric Types
Integer Types
| Type | Storage | Range | Use Case |
|---|---|---|---|
| TINYINT | 1 byte | 0 to 255 | Status codes, flags |
| SMALLINT | 2 bytes | -32,768 to 32,767 | Small counters |
| INT | 4 bytes | -2.1 billion to 2.1 billion | Most IDs, quantities |
| BIGINT | 8 bytes | ±9.2 quintillion | Large IDs, big numbers |
| BIT | 1 bit | 0, 1, NULL | Boolean flags |
1-- Integer examples2CREATE TABLE Product (3 ProductID INT IDENTITY(1,1) PRIMARY KEY, -- INT cho ID4 CategoryID SMALLINT, -- SMALLINT cho lookup5 Quantity INT, -- INT cho quantity6 ViewCount BIGINT DEFAULT 0, -- BIGINT cho counters lớn7 IsActive BIT DEFAULT 1, -- BIT cho boolean8 Priority TINYINT DEFAULT 0 -- TINYINT cho 0-2559);1011-- AdventureWorks example12SELECT 13 ProductID, -- INT14 SafetyStockLevel, -- SMALLINT15 ReorderPoint -- SMALLINT16FROM Production.Product17WHERE ProductID = 1;Exact Numeric (DECIMAL/NUMERIC)
1-- DECIMAL(p, s) = NUMERIC(p, s)2-- p = precision (tổng số digits, max 38)3-- s = scale (số digits sau decimal point)45CREATE TABLE Financial (6 Amount DECIMAL(10, 2), -- 12345678.90 (8 digits + 2 decimals)7 Rate DECIMAL(5, 4), -- 0.0525 (1 digit + 4 decimals)8 Percentage DECIMAL(5, 2), -- 100.00 (3 digits + 2 decimals)9 TaxRate NUMERIC(4, 3) -- 0.085 (tax 8.5%)10);1112-- Storage by precision13-- 1-9 digits: 5 bytes14-- 10-19 digits: 9 bytes15-- 20-28 digits: 13 bytes16-- 29-38 digits: 17 bytes💡 Best Practice: Dùng
DECIMAL(19, 4)cho tiền tệ thay vìMONEYđể có control tốt hơn.
Approximate Numeric (FLOAT/REAL)
1-- FLOAT(n) - n là số bits cho mantissa2-- REAL = FLOAT(24) = 4 bytes3-- FLOAT = FLOAT(53) = 8 bytes45CREATE TABLE Scientific (6 Measurement FLOAT, -- Scientific calculations7 Temperature REAL, -- Less precision needed8 Latitude FLOAT(24), -- Coordinates9 Longitude FLOAT(24)10);1112-- ⚠️ WARNING: FLOAT có rounding errors!13DECLARE @f FLOAT = 0.1 + 0.2;14SELECT @f; -- 0.30000000000000004 (không chính xác!)1516-- ✅ Dùng DECIMAL cho financial calculations17DECLARE @d DECIMAL(10, 2) = 0.1 + 0.2;18SELECT @d; -- 0.30 (chính xác!)Money Types
1-- MONEY vs SMALLMONEY2-- MONEY: -922 trillion to 922 trillion (8 bytes)3-- SMALLMONEY: -214,748.3648 to 214,748.3647 (4 bytes)45CREATE TABLE Transaction (6 Amount MONEY, -- Large amounts7 Fee SMALLMONEY -- Small amounts8);910-- AdventureWorks uses MONEY11SELECT 12 ProductID,13 StandardCost, -- MONEY14 ListPrice -- MONEY15FROM Production.Product16WHERE ProductID = 1;1718-- ⚠️ MONEY có precision issues với division19DECLARE @m1 MONEY = 1.00, @m2 MONEY = 3.00;20SELECT @m1 / @m2; -- 0.3333 (chỉ 4 decimal places)2122-- ✅ Recommend: DECIMAL(19, 4) cho financialCheckpoint
Tại sao nên dùng DECIMAL(19, 4) thay vì MONEY cho financial calculations? FLOAT có vấn đề gì?
📝 String Types
Non-Unicode (CHAR, VARCHAR)
1-- CHAR(n) - Fixed length (1 to 8000)2-- VARCHAR(n) - Variable length (1 to 8000)3-- VARCHAR(MAX) - Up to 2GB45CREATE TABLE Product (6 SKU CHAR(10), -- Fixed 10 chars, padded with spaces7 ProductCode VARCHAR(20), -- Variable up to 20 chars8 Description VARCHAR(MAX) -- Large text9);1011-- Storage12-- CHAR(10): Always 10 bytes13-- VARCHAR(10): 1-10 bytes + 2 bytes overhead14-- VARCHAR(MAX): 2 bytes + actual length (up to 2GB)1516-- ⚠️ CHAR pads with spaces17DECLARE @c CHAR(10) = 'ABC';18SELECT LEN(@c), DATALENGTH(@c); -- LEN=3, DATALENGTH=10Unicode (NCHAR, NVARCHAR)
1-- N = National/Unicode2-- Supports international characters (Vietnamese, Chinese, etc.)3-- Uses 2 bytes per character (UTF-16)45CREATE TABLE Customer (6 FirstName NVARCHAR(50), -- Vietnamese: "Nguyễn"7 LastName NVARCHAR(50), -- Japanese: "田中"8 Email VARCHAR(100), -- ASCII only9 Bio NVARCHAR(MAX) -- Large Unicode text10);1112-- Storage13-- NCHAR(10): Always 20 bytes (10 × 2)14-- NVARCHAR(10): 2-20 bytes + 2 bytes overhead1516-- Insert Unicode data17INSERT INTO Customer (FirstName, LastName)18VALUES (N'Nguyễn', N'Văn A'); -- Prefix N'' for Unicode literal💡 Best Practice cho Vietnamese:
- Luôn dùng
NVARCHARcho text tiếng Việt- Dùng prefix
N''khi insert literal
AdventureWorks String Usage
1-- AdventureWorks dùng NVARCHAR cho names2SELECT 3 c.COLUMN_NAME,4 c.DATA_TYPE,5 c.CHARACTER_MAXIMUM_LENGTH6FROM INFORMATION_SCHEMA.COLUMNS c7WHERE c.TABLE_SCHEMA = 'Person' 8AND c.TABLE_NAME = 'Person'9AND c.DATA_TYPE LIKE '%char%';1011-- FirstName NVARCHAR(50)12-- MiddleName NVARCHAR(50)13-- LastName NVARCHAR(50)Choosing String Type
| Need | Type | Example |
|---|---|---|
| Fixed-length code | CHAR | SKU, Country Code |
| Variable ASCII | VARCHAR | Email, URL |
| International text | NVARCHAR | Names, Addresses |
| Large text | VARCHAR(MAX) | Articles, Logs |
| Large Unicode | NVARCHAR(MAX) | Documents |
Checkpoint
Khi nào dùng NVARCHAR thay vì VARCHAR? Tại sao NVARCHAR quan trọng cho tiếng Việt?
⚡ Date/Time Types
Date Types Comparison
| Type | Storage | Range | Precision | Use Case |
|---|---|---|---|---|
| DATE | 3 bytes | 0001-01-01 to 9999-12-31 | 1 day | Birthdate, dates only |
| TIME | 3-5 bytes | 00:00:00 to 23:59:59 | 100ns | Time only |
| DATETIME | 8 bytes | 1753-9999 | 3.33ms | Legacy |
| DATETIME2 | 6-8 bytes | 0001-9999 | 100ns | Recommended |
| SMALLDATETIME | 4 bytes | 1900-2079 | 1 minute | Approximate |
| DATETIMEOFFSET | 8-10 bytes | 0001-9999 | 100ns | With timezone |
1CREATE TABLE Event (2 EventID INT IDENTITY(1,1) PRIMARY KEY,3 EventDate DATE, -- Date only4 StartTime TIME(0), -- Time, no fractions5 CreatedAt DATETIME2(3), -- Millisecond precision6 ModifiedAt DATETIME2(7) DEFAULT SYSDATETIME(), -- Max precision7 ScheduledTime DATETIMEOFFSET -- With timezone8);910-- Insert examples11INSERT INTO Event (EventDate, StartTime, CreatedAt, ScheduledTime)12VALUES (13 '2024-01-15', -- DATE14 '09:30:00', -- TIME15 '2024-01-15T09:30:00.123', -- DATETIME216 '2024-01-15T09:30:00+07:00' -- DATETIMEOFFSET (Vietnam)17);Date Functions
1-- Current date/time2SELECT 3 GETDATE() AS DateTime, -- DATETIME4 SYSDATETIME() AS DateTime2, -- DATETIME2(7)5 GETUTCDATE() AS UTCDateTime, -- UTC DATETIME6 SYSDATETIMEOFFSET() AS WithOffset; -- DATETIMEOFFSET78-- Date parts9SELECT 10 YEAR(GETDATE()) AS Year,11 MONTH(GETDATE()) AS Month,12 DAY(GETDATE()) AS Day,13 DATEPART(WEEKDAY, GETDATE()) AS Weekday;1415-- Date calculations16SELECT 17 DATEADD(DAY, 7, GETDATE()) AS NextWeek,18 DATEADD(MONTH, -1, GETDATE()) AS LastMonth,19 DATEDIFF(DAY, '2024-01-01', GETDATE()) AS DaysSince;AdventureWorks Date Usage
1-- AdventureWorks dùng DATETIME (legacy)2SELECT 3 SalesOrderID,4 OrderDate, -- DATETIME5 DueDate, -- DATETIME6 ShipDate, -- DATETIME7 ModifiedDate -- DATETIME8FROM Sales.SalesOrderHeader9WHERE SalesOrderID = 43659;1011-- Recommend: DATETIME2 cho new projectsCheckpoint
Tại sao nên dùng DATETIME2 thay vì DATETIME cho projects mới? So sánh 2 loại này.
🗄️ Binary Types
Binary Data
1-- BINARY(n) - Fixed length (1-8000 bytes)2-- VARBINARY(n) - Variable length (1-8000 bytes)3-- VARBINARY(MAX) - Up to 2GB45CREATE TABLE Document (6 DocumentID INT IDENTITY(1,1) PRIMARY KEY,7 FileName NVARCHAR(255),8 FileContent VARBINARY(MAX), -- Store file binary9 Thumbnail VARBINARY(8000), -- Small image10 HashValue BINARY(32) -- Fixed-size hash11);1213-- Insert binary data14INSERT INTO Document (FileName, HashValue)15VALUES (16 'report.pdf',17 HASHBYTES('SHA2_256', 'some content') -- 32-byte hash18);AdventureWorks Binary
1-- Production.Document stores files2SELECT 3 DocumentNode,4 FileName,5 FileExtension,6 DATALENGTH(Document) AS FileSize -- VARBINARY(MAX)7FROM Production.Document8WHERE FileName LIKE '%.doc%';Checkpoint
VARBINARY dùng để lưu loại dữ liệu gì? Khi nào nên dùng BINARY thay vì VARBINARY?
🌟 Special Types
UNIQUEIDENTIFIER (GUID)
1-- 16-byte globally unique identifier2CREATE TABLE Session (3 SessionID UNIQUEIDENTIFIER PRIMARY KEY DEFAULT NEWID(),4 UserID INT,5 CreatedAt DATETIME2 DEFAULT SYSDATETIME()6);78-- Generate GUID9SELECT NEWID(); -- Random GUID10SELECT NEWSEQUENTIALID(); -- Sequential GUID (better for clustered index)1112-- AdventureWorks uses rowguid13SELECT 14 ProductID,15 rowguid -- UNIQUEIDENTIFIER16FROM Production.Product17WHERE ProductID = 1;XML Type
1-- Native XML storage and querying2CREATE TABLE Config (3 ConfigID INT IDENTITY(1,1) PRIMARY KEY,4 ConfigData XML5);67INSERT INTO Config (ConfigData)8VALUES ('<settings><timeout>30</timeout><retries>3</retries></settings>');910-- Query XML11SELECT 12 ConfigID,13 ConfigData.value('(/settings/timeout)[1]', 'INT') AS Timeout,14 ConfigData.value('(/settings/retries)[1]', 'INT') AS Retries15FROM Config;JSON (stored as NVARCHAR)
1-- SQL Server 2016+ supports JSON functions2CREATE TABLE APILog (3 LogID INT IDENTITY(1,1) PRIMARY KEY,4 RequestBody NVARCHAR(MAX), -- JSON stored as string5 ResponseBody NVARCHAR(MAX),6 CreatedAt DATETIME2 DEFAULT SYSDATETIME()7);89-- Insert JSON10INSERT INTO APILog (RequestBody)11VALUES ('{"user_id": 123, "action": "login", "timestamp": "2024-01-15T10:30:00"}');1213-- Query JSON14SELECT 15 LogID,16 JSON_VALUE(RequestBody, '$.user_id') AS UserID,17 JSON_VALUE(RequestBody, '$.action') AS Action18FROM APILog;1920-- Validate JSON21SELECT ISJSON('{"name": "test"}'); -- Returns 1 if validCheckpoint
SQL Server lưu JSON bằng kiểu dữ liệu gì? So sánh ưu nhược điểm của XML và JSON trong SQL Server.
🔧 Computed Columns
1-- Computed column tự động tính toán2CREATE TABLE OrderDetail (3 OrderDetailID INT IDENTITY(1,1) PRIMARY KEY,4 Quantity INT,5 UnitPrice DECIMAL(10, 2),6 Discount DECIMAL(4, 2) DEFAULT 0,7 8 -- Computed columns9 LineTotal AS (Quantity * UnitPrice), -- Not stored10 NetTotal AS (Quantity * UnitPrice * (1 - Discount)) PERSISTED -- Stored11);1213-- AdventureWorks computed columns14SELECT 15 SalesOrderDetailID,16 OrderQty,17 UnitPrice,18 UnitPriceDiscount,19 LineTotal -- Computed: OrderQty * UnitPrice * (1 - UnitPriceDiscount)20FROM Sales.SalesOrderDetail21WHERE SalesOrderID = 43659;Checkpoint
Computed Column là gì? Sự khác nhau giữa computed column thường và PERSISTED?
🛠️ Data Type Conversion
Implicit vs Explicit
1-- Implicit conversion (automatic)2SELECT 1 + '1'; -- INT + VARCHAR = INT (result: 2)3SELECT 1 + 1.5; -- INT + DECIMAL = DECIMAL (result: 2.5)45-- Explicit conversion6SELECT CAST('123' AS INT); -- CAST syntax7SELECT CONVERT(INT, '123'); -- CONVERT syntax8SELECT TRY_CAST('abc' AS INT); -- Returns NULL instead of error9SELECT TRY_CONVERT(INT, 'abc'); -- Returns NULL1011-- Date conversion12SELECT CONVERT(VARCHAR, GETDATE(), 103); -- dd/mm/yyyy13SELECT CONVERT(VARCHAR, GETDATE(), 120); -- yyyy-mm-dd hh:mi:ss14SELECT FORMAT(GETDATE(), 'dd/MM/yyyy'); -- Flexible formattingConversion Gotchas
1-- ⚠️ Data loss in conversion2SELECT CAST(123.456 AS INT); -- Result: 123 (truncated)3SELECT CAST('2024-13-01' AS DATE); -- Error! Invalid month45-- ✅ Safe conversion6SELECT TRY_CAST('2024-13-01' AS DATE); -- Returns NULL78-- ⚠️ Unicode loss9DECLARE @nv NVARCHAR(10) = N'Việt Nam';10SELECT CAST(@nv AS VARCHAR(10)); -- "Vi?t Nam" - lost diacritics!Checkpoint
CAST và CONVERT khác nhau thế nào? Khi nào nên dùng TRY_CAST thay vì CAST?
💡 Best Practices Summary
1## Data Type Selection Guidelines2 3### Numeric4- ✅ INT for most IDs and quantities5- ✅ DECIMAL(19, 4) for money/financial6- ❌ Avoid FLOAT for financial calculations7- ❌ Avoid MONEY type (limited precision)8 9### String10- ✅ NVARCHAR for international text (Vietnamese)11- ✅ VARCHAR for ASCII-only data (emails, codes)12- ✅ Use appropriate size limits13- ❌ Avoid VARCHAR(MAX) unless necessary14- ❌ Don't use CHAR unless truly fixed-length15 16### Date/Time17- ✅ DATETIME2 for new projects18- ✅ DATE when time not needed19- ✅ DATETIMEOFFSET for multi-timezone apps20- ❌ Avoid legacy DATETIME21 22### General23- ✅ Choose smallest type that fits24- ✅ Consider NULL handling25- ✅ Use consistent types for JOINs26- ✅ Document special types (JSON, XML)| Data Need | Recommended Type |
|---|---|
| Primary Key | INT IDENTITY |
| Price/Money | DECIMAL(19, 4) |
| Vietnamese Name | NVARCHAR(100) |
| VARCHAR(255) | |
| Date only | DATE |
| Timestamp | DATETIME2(3) |
| Boolean | BIT |
| Status | TINYINT hoặc VARCHAR(20) |
Checkpoint
Hãy tóm tắt best practices khi chọn Data Type cho: ID, tiền tệ, tên tiếng Việt, ngày tháng.
🚀 Bài tiếp theo
Bài tiếp theo: Tạo Tables với DDL
Học cách viết CREATE TABLE statements hoàn chỉnh với SQL Server!
