SELECT Explanation, Example FROM Pro.Knowledge
FacebookRSS

Zapytania rozproszone i zewnętrzne źródła danych

W SQL Server mamy dostępnych kilka metod, dających nam dostęp do danych zewnętrznych.
W artykule tym, przedstawiam możliwości funkcji OPENQUERY, za pomocą której możemy tworzyć zapytania „Ad Hoc” (spontanicznie) do innych zasobów.

Zaprezentuję także metody wykorzystujące obiekty serwerów powiązanych (Linked Servers). Te z kolei stosujemy, aby utworzyć „stałe” powiązanie z innymi zasobami i w wygodny sposób, regularnie sięgać do zewnętrznych źródeł.


Zapytania rozproszone (Distributed Queries)

Komunikacja w środowiskach rozproszonych odbywa się zawsze w oparciu o interfejs pośredniczący. Standardem są sterowniki ODBC (Open DataBase Connectivity), za pomocą których możemy łączyć się z innymi bazami danych. Każdy producent serwera bazodanowego, udostępnia zazwyczaj w pakiecie klienckim wszystkie wymagane komponenty. Jeśli masz potrzebę łączenia się np. z bazą MySQL czy Oracle, powinieneś zainstalować właściwe dla danego dostawcy biblioteki.

Microsoft, od lat rozwijał równolegle własną koncepcje warstwy pośredniczącej – tzw. dostawców OLE DB (Object Linking and Embedding Database). Biblioteki te, rozszerzają możliwości ODBC i dotyczą połączeń nie tylko do serwerów bazodanowych ale także dostępu do zasobów plikowych (Excel, Access czy nawet zwykłych, płaskich plików tekstowych).

Jeśli chodzi o komunikację z SQL Server, w wersjach 2005-2012, to właśnie dostęp za pośrednictwem Native Client OLE DB był sugerowaną (szybszą, o większych możliwościach) metodą dostępu do danych. Sterowniki Native Client, zawierają w sobie bibliotekę OLE DB oraz ODBC. Dla wielu z pewnością dużym zaskoczeniem, był nagły zwrot w kierunku standardu ODBC w SQL Server 2014. Native Client 11 OLE DB z SQL Server 2012 – jest ostatnim w tej architekturze sterownikiem (więcej na ten temat, możesz przeczytać nas stronach Microsoft dot. kierunku rozwoju oraz oficjalnego powrotu do standardu ODBC)

Komunikacja, pomiędzy klientami, instancją SQL Server (do wersji 11) i środowiskami rozproszonymi odbywa się za pośrednictwem OLE DB.
SQL_SERVER_DISTRIBUTED_QUERIES


Funkcja OPENROWSET

Za pomocą funkcji OPENROWSET, możemy tworzyć zapytania rozproszone (Distributed Queries), odpytujące praktycznie dowolne zbiory zewnętrzne. Jedynym ograniczeniem jest dostępność na serwerze właściwych bibliotek OLE DB lub sterowników ODBC. Funkcja OPENROWSET umożliwia nie tylko odpytywanie zasobów, ale również pozwala na wykonywanie za jej pośrednictwem poleceń typu DML (Insert, Update, Delete). Ponieważ jest to funkcja tabelaryczna, stosować możemy ją analogicznie jak zwykłą tabelę (np. łącząc ją z innymi zbiorami).

Wymagania początkowe – konfiguracja serwera

Warunkiem koniecznym na wykorzystanie tej funkcji, jest włączenie na poziomie serwera, możliwości pisania zapytania rozproszonych (Ad Hoc Distributed Queries). To zadanie wykonamy za pomocą instrukcji :

exec sp_configure 'show advanced options', 1;
RECONFIGURE WITH OVERRIDE;
 
exec sp_configure 'Ad Hoc Distributed Queries', 1;
RECONFIGURE WITH OVERRIDE;
GO

Od tego momentu, możemy tworzyć zapytania „Ad hoc”, korzystające z OPENROWSET. W dalszej części zaprezentuję typowe przykłady zastosowań.

OPENROWSET w praktyce

Odpytywanie źródeł zewnętrznych za pomocą tej funkcji, wymaga podania kilku parametrów. Nie będę omawiać tu wszystkich możliwych opcji, zwrócę uwagę tylko na najważniejsze i najczęściej wykorzystywane w praktyce.

Typowe użycie funkcji OPENROWSET – odpytywanie innego SQL Servera :

SELECT *
FROM OPENROWSET(
         -- Provider_name
	'SQLNCLI',  				
 
         -- Connection String
	'SERVER=ServerZdalny\Instancja; TRUSTED_CONNECTION=yes;',
 
         -- Query
         'SELECT * FROM Northwind.dbo.Customers'
	) AS tabela

Pierwszym parametrem jest określenie dostawcy OLE DB (provider_name) za pośrednictwem którego wykonywane będzie połączenie.

Regułą jest stosowanie dedykowanego dostawcy dla określonego źródła. Jeśli nie jest on dostępny, możesz skorzystać z uniwersalnej biblioteki MSDASQL i połączenia via ODBC.

Listę dostawców OLE DB których masz zainstalowane na swoim serwerze, odnajdziesz nawigując w drzewie hierarchii obiektów w Management Studio :

OLE_DB_Providers

lub za pośrednictwem specjalnej procedury składowanej :

EXEC xp_enum_oledb_providers

OLE_DB_Providers2

W zależności z jakiego oprogramowania korzystasz, ta lista może się różnić.

Warto tutaj wspomnieć, że można utworzyć połączenia ze zdalnymi serwerami na różne sposoby. Już choćby z tej listy widać, że do SQL Server, można się odwołać za pomocą przynajmniej trzech dostawców – SQLOLEDB (ten jest stosowany domyślnie), SQLNCLI oraz uniwersalnego MSDASQL, wykorzystującego pośrednio połączenia ODBC. Wybór dostawcy, powinien być podyktowany konkretnymi potrzebami programistycznymi (więcej na temat różnic znajdziesz np. tutaj ).

Drugim parametrem jest connection string, czyli charakterystyczny dla danego dostawcy zbiór opcji, które określają warunki połączenia. W przypadku SQL Server, będzie to na pewno nazwa sieciowa serwera / instancji, tryb uwierzytelniania, czy wybór konkretnej bazy danych.

