MODUL 4 - LEKCIJA 4

BLOBs, FILESTREAM i Full-Text Search

Ekspertsko upravljanje strukturiranim i nestrukturiranim podacima velikih razmjera

⏱️ Trajanje: ~4 časa 📚 Nivo: Srednji do Napredni 🎯 Praktični primjeri: 6

📖 Izvan teksta i brojeva

U realnim sistemima, morate čuvati PDF ugovore, slike profila, video tutorijale, Word dokumente, Excel fajlove, slike proizvoda, audio zapise i mnoge druge nestrukturirane podatke. Ovi podaci se nazivaju BLOB (Binary Large Objects) - binarni objekti velikih razmjera. SQL Server nudi tri nivoa njihovog čuvanja: direktno u tabeli pomoću VARBINARY(MAX), na fajl sistemu preko baze (FILESTREAM) ili kao eksterni folder sa Windows integracijom (FileTable).

💡 Šta su BLOB podaci?

BLOB (Binary Large Object) je termin koji se koristi za bilo koji binarni podatak koji ne može biti efikasno predstavljen kao tekst ili numerička vrijednost. Primjeri uključuju:

  • Dokumenti: PDF, Word (.docx), Excel (.xlsx), PowerPoint prezentacije
  • Slike: JPEG, PNG, GIF, BMP, TIFF
  • Video: MP4, AVI, MOV
  • Audio: MP3, WAV, FLAC
  • Arhive: ZIP, RAR, 7Z
  • Izvršni fajlovi: EXE, DLL
  • Baze podataka: SQLite, Access (.mdb)

Za razliku od strukturiranih podataka (brojevi, datumi, tekst), BLOB podaci nemaju unutrašnju strukturu koju SQL Server može direktno razumjeti. Oni se čuvaju kao "crna kutija" - SQL Server zna gdje su, ali ne zna šta je unutra bez dodatnih alata.

📦 VARBINARY(MAX): Skladištenje unutar baze

Šta je VARBINARY(MAX)?

VARBINARY(MAX) je SQL Server tip podataka koji može čuvati binarne podatke do maksimalno 2 GB po koloni. Riječ "VAR" znači "variable" (promjenjiva) - kolona može čuvati različite veličine podataka, od 0 bajtova do 2 GB.

Kako VARBINARY(MAX) radi interno?

SQL Server koristi LOB (Large Object) storage mehanizam za VARBINARY(MAX) podatke:

🛠️ Kreiranje tabele sa VARBINARY(MAX)
-- Primjer: Tabela za čuvanje slika profila
CREATE TABLE Users.ProfilePictures (
    ProfilePictureID INT IDENTITY(1,1) PRIMARY KEY,
    UserID INT NOT NULL,
    PictureData VARBINARY(MAX) NOT NULL,
    FileName NVARCHAR(255),
    ContentType NVARCHAR(100), -- npr. 'image/jpeg', 'image/png'
    FileSize BIGINT, -- veličina u bajtovima
    UploadDate DATETIME2 DEFAULT SYSDATETIME()
);
GO

-- Primjer: Tabela za dokumente
CREATE TABLE Documents.Contracts (
    ContractID INT IDENTITY(1,1) PRIMARY KEY,
    ContractNumber NVARCHAR(50) UNIQUE,
    Title NVARCHAR(200) NOT NULL,
    DocumentContent VARBINARY(MAX) NOT NULL,
    DocumentType NVARCHAR(50), -- 'PDF', 'DOCX', 'XLSX'
    CreatedDate DATETIME2 DEFAULT SYSDATETIME(),
    CreatedBy NVARCHAR(100)
);
GO

Prednosti VARBINARY(MAX)

Nedostaci VARBINARY(MAX)

📤 Umetanje BLOB podataka u VARBINARY(MAX)
-- Metoda 1: Umetanje iz fajla pomoću OPENROWSET (zahtijeva permisije)
INSERT INTO Documents.Contracts (Title, DocumentContent, DocumentType)
SELECT 
    'Ugovor o radu',
    BulkColumn,
    'PDF'
FROM OPENROWSET(BULK 'C:\Documents\Contract.pdf', SINGLE_BLOB) AS Document;
GO

