Migracija podataka uz mapiranje upotrebom MERGE komande

Objavljeno: 28-09-2015 | Autor: Nenad Živković | Kategorija: T-SQL, Trikovi

Ознаке:

0

Prebacivanje podataka iz jedne tabele u drugu je nešto što svaki DB developer radi manje-više redovno. Povremeno se, kod tog procesa, može pojaviti i dodatna komplikacija da svi preneti redovi moraju dobiti nove PK u novoj tabeli. Razlozi za to mogu biti različiti: da u ciljnoj tabeli već postoje redovi koji imaju iste ID-eve kao i u izvornoj, da se razlikuje IDENTITY SEED dve tabele, da se razlikuju tipovi podataka PK-a ili čak da se razlikuje i broj PK kolona. U svakom slučaju, najčešće je potrebno usput sačuvati i vezu između novih i starih ID-eva u nekoj tabeli za mapiranje.

Ovaj članak će opisati rešenje za tu situaciju: Prebacivanje redova iz jedne tabele u drugu, gde se u destinacionoj tabeli dodeljuju novi ID-evi, a pritom čuvamo vezu u trećoj tabeli.

Kao primer uzećemo tabelu dbo.CrtaniFilmovi iz naše baze koja kao primarni ključ ima kolonu CrtacID i pored nje još dve kolone sa opisom i nazivom.

MergeMapiranje - CrtaniFilmovi

Zadatak bi nam bio da prebacimo podatke o crtanim filmovima u neku tabelu dbo.Cartoons koja generiše svoje ID-eve u CartoonID koloni (po drugačijem seed-u). Usput bi trebalo sačuvati i vezu između postojećih slogova i novih u tabeli dbo.CartoonsCrtaciMapping

CREATE TABLE dbo.Cartoons 
   (CartoonID INT IDENTITY(100,10)
   , CartoonName NVARCHAR(100));

CREATE TABLE dbo.CartoonsCrtaciMapping 
	(CartoonID INT, CrtacID INT);

Postoji nekoliko načina da se ovo uradi i njih nećemo detaljno opisivati u ovom članku, ali ćemo pomenuti i skrenuti pažnju na njihove nedostatke:

1. While petlja ili kursor koji bi prebacivao red po red, uz pomoć SCOPE_IDENTITY() funkcije čitati novokreirane ID-eve i upisivati ih. Možda naizgled najjednostavnije rešenje, ali već na par hiljada redova postaje neprihvatljivo neperformantno.

2. Dodati privremeno kolonu CrtacID u Cartoons tabelu, popuniti je prilikom inserta i ukloniti nakon prebacivanja podataka u Mapping tabelu. Ovo je relativno OK varijanta, ali samo ukoliko postoji mogućnost altera destinacione tabele, što, usled nedostatka prava ili zbog opasnosti da bi ometalo druge upite, neće uvek biti slučaj.

3. Prebaciti podatke prostim INSERT..SELECT bez razmišljanja o mapiranju, a nakon toga uraditi JOIN između destinacione i izvorne tabele po unique kolonama. Prošlo bi u našem primeru sa kolonama CartoonName i Naziv, ali šta ako nemamo unique kolone? Šta ako u već postojećim podacima postoje podaci identični onim koji se ubacuju? Dosta upitnika i dosta rizična varijanta.

4. Aktivirati IDENTITY_INSERT nad ciljnom tabelom i voditi ručno računa o ključevima ili uz pomoć nekih privremenih tabela. Još jedna riskanta varijanta, a koja usput zahteva i da se tabela zaključa i spreči bilo kakav upis sa strane dok traje migracija.

Jedina logična i bezbedna opcija bila bi korišćenje OUTPUT klauzule prilikom inserta, nešto kao u sledećem primeru:

INSERT INTO dbo.Cartoons
OUTPUT INSERTED.CartoonID, CrtaniFilmovi.CrtacID
INTO dbo.CartoonsCrtaciMapping
SELECT Naziv 
FROM dbo.CrtaniFilmovi;

Međutim navedeni upit će vratiti grešku, s obzirom da u OUTPUT-u nije moguće koristiti kolone iz SELECT dela već samo one koje su insertovane.