Trzecim parametrem jest nasza zdalna kwerenda. Tutaj od razu bardzo ważna uwaga – pamiętaj o tym, ze cały ten zbiór, zwracany przez to zdalne zapytanie, będzie transportowany do serwera z którego je wywołujesz. Może to być przyczyną problemów m.in. sieciowych, trwać długo czyli również przekładać się bezpośrednio na czas trwania zapytania, blokad etc… Zapytania rozproszone, powinny zwracać zawsze minimalny, konieczny zbiór danych. Chyba również z tego powodu, domyślnie możliwość ich wykonywania jest wyłączona.

Zapytania do bazy ORACLE

Jak to bywa, możemy zrealizować tego typu zapytanie ad hoc na kilka sposób. Poniżej parę przykładów – dla każdego coś miłego. Pierwsze trzy zakładają istnienie wpisu TNS w pliku {ORA_HOME}\Network\Admin\tnsnames.ora. W ostatnim przykładzie, jawnie podaje wszystkich parametry komunikacyjne do serwera zdalnego.

-- z providerem OLEDB Oraclowym + wpis w {ORA_HOME}\Network\Admin\tnsnames.ora
SELECT * 
FROM OPENROWSET(
	'OraOLEDB.Oracle',
	'NaszOracleSrv';'username';'paswword', 
	'SELECT ''works fine'' as Kol1 FROM Dual' )
 
-- z providerem MSowym do Oracle 
Select * 
FROM OPENROWSET(
	'MSDAORA',
	'NaszOracleSrv';'username';'paswword', 
	'SELECT ''works fine'' as Kol1 FROM Dual' )
 
-- a tu inaczej - wszystko w Connection Stringu + połączenie via ODBC z wpisem w {ORA_HOME}\Network\Admin\tnsnames.ora
SELECT * 
FROM OPENROWSET(
	'MSDASQL', 
	'DRIVER={Microsoft ODBC for Oracle}; UID=username; PWD=password; SERVER=NaszOracleSrv;', 
	'SELECT ''works fine'' as Kol1 FROM Dual' 
	) as Tabela
 
-- a tu inaczej - wszystko w Connection Stringu + połączenie via ODBC
SELECT * 
FROM OPENROWSET(
	'MSDASQL', 
	'DRIVER={Microsoft ODBC for Oracle}; UID=username; PWD=password; SERVER=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=10.1.1.1)(PORT=1521)))(CONNECT_DATA=(SID=NaszOracleSID)));', 
	'SELECT ''works fine'' as Kol1 FROM Dual' 
	) as Tabela

Zapytania do baz MySQL i innych z użyciem MSDASQL + ODBC

Jeśli nie mamy dostępnego dedykowanego dostawcy OLE DB, możemy łączyć się ze zdalnym serwerem za pomocą MSDASQL i połączenia wykorzystującego sterowniki ODBC. Listę dostępnych driverów, zainstalowanych na maszynie, sprawdzisz w panelu administracyjnym ODBC :

ODBC_Drivers

W przypadku odpytania bazy MySQL z poziomu SQL Server, potrzebne będą sterowniki ODBC (jak widać powyżej, mam takie zainstalowane). Sama kwerenda jest bardzo podobna do poprzedniej. Zastosowałem inny sterownik ODBC (MySQL) i dlatego connection string, którego struktura jest określana przez producenta, różni się w stosunku do poprzedniej, gdy odpytywałem bazę Oracle.

  SELECT  * 
  FROM OPENROWSET(
	'MSDASQL',
       'Driver={MySQL ODBC 5.2 ANSI Driver}; 
  Server=MyServerMySQL; Database=MojaBaza; USER=Username; PASSWORD=alamakota',
	'SELECT * from tabelka limit 10' )

Za pomocą OPENROWSET, możemy odpytywać także zawartości plików. Mogą to być zarówno pliki tekstowe, strukturyzowane (CSV), dokumenty Excel czy „bazy danych” Access. Dość wygodnie, za pomocą OPENQUERY przeczytamy również całe pliki XML. Pobieranie danych z Excela oraz plików tekstowych, opisuje szczegółowo w kolejnych rozdziałach tego kursu.

Poniżej kilka prostych, ale praktycznych przykładów :

-- Czytanie zwykłego pliku txt
SELECT F1 as FileContent 
FROM OPENROWSET(
	'Microsoft.ACE.OLEDB.12.0', 
    'Text;Database=D:\data\;HDR=NO', 
    'SELECT *  FROM test.txt')
 
-- załadowanie pliku XML (można go przypisać do zmiennej
SELECT CONVERT(xml, BulkColumn ) as XmlDocs
FROM 
OPENROWSET (BULK 'D:\DaneXML\NBP\a051z140314.xml',SINGLE_BLOB) as T1

OPENQUERY_1


Serwery powiązane – Linked Servers

Do tej pory, korzystaliśmy z tzw. zapytań Ad hoc – spontanicznych kwerend, do pobrania określonych danych z zewnętrznego źródła. W środowiskach produkcyjnych, istnieją serwery, które regularnie odpytujemy. Pisanie za każdym razem, długich connection stringów, jest niewygodne.

Za pomocą obiektów serwerów powiązanych, możemy zrealizować integrację danych z różnych środowisk w wygodniejszy sposób.

Na wstępie warto jeszcze raz podkreślić, że zapytania rozproszone, niezależnie od metody (OPENROWSET, Linked Server) powinny być stosowane z rozwagą, bo mogą być przyczyną problemów wydajnościowych (sieć, czasy blokad etc.) w środowiskach transakcyjnych.

Świadomi tego :), możemy zabrać się za tworzenie obiektów serwerów powiązanych. Jeśli jesteś zwykłym użytkownikiem bazy danych, potrzebujesz do tego uprawnień serwerowych ALTER ANY LINKED SERVER.

Serwery powiązane, możesz tworzyć w T-SQL (służy do tego procedura sp_addlinkedserver) lub za pomocą wizarda w Management Studio.

Linked_server_01

Całość konfiguracji, ogranicza się zazwyczaj do określenia dostawcy OLE DB, nazw serwera, ewentualnie połączenia ODBC oraz ustawień związanych z bezpieczeństwem. W przypadku SQL Server, wystarczy podać nazwę sieciową instancji – zostanie utworzony serwer powiązany, domyślnie z uwierzytelnianiem zintegrowanym, bazujący na natywnym kliencie SQLNCLI OLE DB.

Pisanie zapytań z wykorzystaniem Linked Servers

Odwoływanie się w kwerendach rozproszonych do obiektów serwerów powiązanych, jest możliwe na dwa sposoby.
Za pomocą funkcji tabelarycznej OPENQUERY(), możemy wysyłać zapytanie do dowolnego obiektu Linked Server.

SELECT * 
FROM OPENQUERY(SerwerPowiazany,'SELECT * FROM TABELA')

W tej sytuacji, zostanie wykonane zapytanie na serwerze zdalnym w dokładnie takiej postaci, jak parameter query funkcji OPENQUERY. Czyli zostanie pobrana CAŁA zawartość odpytywanej tabeli i przesłana przez sieć do klienta. Porównaj takie dwa zapytania z filtracją rekordów :

-- źle
SELECT * 
FROM OPENQUERY(SerwerPowiazany,'SELECT * FROM TABELA')
WHERE KolID = 12345
 
-- dobrze :)
SELECT * 
FROM OPENQUERY(SerwerPowiazany,'SELECT * FROM TABELA WHERE KolID = 12345 ')

Zwrócą to samo, ale o ile lżejsze jest zapytanie drugie, z filtracją po stronie zdalnego serwera….
Funkcja OPENQUERY, pozwala również na wysyłanie poleceń typu DML.

Drugim sposobem, jest odwoływanie się w poleceniach SQL do obiektów (tabel, widoków czy procedur), po w pełni kwalifikowanej, czteroczłonowej nazwie. W ten sposób, możemy wywoływać także procedury składowane na zdalnym serwerze.

           <SERVER>.<BAZA_DANYCH>.<SCHEMAT>.<OBIEKT>

Zarówno pierwszy jak i drugi sposób, pozwala na pobieranie danych z zewnętrznych źródeł podobnie jak ze zwykłych tabel. Można łączyć je w zapytaniach, odwołując się jednocześnie do różnych serwerów (UWAGA na wydajność !!!).

SELECT c.*, o.OrderID  
FROM Server1.Northwind.dbo.Customers c 
		inner join Server2.Northwind.dbo.Orders o on c.CustomerID = o.CustomerID

Metadane związane z Linked Servers

Z obiektami Linked Servers, związanych jest kilka przydatnych widoków i procedur składowanych, które warto poznać. Listę dostępnych obiektów Linked Servers, loginów z nimi związanych, możesz obejrzeć poprzez widoki systemowe w bazie msdb (sys.servers, sys.linked_logins oraz sys.remote_logins).

Mamy także dostępnych kilka specjalnych procedur składowanych. Z bardziej praktycznych są sp_catalogs oraz sp_tables_ex, które pozwalają na podejrzenie wszystkich baz danych / tabel, dostępnych po przez dany obiekt (o ile dostawca OLE DB/ODB oferuje takie funkcjonalności). Poniżej przykład wywołania sp_catalogs do zdalnego SQL Servera o nazwie RFN.

  -- bazy danych
  sp_catalogs 'RFN'

Linked_server_02

Za pośrednictwem serwerów powiązanych, podobnie jak funkcji OPENROWSET, możemy odnosić się również do plików. Jest wiele dróg na import danych z plików. Jedno z nich to rozwiązanie oparte o Linked Servers. Poniżej przykład utworzenia obiektu „serwera”, będącego katalogiem z plikami. Do tego celu wykorzystam dostawcę Jet.OLEDB.4.0.

EXEC sp_addlinkedserver  PlikiWymiany, 
	'Jet 4.0', 
         'Microsoft.Jet.OLEDB.4.0',
         'D:\Dane\',
         NULL,
         'Text';

W katalogu D:\Dane\ – są umieszczone dwa pliki tekstowe :

LinkedServer_TXT_FILE_01

Na koniec zastosowanie procedury składowanej sp_tables_ex oraz odczytanie zawartości pierwszego z plików.

EXEC sp_tables_ex PlikiWymiany;
GO
 
SELECT * 
FROM PlikiWymiany...[test#txt];

LinkedServer_TXT_FILE_02


Podsumowanie

Opisane powyżej metody pracy w środowisku rozproszonym są z pewnością bardzo praktyczne i często stosowane. Korzystając z nich, pamiętaj o aspektach wydajnościowych. Pobieranie danych (czasem całych tabel) poprzez sieć ze zdalnych serwerów, z pewnością nie jest najlepszym pomysłem.

Zapytania do danych XML w SQL

Zakres zagadnień dotyczących obecności XML’a w SQL Server jest szeroki. Pisanie zapytań do dokumentów XML, to bardzo często wykorzystywana w praktyce umiejętność. Dlatego też, postanowiłem umieścić rozdział wprowadzający do XML w ramach tego kursu.

Na początek, zaprezentuję ogólną koncepcję standardu XML i jego typowe zastosowania w praktyce. Pokażę gotowe recepty, przykłady – w jaki sposób pisać zapytania SQL do dokumentów XML.

W artykule tym omawiam podstawowe zastosowania funkcji OPENXML() oraz wbudowanych metod typu danych XML. Związanych z nimi wyrażeń XPath i elementów języka XQuery w aspekcie przeszukiwania dokumentów XML i przekształcania ich na postać relacyjną.


Czym jest XML

XML (ang. Extensible Markup Language) określany jest często jako „język”, ale podobnie jak SQL, nie jest to język programowania. XML to najbardziej popularny standard (język) opisu danych. Jego komercyjne pojawienie się pod koniec lat 90-tych, spowodowało wręcz eksplozję zastosowań.

Stosuje się go wszędzie tam, gdzie chcemy przekazać jakieś informacje. W ogólności, na XML możemy spojrzeć jak na opakowanie. To nic innego jak metadane opisujące i nadające sens przesyłanym informacjom.

XML to zbiór zasad, które pozwalają definiować dowolne, ale ściśle ustandaryzowane, hierarchiczne dokumenty. XML (czyli standard) posiada wiele rozszerzeń powiązanych z celem do którego został stworzony.

Jedną z głównych zalet XML, to możliwość silnego typizowania dokumentów (schematy XSD). Możemy dokonywać weryfikacji ich poprawności pod względem określonego schematu. Definiować elementy czy atrybuty jako obowiązkowe lub opcjonalne. Narzucać ograniczenia dla wartości – podobnie jak w konstrukcjach CHECK CONSTRAINT (np. zakresy). Standard ten jest bardzo elastyczny i niezależny od platformy.

Wymianę danych pomiędzy systemami najwygodniej realizować za jego pomocą, choć czasem może być postrzegany jako mocno nadmiarowy. Obecnie większość urządzeń udostępnia na przykład swoje dane konfiguracje, czy zbierane informacje w postaci plików XML.


XML w SQL Server

Podstawowe funkcjonalności związane z XML, pojawiły się już w SQL Server 2000 (np. funkcja OPENXML czy FOR XML). W późniejszych edycjach (od wersji 9 – 2005), XML stał się pełnoprawnym, natywnie wspieranym typem danych. Jego implementacja w SQL Server to szereg dedykowanych funkcjonalności takich jak wbudowane metody tworzenia dokumentów XML, specjalne typy indeksów czy mechanizmy przeszukiwania FLWOR (XQuery).

Przetwarzanie obiektów XML, jest wykonywane w oparciu o jego hierarchiczną strukturę drzewa. Jest to znacznie bardziej efektywny sposób niż metody przeszukiwania tekstów.

Natywny typ danych XML, możemy stosować w różnych miejscach np.

  • przy określaniu typu kolumn w definicjach tabel – do składowania dokumentów XML w bazie relacyjnej.
  • w definicji zmiennych – do przetwarzania dokumentów.
  • jako wartości zwracanych przez funkcję lub parametrów procedur składowanych.

Mamy możliwość tworzenia dokumentów XML bezpośrednio z postaci relacyjnej. Służą do tego polecenia FOR XML, rozszerzające składnię języka SQL. Ale nie o nich jest ten artykuł :)

W drugą zaś stronę – z postaci XML do postaci relacyjnej, możemy dokonać przekształceń za pomocą funkcji OPENXML() lub wbudowanych metod typu XML. Wykorzystując wyrażenia XPath i język zapytań XQuery. W artykule tym ograniczam się właśnie do omówienia sposobów, pobierania interesujących nas danych z dokumentów XML.


Przykład dokumentu XML

Jednymi z publicznie dostępnych dokumentów XML, na których zaprezentuję kilka przykładów zapytań, są publikowane przez NBP, aktualne kursy walut. Jest to typowe zastosowanie tego standardu, służące do przekazywania danych pomiędzy różnymi systemami. Pobierać je może każdy i niezależnie od platformy, przetwarzać zgodnie z własnymi potrzebami.

Fragment takiego pliku poniżej :

Odpytywanie_XML_w_SQL_01

Kilka słów na temat samej konstrukcji. Generalnie XML, daje dużą swobodę użytkownikowi w definiowaniu własnych dokumentów. Możemy określać dowolną strukturę za pomocą elementów oraz związanych z nimi atrybutów

<Element Atrybut=”wartość_atrybutu”> wartość_elementu </Element>

Każdy z nich może mieć przypisaną wartość, a ich typ, zakres czy charakter (obowiązkowy / opcjonalny) może być określony schematem.

Poprawny dokument XML musi posiadać korzeń. W naszym przykładzie jest to element nadrzędny o nazwie <tabela_kursow>. XML jest zawsze ściśle określony, stąd wrażliwy jest na małe / wielkie litery (case sensitive) oraz konieczność zamykania znaczników elementów :

 <nazwa_elementu> wartość </nazwa_elementu>

Poza tymi podstawowymi elementami konstrukcji, w typowym dokumencie XML określane są standardy kodowania, przestrzenie nazw (namespaces), czy powiązania do schematów, opisujących jego strukturę. W naszym przykładzie, mamy bardzo prosty dokument i w jego definicji te elementy nie są określone.


Przeszukiwanie pliku XML w SQL

Pierwszym przykładem, będzie odpytywanie pliku XML z poziomu T-SQL za pomocą funkcji OPENXML i prostych wyrażeń XPath. Wykorzystam do tego dokument XML, który możemy pobrać ze strony zasobów NBP – średnie kursy walut opublikowane 14 marca 2014.

Załóżmy, że chcemy przekształcić taki dokument na postać relacyjną – czyli zasilić naszą bazę, aktualnymi kursami walut.

Schemat tabeli, przechowującej kursy walut w postaci relacyjnej, będzie wyglądał tak :

USE TEMPDB
GO
 
CREATE TABLE [dbo].[KursyWalut](
	[Kod_Waluty] [char](3) NOT NULL,
	[Data] [date] NOT NULL,
	[Kurs_Sredni] [smallmoney] NOT NULL,
	[Przelicznik] [smallint] NOT NULL DEFAULT 1,
 
	 CONSTRAINT [PK_KursyWalut] PRIMARY KEY CLUSTERED 
	(
		[Kod_Waluty] ASC,
		[Data] ASC
	)
)

Oczywiście budując aplikację, należałoby zasilać bazę codziennie. Można to zrealizować na kilka sposobów, korzystając z paczek SSIS, własnych funkcji CLR lub pisząc proste skrypty w Visual Basic’u. W naszym przykładzie, zakładam, że mamy dostępny dokument XML na lokalnym serwerze na dysku D.

Załadowanie pliku XML do zmiennej w T-SQL

Pierwszym krokiem będzie wrzucenie pliku XML na serwer i załadowanie go do zmiennej z poziomu T-SQL. Wykorzystamy do tego celu funkcję OPENROWSET().

DECLARE @xmldata XML
 
SELECT @xmldata=BulkColumn
FROM 
OPENROWSET (BULK 'D:\DaneXML\NBP\a051z140314.xml',SINGLE_BLOB) as T1
 
SELECT @xmldata as Dokument

Odpytywanie_XML_w_SQL_02

Cały dokument, został załadowany do zmiennej typu XML. Możemy go wrzucić bezpośrednio do odpowiedniej kolumny w tabeli lub wyciągnąć z niego tylko istotne dla nas informacje.

Obiekty typu XML, wyświetlane są w Management Studio w postaci linku. Możemy podejrzeć taki dokument, po prostu klikając w taki link.
Odpytywanie_XML_w_SQL_03


Czytanie pliku XML za pomocą OPENXML()

Funkcja OPENXML jest dość wiekowa i dostępna była już w SQL Server 2000. Są z nią bezpośrednio związane dwie specjalne procedury składowane : sp_xml_preparedocument oraz sp_xml_removedocument.

OPENXML pozwala na proste szatkowanie dokumentu XML do postaci relacyjnej. Wyciąganie interesujących danych z XML i np. ładowanie ich do tabeli.

Algorytm pracy z tą funkcją obejmuje 3 kroki :

  1. Przygotowanie dokumentu – czyli załadowanie całego (!) do pamięci CACHE serwera. Służy do tego procedura sp_xml_preparedocument, do której przekazujemy jako parametr, dokument XML. Zwraca ona „uchwyt” do dokumentu – wskaźnik do pamięci CACHE pod którym jest on dostępny.
  2. Właściwe przeszukiwanie dokumentu za pomocą OPENXML, wykorzystując proste wyrażenia XPath do nawigacji po węzłach.
  3. Sprzątanie pamięci CACHE – zwalnianie zasobów za pomocą sp_xml_removedocument. Pamiętajmy o tym, żeby nie pozostawiać śmieci.

Z kolei funkcja OPENXML() przyjmuje 3 (opcjonalnie 4) parametry :

  • Pierwszym jest „uchwyt” (wskaźnik) do dokumentu w pamięci Cache Servera (zwracany przez sp_xml_preparedocument).
  • Drugim, ścieżka (XPath), wskazująca na punkt odniesienia jaki będzie stosowany w pobieraniu danych. Do tego miejsca w strukturze, będziemy mogli odnosić się w bloku WITH() tej funkcji.
  • Trzecim, flaga wskazująca na typ obiektów (elementy, atrybuty czy ich mix), których wartości chcemy zwrócić.
  • Czwartym, opcjonalnym jet definicja przestrzeni nazw

Dodatkowo, z funkcją OPENXML, powiązany jest blok WITH(), w którym możemy nawigować po elementach i atrybutach (z wykorzystaniem XPath), wyciągając z XMLa interesujące nas wartości.

Napiszmy więc skrypt, pobierający dane z pliku XML. Zgodnie z opisanym wcześniej algorytmem, przygotujemy dokument do obróbki, wyciągniemy interesujące nas informacje i wrzucimy je do tabeli dbo.KursyWalut. Na koniec zwolnimy zajęte przez nasz dokument zasoby w pamięci CACHE.

DECLARE @xmldata XML
 
-- 0. Załadowanie pliku do zmiennej
SELECT @xmldata=BulkColumn
FROM 
OPENROWSET (BULK 'D:\DaneXML\NBP\a051z140314.xml',SINGLE_BLOB) as T1
 
-- 1. Przygotowanie dokumentu
DECLARE @docHandle int
EXEC sp_xml_preparedocument @docHandle OUTPUT, @xmldata
 
-- 2. OPENXML - przyjmujemy za punkt odniesienia /tabela_kursow/pozycja
-- interesują nas wartości elementów (flaga = 2) i ładujemy do tabeli dbo.KursyWalut
 
INSERT INTO dbo.KursyWalut
SELECT 
	kod_waluty, Data_publikacji,
	cast ( Replace(kurs_sredni , ',','.') as smallmoney ) as Kurs, przelicznik
FROM
OPENXML(@docHandle, '/tabela_kursow/pozycja', 2)
WITH
(	
	data_publikacji varchar(10) '../data_publikacji',   -- poziom w górę
	kod_waluty	char(3) ,
	kurs_sredni	varchar(100) ,
	przelicznik int
)
 
-- 3. Sprzątanie pamięci 
EXEC sp_xml_removedocument @docHandle
GO
 
SELECT * from dbo.KursyWalut

Fragment zawartości tabeli dbo.KursyWalut, po załadowaniu danych z pliku XML :

Odpytywanie_XML_w_SQL_04

Nawigacja po węzłach za pomocą wyrażeń XPath, jest dość intuicyjna i podobna do określania ścieżki np. w systemie plików czy obiektach HTMLowych. Zresztą standard HTML wywodzi się z tej samej rodziny (SGML).


Przeszukiwanie XML za pomocą natywnych metod

Zaprezentowana funkcja OPENXML, jest bardzo uboga w porównaniu z pełną implementacją typu danych XML.

Typ XML, posiada pięć wbudowanych metod, które dają szerokie możliwości jego przeszukiwania i modyfikacji. Wszystkie bazują na języku zapytań XQuery i związanych z nim wyrażeniach FLWOR. Działanie pierwszych trzech, które stosuje się typowo do wyciągania informacji z dokumentów XML zaprezentuję na przykładach.

Typ danych XML posiada następujące, natywne metody :

  • value() – zwraca pojedynczą wartość, wynik zapytania XQuery w postaci skalarnego typu danych.
  • query() – zwraca fragment (wycinek) dokumentu XML.
  • nodes() – szatkuje dokument XML na wiele mniejszych, podrzędnych.
  • exists() – przeszukuje dokument XML pod kątem istnienia w nim określonych elementów. Zazwyczaj stosowana w budowaniu warunków, wyrażeń logicznych w WHERE.
  • modify() – służy do aktualizacji dokumentu XML.

Zapytanie do dokumentu XML, pokazane w poprzednim przykładzie za pomocą funkcji OPENXML(), możemy zrealizować wykorzystując znacznie szybsze (!), natywne metody value() oraz nodes(). Ich przewagę widać na pierwszy rzut oka. Są czytelniejsze i bardziej wygodne. Prawdziwą swoją moc, pokażą gdy zastosujesz dodatkowo, specjalne typy indeksów XML.

Alternatywne zapytanie do dokumentu XML, pobierające dane za pomocą metod wbudowanych w typ XML, będzie wyglądało tak :

DECLARE @xmldata XML
 
SELECT @xmldata=BulkColumn
FROM 
OPENROWSET (BULK 'D:\DaneXML\NBP\a051z140314.xml',SINGLE_BLOB) as T1
 
 
-- Zastosoowanie XQuery
-- meotda nodes() dzieli 
 
SELECT  
	Tabliczka.element.value('kod_waluty[1]','char(3)') as kod_waluty,
	Tabliczka.element.value('../data_publikacji[1]','varchar(10)') as data_publikacji,
	Cast( Replace(Tabliczka.element.value('kurs_sredni[1]','varchar(10)'),',','.') as smallmoney)  as kurs_sredni,
	Tabliczka.element.value('przelicznik[1]','int') as przelicznik
      -- , Tabliczka.element.value('.././@typ[1]','varchar(10)') as Typ
 
FROM 
	@xmldata.nodes ('/tabela_kursow/pozycja') as Tabliczka(element)
 
-- metoda query() zwraca fragment dokumentu XML
SELECT  @xmldata.query('/tabela_kursow/pozycja[kod_waluty="USD"]/kurs_sredni') as Query
 
-- metoda value() – wartość skalarną
 SELECT  @xmldata.value('(/tabela_kursow/pozycja[kod_waluty="USD"]/kurs_sredni)[1]',
                                                              'varchar(10)') as Value

Odpytywanie_XML_w_SQL_05

Działanie metody nodes() jest podobne do funkcji tabelarycznych, dlatego możemy ją stosować we FROM. Poszatkowała nam ona dokument XML, na zbiór mniejszych elementów. Żeby lepiej sobie to wyobrazić, każdy z nich mógłby wyglądać mniej więcej tak :

    <nazwa_waluty>dolar amerykański</nazwa_waluty>
    <przelicznik>1</przelicznik>
    <kod_waluty>USD</kod_waluty>
    <kurs_sredni>3,0481</kurs_sredni>

Upraszcza to sposób przeszukiwania i odwoływania do fragmentów dokumentu XML.

Co bardzo ważne – tablica elementów (Tabliczka) powstałych na wskutek działania nodes(), nie stanowi osobnych dokumentów. Każdy z nich jest przetwarzany w kontekście dokumentu głównego. Lepszą interpretacją działania nodes() jest utworzenie wektora węzłów (wskaźników) wewnątrz dokumentu głównego.

W ramach węzłów stworzonych przez tą funkcję, możemy sięgać do dowolnych elementów np. wyżej w hierarchii – wartości data_publikacji czy atrybutu typ (jest on zakomentowany w tym przykładzie).

Dwie kolejne kwerendy to proste przykłady zastosowania metod query() oraz value() do przeszukiwania elementów o określonej wartości.


Przeszukiwanie dokumentów XML z określoną przestrzenią nazw

Większość plików XML ma określoną przestrzeń nazw. Obydwie zaprezentowane w tym artykule metody pobierania danych z dokumentów XML, obsługują oczywiście przestrzenie nazw.

Korzystając z natywnych metod, możemy je definiować na różne sposoby. Każde z poniższych zapytań, zwróci poprawny rezultat :

USE AdventureWorks2008
GO
 