-- Metoda 2: Umetanje iz aplikacije (C#, Python, itd.)
-- Aplikacija čita fajl u byte array i šalje kao parametar
-- INSERT INTO Documents.Contracts (Title, DocumentContent) 
-- VALUES (@Title, @DocumentBytes);

-- Metoda 3: Konverzija iz string-a (za male podatke)
DECLARE @SmallImage VARBINARY(MAX) = CONVERT(VARBINARY(MAX), 'Binary data here');
GO

⚠️ Važno za VARBINARY(MAX)

  • Preporučena veličina: Koristite VARBINARY(MAX) za fajlove manje od 1 MB
  • Granica: Maksimalna veličina je 2 GB po koloni
  • Performanse: Za fajlove veće od 1 MB, razmotrite FILESTREAM
  • Memorija: Čitanje velikih BLOB-ova može zauzeti puno RAM-a

💾 FILESTREAM: Najbolje od oba svijeta

Šta je FILESTREAM?

FILESTREAM je SQL Server tehnologija koja kombinuje ACID transakcije baze podataka sa performansama fajl sistema. Kada koristite FILESTREAM:

Kako FILESTREAM radi?

FILESTREAM koristi poseban FILESTREAM filegroup koji mapira SQL Server strukture na NTFS folder. Kada umetnete podatak u FILESTREAM kolonu:

  1. SQL Server kreira GUID identifikator za fajl
  2. Fajl se čuva u FILESTREAM folderu na disku
  3. U tabeli se čuva samo pointer (GUID) na fajl
  4. Windows File System API se koristi za čitanje/pisanje (brže od SQL Server I/O)

Konfiguracija FILESTREAM-a

FILESTREAM se mora omogućiti na nivou SQL Server instance prije korištenja:

⚙️ Omogućavanje FILESTREAM-a
-- Korak 1: Omogućiti FILESTREAM na SQL Server instance nivou
-- Ovo se radi kroz SQL Server Configuration Manager ili T-SQL:
EXEC sp_configure filestream_access_level, 2;
RECONFIGURE;
GO

-- Vrijednosti:
-- 0 = FILESTREAM onemogućen
-- 1 = Omogućen samo za Transact-SQL pristup
-- 2 = Omogućen za T-SQL i Windows file I/O pristup (preporučeno)

-- Korak 2: Kreirati FILESTREAM filegroup u bazi
ALTER DATABASE MyDatabase
ADD FILEGROUP FileStreamFG CONTAINS FILESTREAM;
GO

-- Korak 3: Dodati FILESTREAM fajl u filegroup
ALTER DATABASE MyDatabase
ADD FILE (
    NAME = 'FileStreamData',
    FILENAME = 'C:\SQLData\FileStreamData' -- Folder gdje će se čuvati fajlovi
)
TO FILEGROUP FileStreamFG;
GO

-- Napomena: Folder mora postojati, ali SQL Server će ga kreirati ako ne postoji
-- FILENAME mora biti putanja do foldera, ne fajla
🛠️ Kreiranje tabele sa FILESTREAM kolonom
-- Važno: FILESTREAM tabele MORAJU imati UNIQUEIDENTIFIER kolonu sa ROWGUIDCOL
CREATE TABLE Legal.Contracts (
    ContractID UNIQUEIDENTIFIER ROWGUIDCOL PRIMARY KEY DEFAULT NEWID(),
    ContractNumber NVARCHAR(50) UNIQUE NOT NULL,
    Title NVARCHAR(200) NOT NULL,
    Document VARBINARY(MAX) FILESTREAM NULL, -- FILESTREAM kolona
    FileName NVARCHAR(255),
    FileSize BIGINT,
    UploadDate DATETIME2 DEFAULT SYSDATETIME(),
    CreatedBy NVARCHAR(100)
);
GO

-- Napomena: 
-- - ROWGUIDCOL označava kolonu koja čuva GUID za FILESTREAM
-- - FILESTREAM kolona može biti NULL
-- - Maksimalna veličina fajla je ograničena samo disk prostorom (ne 2 GB kao VARBINARY)

Rad sa FILESTREAM podacima

📤 Umetanje fajla u FILESTREAM kolonu
-- Metoda 1: Umetanje iz fajla pomoću OPENROWSET
INSERT INTO Legal.Contracts (ContractNumber, Title, Document, FileName, FileSize)
SELECT 
    'CONTRACT-2024-001',
    'Ugovor o radu',
    BulkColumn,
    'Contract.pdf',
    DATALENGTH(BulkColumn)
FROM OPENROWSET(BULK 'C:\Documents\Contract.pdf', SINGLE_BLOB) AS Document;
GO

-- Metoda 2: Umetanje iz aplikacije (preporučeno)
-- Aplikacija koristi SqlFileStream klasu (.NET) ili slično za direktan pristup
-- Ovo omogućava streaming bez kopiranja cijelog fajla u memoriju

-- Metoda 3: Umetanje praznog FILESTREAM-a i kasnije popunjavanje
INSERT INTO Legal.Contracts (ContractNumber, Title, Document)
VALUES ('CONTRACT-2024-002', 'Novi ugovor', 0x); -- 0x = prazan BLOB
GO
📥 Čitanje FILESTREAM podataka
-- Čitanje FILESTREAM podataka
SELECT 
    ContractID,
    ContractNumber,
    Title,
    Document, -- Vraća VARBINARY(MAX)
    FileName,
    FileSize
FROM Legal.Contracts
WHERE ContractID = '12345678-1234-1234-1234-123456789012';
GO

-- Za eksport u fajl, koristite aplikaciju koja čita VARBINARY(MAX) i piše u fajl
-- Ili koristite bcp utility ili SQL Server Integration Services (SSIS)

Prednosti FILESTREAM-a

Nedostaci FILESTREAM-a

🔑 Kada koristiti šta?

Kriterij VARBINARY(MAX) FILESTREAM
Veličina fajla < 1 MB > 1 MB
Maksimalna veličina 2 GB Ograničeno samo disk prostorom
Performanse Brzo za male fajlove Brzo za velike fajlove
Kompleksnost Jednostavno Zahtijeva konfiguraciju
Backup Automatski u backup baze Mora eksplicitno uključiti FILESTREAM
Windows pristup Nema Moguć kroz FileTable

📂 FileTable: SQL Server kao Windows folder

Šta je FileTable?

FileTable je nadogradnja FILESTREAM-a koja omogućava da SQL Server tabele izgledaju i ponašaju se kao Windows folder. Sa FileTable-om možete:

Kako FileTable radi?

FileTable koristi FILESTREAM tehnologiju u pozadini, ali dodaje:

Konfiguracija FileTable-a

⚙️ Omogućavanje FileTable-a
-- Korak 1: Omogućiti FILESTREAM (kao što je prikazano ranije)
EXEC sp_configure filestream_access_level, 2;
RECONFIGURE;
GO

-- Korak 2: Kreirati FILESTREAM filegroup (ako već nije kreiran)
ALTER DATABASE MyDatabase
ADD FILEGROUP FileStreamFG CONTAINS FILESTREAM;
GO

ALTER DATABASE MyDatabase
ADD FILE (
    NAME = 'FileStreamData',
    FILENAME = 'C:\SQLData\FileStreamData'
)
TO FILEGROUP FileStreamFG;
GO

-- Korak 3: Omogućiti non-transacted access (potrebno za FileTable)
ALTER DATABASE MyDatabase
SET FILESTREAM (NON_TRANSACTED_ACCESS = FULL, DIRECTORY_NAME = 'MyFileTableShare');
GO

-- NON_TRANSACTED_ACCESS = FULL omogućava Windows pristup fajlovima
-- DIRECTORY_NAME je ime Windows share-a koji će biti kreiran
🛠️ Kreiranje FileTable-a
-- Kreiranje FileTable-a
CREATE TABLE Documents.DocumentStore AS FileTable
WITH (
    FileTable_Directory = 'DocumentStore', -- Ime foldera u Windows share-u
    FileTable_Collate_Filename = database_default
);
GO

-- FileTable automatski kreira sljedeće kolone:
-- - stream_id (UNIQUEIDENTIFIER, ROWGUIDCOL) - jedinstveni ID
-- - file_stream (VARBINARY(MAX), FILESTREAM) - stvarni fajl
-- - name (NVARCHAR(255)) - ime fajla
-- - path_locator (HIERARCHYID) - pozicija u hijerarhiji
-- - parent_path_locator (HIERARCHYID) - parent folder
-- - file_type (NVARCHAR(255)) - ekstenzija fajla
-- - cached_file_size (BIGINT) - veličina fajla
-- - creation_time (DATETIME2) - vrijeme kreiranja
-- - last_write_time (DATETIME2) - vrijeme zadnje izmjene
-- - last_access_time (DATETIME2) - vrijeme zadnjeg pristupa
-- - is_directory (BIT) - da li je folder
-- - is_archive (BIT) - archive atribut
-- - is_hidden (BIT) - hidden atribut
-- - is_readonly (BIT) - read-only atribut
-- - is_offline (BIT) - offline atribut
-- - is_system (BIT) - system atribut
-- - is_temporary (BIT) - temporary atribut

Pristupanje FileTable-u

Nakon kreiranja FileTable-a, možete mu pristupiti na nekoliko načina:

📂 Pristupanje FileTable-u
-- Metoda 1: Kroz Windows Explorer
-- Putanja: \\ServerName\MyFileTableShare\DocumentStore\
-- Možete kopirati, brisati, i mijenjati fajlove direktno iz Windows-a

-- Metoda 2: Kroz T-SQL (kao običnu tabelu)
SELECT 
    name,
    file_type,
    cached_file_size,
    creation_time,
    file_stream
FROM Documents.DocumentStore
WHERE is_directory = 0; -- Samo fajlovi, ne folderi
GO

-- Metoda 3: Umetanje fajla kroz T-SQL
INSERT INTO Documents.DocumentStore (name, file_stream)
SELECT 
    'MyDocument.pdf',
    BulkColumn
FROM OPENROWSET(BULK 'C:\Temp\MyDocument.pdf', SINGLE_BLOB) AS Document;
GO

-- Metoda 4: Kreiranje foldera
INSERT INTO Documents.DocumentStore (name, is_directory)
VALUES ('MyFolder', 1);
GO

Prednosti FileTable-a

Nedostaci FileTable-a

🔍 Full-Text Search (FTS): Lingvistička pretraga

Šta je Full-Text Search?

Standardni LIKE '%tekst%' operator je prespor jer ne koristi indekse i mora skenirati svaki red u tabeli. Na milionima redova, ovo može trajati minute ili čak sate. Full-Text Search (FTS) je napredna SQL Server tehnologija koja:

Kako Full-Text Search radi?

FTS koristi Full-Text Engine koji:

  1. Tokenizira tekst: Razbija tekst na riječi (tokens)
  2. Primjenjuje word breaker: Razumije granice riječi (npr. "SQL Server" = 2 riječi)
  3. Primjenjuje stemmer: Redukuje riječi na korijen (npr. "trčanje" → "trč")
  4. Kreira invertirani indeks: Mapira svaku riječ na redove gdje se pojavljuje
  5. Čuva pozicije: Zna gdje se riječ pojavljuje u dokumentu

Konfiguracija Full-Text Search-a

⚙️ Kreiranje Full-Text Catalog-a
-- Korak 1: Kreirati Full-Text Catalog
-- Catalog je kontejner za Full-Text indekse
CREATE FULLTEXT CATALOG ft_ProductCatalog 
WITH ACCENT_SENSITIVITY = ON
AS DEFAULT; -- Ovo čini katalog default-om za bazu
GO

-- ACCENT_SENSITIVITY = ON znači da razlikuje "č" od "c"
-- ACCENT_SENSITIVITY = OFF tretira "č" i "c" isto
🛠️ Kreiranje Full-Text Index-a
-- Važno: Tabela MORA imati jedinstveni indeks (obično PRIMARY KEY)
-- Prije kreiranja Full-Text Index-a, provjerite da tabela ima unique index

-- Kreiranje Full-Text Index-a na koloni ReviewBody
CREATE FULLTEXT INDEX ON dbo.ProductReview (
    ReviewBody LANGUAGE 'Bosnian' -- Specifikacija jezika
)
KEY INDEX PK_ProductReview -- Jedinstveni indeks na tabeli
ON ft_ProductCatalog -- Catalog gdje će se čuvati
WITH (
    CHANGE_TRACKING AUTO, -- Automatsko praćenje promjena
    STOPLIST = SYSTEM -- Koristi sistem stop listu (riječi koje se ignoriraju)
);
GO

-- LANGUAGE opcije:
-- 'Bosnian', 'Croatian', 'Serbian' - za našu regiju
-- 'English' - za engleski
-- 0 ili 'Neutral' - bez jezičke analize

-- CHANGE_TRACKING opcije:
-- AUTO - automatsko praćenje promjena (preporučeno)
-- MANUAL - ručno ažuriranje sa ALTER FULLTEXT INDEX ... START UPDATE POPULATION
-- OFF - bez praćenja promjena

Full-Text Search Funkcije

1. CONTAINS - Precizna pretraga

CONTAINS omogućava preciznu pretragu sa podrškom za:

🔍 CONTAINS Primjeri
-- Pronalaženje riječi
SELECT Title, ReviewBody
FROM dbo.ProductReview
WHERE CONTAINS(ReviewBody, 'kvalitet');
GO

-- Pronalaženje tačne fraze
SELECT Title, ReviewBody
FROM dbo.ProductReview
WHERE CONTAINS(ReviewBody, '"odličan proizvod"');
GO

-- Boolean operatori (AND, OR, NOT)
SELECT Title, ReviewBody
FROM dbo.ProductReview
WHERE CONTAINS(ReviewBody, 'kvalitet AND cijena');
GO

SELECT Title, ReviewBody
FROM dbo.ProductReview
WHERE CONTAINS(ReviewBody, 'kvalitet OR performanse');
GO

SELECT Title, ReviewBody
FROM dbo.ProductReview
WHERE CONTAINS(ReviewBody, 'kvalitet AND NOT skup');
GO

-- Wildcard pretraga (mora biti na kraju)
SELECT Title, ReviewBody
FROM dbo.ProductReview
WHERE CONTAINS(ReviewBody, 'prog*'); -- Naći će "program", "programiranje", "programer"
GO

-- NEAR - pronalazi riječi blizu jedna drugoj
SELECT Title, ReviewBody
FROM dbo.ProductReview
WHERE CONTAINS(ReviewBody, 'NEAR((kvalitet, cijena), 5)');
-- Pronalazi redove gdje su "kvalitet" i "cijena" unutar 5 riječi jedna od druge
GO

-- Weighted pretraga (rangiranje)
SELECT 
    Title, 
    ReviewBody,
    KEY_TBL.RANK AS RelevanceScore
FROM dbo.ProductReview
INNER JOIN CONTAINSTABLE(dbo.ProductReview, ReviewBody, 
    'ISABOUT(kvalitet WEIGHT(0.8), cijena WEIGHT(0.2))') AS KEY_TBL
    ON dbo.ProductReview.ReviewID = KEY_TBL.[KEY]
ORDER BY KEY_TBL.RANK DESC;
GO

2. FREETEXT - Inteligentna pretraga

FREETEXT je "pametnija" pretraga koja:

🧠 FREETEXT Primjeri
-- Inteligentna pretraga - razumije različite oblike riječi
SELECT Title, ReviewBody
FROM dbo.ProductReview
WHERE FREETEXT(ReviewBody, 'trčanje');
-- Naći će: "trčanje", "trčao", "trčati", "trkač", itd.
GO

-- Pretraga sa više riječi
SELECT Title, ReviewBody
FROM dbo.ProductReview
WHERE FREETEXT(ReviewBody, 'kvalitet proizvoda i cijena');
-- FTS će razumjeti da tražite dokumente o kvalitetu, proizvodima i cijeni
GO

-- FREETEXT sa rangiranjem
SELECT 
    Title,
    ReviewBody,
    KEY_TBL.RANK AS RelevanceScore
FROM dbo.ProductReview
INNER JOIN FREETEXTTABLE(dbo.ProductReview, ReviewBody, 
    'kvalitet proizvoda i cijena') AS KEY_TBL
    ON dbo.ProductReview.ReviewID = KEY_TBL.[KEY]
ORDER BY KEY_TBL.RANK DESC;
GO

CONTAINSTABLE i FREETEXTTABLE

Ove funkcije vraćaju tabelu sa rangiranim rezultatima, što omogućava:

📊 CONTAINSTABLE Primjer
-- CONTAINSTABLE vraća tabelu sa KEY i RANK kolonama
SELECT 
    pr.ReviewID,
    pr.Title,
    pr.ReviewBody,
    ct.RANK AS RelevanceScore
FROM dbo.ProductReview pr
INNER JOIN CONTAINSTABLE(dbo.ProductReview, ReviewBody, 
    'kvalitet AND cijena', 10) AS ct -- Top 10 rezultata
    ON pr.ReviewID = ct.[KEY]
ORDER BY ct.RANK DESC;
GO

-- Napredna pretraga sa više kolona
SELECT 
    pr.ReviewID,
    pr.Title,
    pr.ReviewBody,
    ct.RANK
FROM dbo.ProductReview pr
INNER JOIN CONTAINSTABLE(dbo.ProductReview, 
    (Title, ReviewBody), -- Pretraga u više kolona
    'kvalitet', 20) AS ct
    ON pr.ReviewID = ct.[KEY]
WHERE ct.RANK > 50 -- Samo relevantni rezultati
ORDER BY ct.RANK DESC;
GO

Stop Liste (Stopwords)

Stop liste su liste riječi koje se ignoriraju tokom Full-Text pretrage jer su previše česte i ne nose značenje. Primjeri: "i", "ili", "je", "su", "na", "u", itd.

🚫 Upravljanje Stop Listama
-- Kreiranje custom stop liste
CREATE FULLTEXT STOPLIST MyCustomStoplist;
GO

-- Dodavanje riječi u stop listu
ALTER FULLTEXT STOPLIST MyCustomStoplist
ADD 'riječ1' LANGUAGE 'Bosnian';
ALTER FULLTEXT STOPLIST MyCustomStoplist
ADD 'riječ2' LANGUAGE 'Bosnian';
GO

-- Korištenje custom stop liste u Full-Text Index-u
ALTER FULLTEXT INDEX ON dbo.ProductReview
SET STOPLIST MyCustomStoplist;
GO

-- Vraćanje na sistem stop listu
ALTER FULLTEXT INDEX ON dbo.ProductReview
SET STOPLIST SYSTEM;
GO

💡 Best Practices za Full-Text Search

  • Ispravan jezik: Uvijek specificirajte jezik u Full-Text Index-u za bolje rezultate
  • CHANGE_TRACKING AUTO: Koristite AUTO za automatsko ažuriranje indeksa
  • Stop liste: Koristite stop liste za bolje performanse
  • Kombinacija sa WHERE: Kombinujte FTS sa običnim WHERE klauzulama za bolje performanse
  • Rangiranje: Koristite CONTAINSTABLE/FREETEXTTABLE za rangirane rezultate

🎯 Praktične Vježbe

Vježba 1: Full-Text Search Engine za Recenzije Proizvoda

Imate tabelu ProductReview sa hiljadama dugih recenzija. Korisnici žele brzo pretraživati recenzije po ključnim riječima sa podrškom za morfološku pretragu.

Korak 1: Kreirajte tabelu za recenzije i Full-Text Catalog.

💡 Rješenje - Korak 1
-- Kreirati tabelu za recenzije
CREATE TABLE dbo.ProductReview (
    ReviewID INT IDENTITY(1,1) PRIMARY KEY,
    ProductID INT NOT NULL,
    CustomerName NVARCHAR(100),
    ReviewTitle NVARCHAR(200),
    ReviewBody NVARCHAR(MAX) NOT NULL, -- Kolona za Full-Text Search
    Rating INT CHECK (Rating BETWEEN 1 AND 5),
    ReviewDate DATETIME2 DEFAULT SYSDATETIME(),
    IsVerified BIT DEFAULT 0
);
GO

-- Kreirati Full-Text Catalog
CREATE FULLTEXT CATALOG ft_ProductCatalog 
WITH ACCENT_SENSITIVITY = ON
AS DEFAULT;
GO

Korak 2: Kreirajte Full-Text Index nad kolonom ReviewBody.

💡 Rješenje - Korak 2
-- Kreirati Full-Text Index
CREATE FULLTEXT INDEX ON dbo.ProductReview (
    ReviewBody LANGUAGE 'Bosnian'
)
KEY INDEX PK__ProductReview__ReviewID
ON ft_ProductCatalog
WITH (
    CHANGE_TRACKING AUTO,
    STOPLIST = SYSTEM
);
GO

-- Provjera statusa Full-Text Index-a
SELECT 
    OBJECT_NAME(object_id) AS TableName,
    fulltext_catalog_id,
    is_enabled,
    change_tracking_state_desc
FROM sys.fulltext_indexes;
GO

Korak 3: Umetnite test podatke i testirajte različite tipove pretrage.

💡 Rješenje - Korak 3
-- Umetanje test podataka
INSERT INTO dbo.ProductReview (ProductID, CustomerName, ReviewTitle, ReviewBody, Rating)
VALUES 
    (1, 'Amar Selimović', 'Odličan proizvod', 
     'Ovaj proizvod ima izuzetan kvalitet. Cijena je pristupačna i vrijedi svake marke. Preporučujem svima!', 5),
    (1, 'Lejla Hasanović', 'Zadovoljna sam', 
     'Kvalitet proizvoda je na visokom nivou. Brza dostava i dobra komunikacija sa prodavcem.', 4),
    (2, 'Emir Kovačević', 'Može bolje', 
     'Proizvod je dobar, ali cijena je previsoka za ono što dobijate. Performanse su solidne.', 3);
GO

-- Čekati da se Full-Text Index popuni
WAITFOR DELAY '00:00:05';
GO

-- Test 1: CONTAINS pretraga
SELECT ReviewTitle, ReviewBody, Rating
FROM dbo.ProductReview
WHERE CONTAINS(ReviewBody, 'kvalitet');
GO

-- Test 2: FREETEXT pretraga (razumije različite oblike)
SELECT ReviewTitle, ReviewBody, Rating
FROM dbo.ProductReview
WHERE FREETEXT(ReviewBody, 'kvalitet');
GO

-- Test 3: Rangirana pretraga
SELECT 
    pr.ReviewID,
    pr.ReviewTitle,
    pr.ReviewBody,
    pr.Rating,
    ct.RANK AS RelevanceScore
FROM dbo.ProductReview pr
INNER JOIN CONTAINSTABLE(dbo.ProductReview, ReviewBody, 
    'kvalitet AND cijena', 10) AS ct
    ON pr.ReviewID = ct.[KEY]
ORDER BY ct.RANK DESC;
GO

Vježba 2: FILESTREAM Sistem za Dokumente

Kreirajte kompletan sistem za upravljanje dokumentima koji koristi FILESTREAM za čuvanje PDF, Word i Excel fajlova.

💡 Kompletan Primjer
-- 1. Omogućiti FILESTREAM
EXEC sp_configure filestream_access_level, 2;
RECONFIGURE;
GO

-- 2. Kreirati bazu sa FILESTREAM filegroup-om
CREATE DATABASE DocumentManagement;
GO

USE DocumentManagement;
GO

ALTER DATABASE DocumentManagement
ADD FILEGROUP DocumentFileStreamFG CONTAINS FILESTREAM;
GO

ALTER DATABASE DocumentManagement
ADD FILE (
    NAME = 'DocumentFileStreamData',
    FILENAME = 'C:\SQLData\DocumentFileStream'
)
TO FILEGROUP DocumentFileStreamFG;
GO

-- 3. Kreirati tabelu sa FILESTREAM kolonom
CREATE SCHEMA Documents;
GO

CREATE TABLE Documents.DocumentStore (
    DocumentID UNIQUEIDENTIFIER ROWGUIDCOL PRIMARY KEY DEFAULT NEWID(),
    DocumentNumber NVARCHAR(50) UNIQUE NOT NULL,
    Title NVARCHAR(200) NOT NULL,
    DocumentContent VARBINARY(MAX) FILESTREAM NULL,
    FileName NVARCHAR(255) NOT NULL,
    FileExtension NVARCHAR(10),
    FileSize BIGINT,
    CreatedDate DATETIME2 DEFAULT SYSDATETIME(),
    CreatedBy NVARCHAR(100)
);
GO

-- 4. Umetanje dokumenta
INSERT INTO Documents.DocumentStore (
    DocumentNumber, Title, DocumentContent, FileName, FileExtension, FileSize, CreatedBy
)
SELECT 
    'DOC-2024-001',
    'Ugovor o radu',
    BulkColumn,
    'Contract_2024_001.pdf',
    'PDF',
    DATALENGTH(BulkColumn),
    'admin'
FROM OPENROWSET(BULK 'C:\Documents\Contract.pdf', SINGLE_BLOB) AS Document;
GO

✅ Zaključak Modula 4

Završili smo specijalizovano skladištenje. Vaša baza sada može čuvati sve:

📚 Modul 5: Konkurentnost i Sigurnost

U sljedećem modulu prelazimo na kritične operacije. Naučićete kako rješavati Deadlock situacije, koristiti Always Encrypted za zaštitu podataka i podesiti Audit za potpuni mir.