Msg 4104, Level 16, State 1, Line 2
The multi-part identifier „CrtaniFilmovi.CrtacID“ could not be bound.

Problem se prevazilazi tako što se umesto INSERT naredbe može upotrebiti MERGE naredba koja dozvoljava OUTPUT i izvornih podataka. Iako originalna namena MERGE-a nije za prost INSERT, ništa nas ne sprečava da je upotrebimo tako. Samo ćemo za spajanje staviti neki nemogući uslov i u svakom slučaju će se desiti INSERT:

MERGE dbo.Cartoons
USING dbo.CrtaniFilmovi 
	ON 1=2
WHEN NOT MATCHED THEN
	INSERT (CartoonName)
	VALUES (Naziv)
	OUTPUT INSERTED.CartoonID, CrtaniFilmovi.CrtacID
	INTO CartoonsCrtaciMapping;

Izvršavanjem ove naredbe svi crtaći iz naše tabele će biti prebačeni u novu dbo.Cartoons, a usput će i mapping tabela biti popunjena novim i starim ID-evima.

MergeMapiranje - CartoonsMapping

Naravno, ovo je moguće samo ukoliko koristite SQL Server 2008 ili noviji gde postoji komanda MERGE. Ukoliko ste i dalje na 2005 moraćete da primenite neku od gore pomenutih varijanti (2 ili 3 ukoliko je moguće).

Keyboard Query Shortcuts – Prečice za izvršavanje upita

Objavljeno: 20-03-2015 | Autor: Nenad Živković | Kategorija: Management Studio, Trikovi

0

Kao skoro svaki program danas, i SQL Server Managment Studio nudi opciju da se razne operacije mogu pozivati prečicama sa tastature. Mnoge od njih verovatno i koristite svakodnevno, ali ono što ćemo opisati u ovom članku je posebna vrsta prečica koje nisu toliko poznate, a zovu se Query Shortcuts. U pitanju su prečice koje umesto okidanja definisanih komandi, izvršavaju unapred pripremljene upite. Ako dodate prave upite i malo se naviknete, ove prečice mogu značajno da vam olakšaju svakodnevni rad.

Za podešavanje, otvorite iz menija Tools -> Options, a zatim, u otvorenom prozoru sa leve strane Environment -> Keyboard -> Query Shortcuts.

Keyboard Query Shortcuts Options

Neke od ovih prečica su već predefinisane u SSMS, ali možete i sami da ih promenite ili

Agregirani bitovi

Objavljeno: 19-06-2014 | Autor: Nenad Živković | Kategorija: Funkcije, T-SQL, Trikovi

Ознаке: , , ,

0

Ukoliko dobijete ideju da proverite da li u nekoj BIT koloni postoji makar jedna vrednost true ili makar jedna vrednost false, možda će vam prvo pasti na pamet ideja da iskoristite agregatne funkcije MAX() ili MIN() i lako proverite da li su sve vrednosti iste, s obzirom da postoje samo dve moguće vrednosti.

Međutim, ako pokušate da izvršite komandu:

SELECT MAX(UBoji) FROM dbo.CrtaneEpizode;

ubrzo ćete udariti u zid pošto se javlja sledeća greška:

Msg 8117, Level 16, State 1, Line 1
Operand data type bit is invalid for max operator.

Kreiranje XML-a za svaki red u tabeli

Objavljeno: 01-04-2014 | Autor: Nenad Živković | Kategorija: T-SQL, Trikovi, XML

0

Nedavno smo objasnili kako se tabela ili rezultat nekog upita mogu pretvoriti u XML. Kao mala dopuna tog članka, danas ćemo prikazati i trik kako se svaki red tabele može pretvoriti u zaseban XML.

Već objašnjena sintaksa FOR XML sada se koristi unutar podupita, a kao uslov se dodaje JOIN tabele sa samom sobom:

SELECT 
	CrtacID
  , Naziv
  , Opis
  , (
		SELECT cfx.*
		FROM dbo.CrtaniFilmovi cfx
		WHERE cfx.CrtacID = cf.CrtacID
		FOR XML PATH ('')
	) AS CrtacXML
FROM dbo.CrtaniFilmovi cf;

XML za svaki red u tabeli

CONTEXT_INFO