-- sposób 1
SELECT  
 hj.Resume.value(
 'declare namespace MyNS="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/Resume"; 
 (/MyNS:Resume/MyNS:Name/MyNS:Name.First)[1]' ,'nvarchar(100)')  as FirstName,
 hj.Resume.value(
 'declare namespace MyNS="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/Resume"; 
 (/MyNS:Resume/MyNS:Name/MyNS:Name.Last)[1]' ,'nvarchar(100)')  as LastName
FROM [HumanResources].[JobCandidate] hj;
 
-- sposób 2
WITH XMLNAMESPACES (N'http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/Resume' as MyNS)
SELECT
 hj.Resume.value(
 '(/MyNS:Resume/MyNS:Name/MyNS:Name.First)[1]' ,'nvarchar(100)')  as FirstName,
 hj.Resume.value(
 '(/MyNS:Resume/MyNS:Name/MyNS:Name.Last)[1]' ,'nvarchar(100)') as LastName
FROM [HumanResources].[JobCandidate] hj;
 
-- sposób 3
WITH XMLNAMESPACES (DEFAULT N'http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/Resume' )
SELECT hj.Resume.value(
 '(/Resume/Name/Name.First)[1]' ,'nvarchar(100)')  as FirstName,
  hj.Resume.value(
 '(/Resume/Name/Name.Last)[1]' ,'nvarchar(100)') as LastName
FROM [HumanResources].[JobCandidate] hj

Odpytywanie_XML_w_SQL_07

Z kolei definiowanie przestrzeni nazw w przykładzie wykorzystującym funkcję OPENXML, sprowadza się do przekazania tej informacji w momencie przygotowania dokumentu, czyli wywołania procedury sp_xml_preparedocument. Przyjmuje ona opcjonalnie dodatkowy parametr.

Ponieważ funkcja OPENXML(), jest ściśle skojarzona z procedurami składowanymi, zastosowanie jej w celu osiągnięcia podobnego rezultatu (czytania wielu obiektów XML), wymaga działania na kursorach.

Widać więc, że nie jest to wygodna ani efektywna metoda, przeszukiwania dokumentów XML składowanych w tabeli. Być może wydawać się prostsza lub dla niektórych, (historycznie) bardziej bliska. Polecam jednak metody natywne, bo są bardziej uniwersalne i z pewnością szybsze.

Przetworzenie pierwszego dokumentu XML z określoną przestrzenią nazw za pomocą OPENXML, może wyglądać tak :

DECLARE @idoc int, @rootxmlns varchar(100)
DECLARE @doc xml 
 
SELECT TOP 1 @doc=Resume
FROM [HumanResources].[JobCandidate] hj
 
SET @rootxmlns = '<root xmlns:MyNS="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/Resume" />'
EXEC sp_xml_preparedocument @idoc OUTPUT, @doc, @rootxmlns
 
SELECT    *
FROM       OPENXML (@idoc, '/MyNS:Resume/MyNS:Name ',1)
WITH
(	
	FirstName nvarchar(100)  './MyNS:Name.First',
	LastName nvarchar(100) './MyNS:Name.Last'
)
 
EXEC sp_xml_removedocument @idoc
GO

Odpytywanie_XML_w_SQL_08


Podsumowanie

Na temat języka zapytań XQuery oraz samego XML’a można napisać wiele artykułów. Z założenia, rozdział ten miał być zwięzłym wprowadzeniem i prezentować gotowe rozwiązania kwerend do dokumentów XML. Dlatego ograniczyłem się tylko do kilku podstawowych przykładów z wykorzystaniem funkcji OPENXML oraz metod typu danych XML – nodes(), value() oraz query(). Jeśli szukasz szerszej wiedzy na ten temat XML – zapraszam na moje kursy.

Zapytania do źródeł zewnętrznych

W dzisiejszych czasach, rzadko można spotkać komercyjny system będący „samotną wyspą”. Umiejętność sięgania do danych z różnych serwerów czy plików jest niezwykle przydatna w codziennej pracy.

W ramach tego kursu umieściłem kilka, moim zdaniem obowiązkowych, artykułów dotyczących możliwości pisania zapytań SQL do źródeł zewnętrznych.


Pisanie kwerend rozproszonych

W każdej większej firmie z którą współpracowałem, działało komercyjnie wiele różnych aplikacji. Pracowały one często w diametralnie innych środowiskach (Windows / Unix). Zazwyczaj na dedykowanych platformach sprzętowych czy maszynach wirtualnych.

Dzieje się tak zazwyczaj w większych korporacjach czy podmiotach o bogatej historii informatycznej. Systemy są mocno zróżnicowane, wiekowe aplikacje działają obok najnowszych wdrożeń. Krytyczne są separowane od mniej ważnych.
Jest to także konsekwencja stosowania dedykowanych platform serwerowych, dostarczanych „w pakiecie” przez producentów sprzętu czy aplikacji.

Zapytania rozproszone w SQL Server

Bardzo ważną cechą jest także możliwość integracji z systemami zewnętrznymi – np. bazami Dostawców czy Klientów. Muszą istnieć metody, swobodnej wymiany informacji np. za pomocą plików XML czy usług sieciowych.

Stąd potrzeba pobierania danych z wielu źródeł na jednej platformie. W szczególności, możliwość pisania zapytań SQL do serwerów rozproszonych lub plików z danymi.


Metody dostępu do zewnętrznych danych

W SQL Server mamy szereg mechanizmów, pozwalających na sięganie do danych poza instancję z której wykonujemy zapytania. Przypomnę, że na jednej fizycznej maszynie, może być zainstalowanych wiele instancji SQL Server. Wtedy sięganie do innych np. starszych wersji serwera, rozpatrujemy również jako kwerendy rozproszone.

Pisanie kwerend rozproszonych to przeważnie część procesów ETL (Extract, Transform & Load), związanych np. z zasilaniem hurtowni danych, replikacją czy wymianą danych między serwerami. Dedykowanym środowiskiem do tworzenia tego typu procesów jest Integration Services (dostępne w edycji Standard i wyższych).

W rozdziale tym skupiamy się na metodach uniwersalnych, bezpośredniego dostępu do danych z poziomu pojedynczej kwerendy SQL. Dostępnych również w wersjach darmowych – Express.

Najważniejsze i najbardziej praktyczne z nich, opisałem w trzech dedykowanych artykułach :


Podsumowanie

Każda z obecnych na rynku, liczących się platform bazodanowych tj. SQL Server, Oracle, MySQL, Postgre czy DB2, jest w stanie obsłużyć zdecydowaną większość wdrażanych aplikacji. Myślę, że jedną z ważniejszych cech dobrego produktu, jest prostota, elastyczność jego integracji i możliwość pracy w mocno zróżnicowanym środowisku. W SQL Server stosunkowo prosto można ten cel osiągnąć za pomocą opisanych powyżej metod oraz szerokich możliwości jakie dają paczki SSIS (SQL Server Integration Services).

Pozostałe użyteczne funkcje skalarne SQL

W SQL Server, oprócz opisanych w poprzednich artykułach, funkcjach daty i czasu, tekstowych czy matematycznych, istnieje wiele innych kategorii. Związane mogą być one z rozszerzeniami analitycznymi SQL (funkcje analityczne w SQL), bezpieczeństwem czy wyciąganiem informacji o strukturach i środowisku (metadane).

Opisywanie ich wszystkich w ramach kursu SQL dla początkujących mija się z celem. Chciałbym zwrócić Twoją uwagę na kilka dodatkowych, służących weryfikacji typu danych.

Dzięki nim możesz dokonywać podstawowego sprawdzenia typu danych, np. podczas importu z zewnętrznych źródeł (plików, innych baz danych).


Pierwszą z nich jest funkcja ISDATE ( atrybut ) – zwraca true (1) – jeśli wartość jest datą lub istnieje możliwość niejawnej konwersji na datę. Jej działanie obrazuje poniższy przykład.

-- tylko dwa ostatnie przypadki Exp5 i 6 nie są datami
-- choć obie mogą nimi być np. Exp 5 YYYYDDMM
 
SELECT ISDATE( getdate() ) as Exp1,
       ISDATE( '2013-01-02' ) as Exp2,
       ISDATE( '20130102' ) as Exp3,
       ISDATE( '2013/01/02' ) as Exp4,
       ISDATE( '20131402' ) as Exp5,
       ISDATE( '2013 01 02' ) as Exp6

FN_ISDATE
Używać jej możesz zarówno w SELECT jak i w warunkach WHERE (żeby wyfiltrować tylko takie rekordy, które mają wpisaną datę a nie jakieś inne ciągi znakowe).


Drugą funkcją sprawdzania typu danych jest ISNUMERIC ( atrybut ) – działa analogicznie jak poprzednia. Zzwraca wartość true, jeśli badany atrybut (stała, zmienna, wartość danej kolumny), jest liczbą lub może zostać niejawnie przekonwertowana na liczbę.

-- jeśli jest możliwa niejawna konwersja na dowolny typ liczbowy
-- ISNUMERIC zwróci wartość true
 
SELECT ISNUMERIC('133') as Exp1,
       ISNUMERIC('133 ') as Exp2,
       ISNUMERIC('133.1') as Exp3,
       '133' + 123 as Exp4,
       ' 133 ' + 123.32 as Exp5,
       ' 133.1' - 132.1 as Exp6

FN_ISNUMERIC_01
Zauważ, że niektóre z tych stringów, nie do końca są poprawnymi liczbami (spacje). Jeśli jest to możliwe, silnik bazy danych wykona na nich niejawną konwersję typu na liczbowy, dlatego możliwe jest wykonanie na nich operacji matematycznych bez użycia CAST / CONVERT.

Z tą funkcją wiążą się jednak pewne zagrożenia. Jej działanie jest rozszerzone także na wartości „monetarne”. Akceptuje pewne znaki, których później nie można niejawnie przekonwertować np. na postać float, decimal czy int. Zwraca true również dla wartości zawierających takie symbole jak , . $ E + – etc..

SELECT ISNUMERIC ( '-,') as Result

FN_ISNUMERIC_02
Skoro jest to liczba, to dlaczego nie można zrobić tak :

SELECT '-,' + 10
Msg 245, Level 16, State 1, Line 1
Conversion failed when converting the varchar value '-,' to data type int.

Z drugiej strony, możemy najpierw przekonwertować naszą „problematyczną” liczbę na wartość typu money / smallmoney a dopiero następnie wykonywać na niej operacje matematyczne. To zadziała.

SELECT CAST('-,' as smallmoney) + 10 as Result

FN_ISNUMERIC_03


Na koniec, jeszcze jedna funkcja DATALENGTH ( atrybut ), która zwraca informację o faktycznej liczbie bajtów, ile zajmuje dana wartość.

Możemy przekonać się, jaka jest różnica pomiędzy ciągiem znaków zapisanych standardowo na 8 bitach (1bajt na każdy znak) versus kodowanie w UNICODE (stąd przedrostek nvarchar, nchar oraz N przed stringami) na dwóch bajtach, dla każdego znaku. Zauważ, że funkcja LEN() zwraca informację o liczbie znaków (nie bajtów).

SELECT  DATALENGTH(  'Ala ma kota' ) , 
	DATALENGTH( N'Ala ma kota' ) as DataLen,
	LEN (  'Ala ma kota' ) as ASCIILen, 
	LEN ( N'Ala ma kota' ) as UNICODELen

FN_DATALENGTH

Funkcje konwersji typów, CAST i CONVERT

Jednymi z częściej stosowanych skalarnych funkcji wbudowanych są CAST oraz CONVERT. Służą one do konwersji typów danych na inne (np. liczby na ciąg znaków). Szczególnie pomocne, gdy chcesz np. dokonać konkatenacji (złączenia) atrybutów w ciągi znakowe (stringi) z wartościami typu data czy liczbami.

W T-SQL trzeba zadbać o sensowność operacji pod względem typów danych na któych operujemy. Trudno porównać wartość tekstową ‚Seattle’ z liczbą 2. Poniższe dwa zapytania zawierają typowe błędy, związane ze znaczącą różnicą porównywnaych typów czy przekształcacnych danych (składanie stringu).

use northwind
go
 
-- błąd konwersji w warunku WHERE 
-- porównanie wartości tekstowej z liczbą
select * from dbo.Employees
where City = 2
 
-- błąd konwersji w SELECT
-- próba połączenia stringów z typem danych date/time
select LastName + ' urodzony : ' + BirthDate
from dbo.Employees
Msg 245, Level 16, State 1, Line 3
Conversion failed when converting the nvarchar value 'Seattle' to data type int.

Msg 241, Level 16, State 1, Line 3
Conversion failed when converting date and/or time from character string.

W niektórych przypadkach, można działać na różniących się typach z tej samej rodziny. Wtedy gdy możliwa jest niejawna konwersja – np. wartość liczbowa typu całkowitego oraz zmiennoprzecinkowa. Jeśli jednak chcemy być pewni wyniku, powinniśmy zawsze zatroszczyć się o pełną zgodność typów. Funkcje CAST oraz CONVERT służą właśnie do osiągnięcia tego celu.


CAST(wartość_konwertowana AS typ_danych) jest podstawową funkcją konwersji zgodną ze standardem ANSI. Jej działanie ogranicza się do bezpośredniej konwersji danej wartości na inny typ danych podany jako drugi parametr funkcji (po słowie kluczowym AS). Z uwagi na jej kompatybilność z ANSI, powinna być stosowana zawsze, gdy nie potrzeba określać styli (np. w konwersji dat).

Jej możliwości są jednak nieco ograniczone w stosunku do CONVERT, ale w wielu sytuacjach nie ma to znaczenia. Możemy stosować je wymiennie.

Konwersję używamy np. do łączenia danych różnego typu, chcąc uzyskać w rezultacie ciąg znakowy.

USE Northwind
GO
 
SELECT LastName + ' hired : ' +  CAST (HireDate as varchar(100)) as EmpInfo,
       HireDate
FROM dbo.Employees;

FN_CAST_01
Zauważ, że w tym przypadku wartość daty została przekonwertowana na określony styl. Funkcja CAST nie posiada możliwości wyboru stylu, dlatego jeśli chcemy otrzymać samą datę (w formacie YYYY-MM-DD), powinniśmy w tej sytuacji skorzystać z funkcji CONVERT ze wskazanym stylem.


CONVERT (typ_danych, wartość_konwertowana, opcjonalnie_styl) potrafi wszystko to co CAST, dodatkowo możemy określić styl typu danych. Ma on znaczenie zwłaszcza w przypadku konwersji na typy danych związanych z datą i czasem, a także liczbowe (określenie precyzji), XML i binarne. Szczegółowy opis styli znajdziesz tutaj (MSDN).

USE Northwind
GO
 
SELECT 'Hired : ' +  CAST (HireDate as varchar(10)) as konwersjaCast,
        CONVERT(varchar(10),HireDate ,120) as KonwersjaConvertStyles, 
        CAST(CAST (HireDate as date) as varchar(10)) as DblCast,
        HireDate
FROM dbo.Employees

FN_CAST_02
Podobne operacje musimy wykonać jeśli chcemy łączyć ze sobą wartości liczbowe i tekstowe. Poniższy przykład obnaża po raz kolejny ograniczenia CAST (tym razem związane z zaokrąglaniem wartości).

USE AdventureWorks2008
GO
 
SELECT salesOrderId, 'Cast  = ' + CAST(TotalDue as varchar(100)) + 
       '; Convert = ' + CONVERT(varchar(100),TotalDue,2) as Summary, 
       TotalDue
FROM Sales.SalesOrderHeader
WHERE TotalDue BETWEEN 123 AND 124

FN_CAST_CONVERT_03
Trzeba pamiętać, że w ten sposób wykonywana konwersja, musi być możliwa dla wszystkich wartości w danej kolumnie. W przeciwnym razie, jeśli chodzi dla jednej wartości nie będzie możliwa zmiany typu danych – zapytanie zakończy się niepowodzeniem. Zdarza się tak zazwyczaj w „zabrudzonych” bazach, w których dane są niespójne na wskutek np. importów z pominięciem reguł itp. akcji.


W SQL Server 2012 wprowadzono nowe funkcje związane z konwersją typów danych. Szczególnie przydatne to – TRY_CAST oraz TRY_CONVERT. Ich pojawienie upraszcza „czyszczenie danych”.
Funkcje te działają identycznie do CAST oraz CONVERT z tym że dla danych, dla których konwersja nie jest możliwa, zamiast błędu, zwracana jest wartość NULL.