Objavljeno: 14-03-2014 | Autor: Milen Blagojević | Kategorija: T-SQL, Trikovi

0

Context informacija je binarna vrednost veličine do 128 bajtova koja se može postaviti na nivou sesije i koristiti u procedurama, trigerima ili funkcijama koje se izvršavaju u okviru iste sesije.

Postoje dve komande koje se koriste za postavljanje i čitanje ove informacije:

  • SET CONTEXT_INFO – za upisivanje vrednosti
  • CONTEXT_INFO () – za čitanje vrednosti

Ova vrednost se takođe može pročitati i u sledećim DMVs:

  • sys.dm_exec_requests
  • sys.dm_exec_sessions
  • sys.sysprocesses

Primer:

Rekurzivni CTE za kreiranje datuma

Objavljeno: 05-03-2014 | Autor: Nenad Živković | Kategorija: T-SQL, Trikovi

Ознаке: , ,

0

Ukoliko vam je potrebno da izvučete sve datume u nekom periodu, to možete učiniti uz pomoć rekurzivnog CTE kome zadate početni i krajnji datum. U baznom delu se selektuje početni datum, a u rekurzivnom dodaje po jedan dan dok ne stigne do krajnjeg. Primer je u sledećem upitu:

DECLARE @pocetni DATE;
DECLARE @krajnji DATE;

SET @pocetni = '20131226';
SET @krajnji = '20140304';

WITH datumi AS 
(
	SELECT @pocetni AS DT
	UNION ALL
	SELECT DATEADD(DD, 1, DT)
	FROM datumi
	WHERE DATEADD(DD, 1, DT) <= @krajnji
)
SELECT * FROM datumi
OPTION (MAXRECURSION 0);

Čitanje i upisivanje podataka u Excel uz pomoć T-SQL-a

Objavljeno: 30-01-2014 | Autor: Miloš Milenković | Kategorija: T-SQL, Trikovi

Ознаке: ,

2

Ukoliko postoji potreba da se podaci iz nekog Excel dokumenta učitaju u bazu ili da se iz baze izvezu u Excel najčešće se koristi SQL Server Import/Export Wizard (što smo objasnili u prethodnom članku), koji u stvari predstavlja grafički interfejs za kreiranje SSIS paketa kojim se vrši prebacivanje podataka. U slučaju da postoji potreba da se postave neka dodatna podešavanja, najbolje rešenje je otvaranje i editovanje SSIS paketa kreiranog kroz pomenuti Wizard ili kreiranje novog korišćenjem BI Development Studio-a. Međutim, u nekim slučajevima ovaj proces može biti previše komplikovan i zamoran.

Jednostavno rešenje za brzo upisivanje ili iščitavanje podataka iz Excel-a je korišćenje metode OPENROWSET. Osnovna funkcija ove metode je brz i jednostavan pristup linkovanom serveru, a u ovom slučaju je linkovani server ništa drugo do instanca Excela.

Smeštanje rezultata procedure u temp tabelu

Objavljeno: 20-01-2014 | Autor: Nenad Živković | Kategorija: Stored procedure, T-SQL, Trikovi

Ознаке: ,

0

Sintaksa koju svi često volimo da koristimo je SELECT * INTO #temp FROM.. koja nam omogućava da brzo kreiramo temp tabelu od rezultata koji upit vraća.

Verovatno je i svako ponekad poželeo da to isto iskoristi i da rezultate stored procedure na sličan način smesti u neku privremenu tabelu, ali već prvi pokušaj će pokazati da takva sintaksa za procedure ne postoji.

SELECT * INTO #temp FROM EXEC dbo.usp_Kefalo_Procedura; --?!?!
EXEC INTO #temp dbo.usp_Kefalo_Procedura; --?!?!

Jedino ispravno rešenje je unapred kreiranje temp tabele, i njeno punjenje INSERT..EXEC sintaksom:

CREATE TABLE #tempTabela (Kolona INT);

INSERT INTO #tempTabela
EXEC dbo.usp_Kefalo_Procedura;

Međutim, ukoliko postoje određeni uslovi, moguće je iskoristiti funkciju OPENROWSET i postići željeni cilj. Komanda bi izgledala ovako: