sql >> Database >  >> RDS >> Sqlserver

Binaire gegevenstypen opslaan in SQL Server

Inleiding

Dagelijks werk vereist zelden dat binaire gegevens rechtstreeks in databasekolommen worden opgeslagen. In sommige gevallen is het echter erg handig.

In tegenstelling tot wat vaak wordt gedacht, kunnen byte-arrays helpen met aanzienlijk meer dan alleen het opslaan van grote binaire objecten (documenten, multimedia, enz.). Ze kunnen ook worden gebruikt om hash-waarden en voorbeeldgegevens op te slaan voor sneller zoeken/analyse op hoog niveau. Of ze kunnen bytes bevatten die in de AAN/UIT-status staan ​​in een elektronisch relais. Zodra we beginnen na te denken over hardwaregegevens die zijn opgeslagen in databases, worden toepassingen duidelijker.

In tegenstelling tot VARCHAR-gegevenstypen waarbij u moet zorgen voor sortering en codetabellen, zijn binaire gegevenstypen reeksen bytes (soms byte-arrays genoemd in objectgeoriënteerde programmeertalen), ofwel vast (BINAR ) of variabel (VARBINAR ) in grootte.

Om details over binaire typen beter te begrijpen, zullen we eerst een korte inleiding geven over hexadecimale getallen, waarmee deze gegevens intern worden opgeslagen.

Hexadecimale getallen

Als je de les over hexadecimale getallen op de middelbare school hebt overgeslagen, kun je een goede introductie vinden op een speciale Wikipedia-pagina. Daar kunt u vertrouwd raken met dit nummeringsformaat.

Om dit artikel te begrijpen, is het belangrijk om te weten dat SQL Server Management Studio binaire gegevens in hexadecimale indeling weergeeft met het voorvoegsel "0x".

Er is geen groot verschil tussen hexadecimale en decimale nummeringsindeling. Het hexadecimale formaat maakt gebruik van grondtal-16 tekens (0-9 en A-F) in plaats van grondtal-10 van decimale notatie (0-9). Waarden A-F zijn getallen 10-15 van decimale nummering.

Daarom gebruiken we hexadecimale notatie. Aangezien één byte 8 bits bevat, wat 256 discrete gehele getallen mogelijk maakt, is het voordelig om bytes in hex-formaat te presenteren. Als we het bereik 0-256 targeten, wordt dit weergegeven als 00-FF in hexadecimale notatie. Prefix in Management Studio is voor de leesbaarheid, om te benadrukken dat we hexadecimale getallen weergeven en niet de standaard decimale waarden.

Handmatige waardeconversie met CAST()

Aangezien binaire waarden in hun strikte zin tekenreeksen zijn, kunnen we ze converteren van getal- naar tekenformaat met behulp van CAST of CONVERTEREN SQL-methoden.

Bekijk het voorbeeld dat de CAST . gebruikt methode:

SELECT CAST('HexTest' AS VARBINARY);                 
SELECT CAST(0x48657854657374 AS VARCHAR);  

Conversiestijlen gebruiken met CONVERT()

CONVERTEREN() methode, in tegenstelling tot CAST() , heeft een extra optie om conversiestijlen te gebruiken.

Conversiestijlen zijn sjablonen voor regels die worden gebruikt in het conversieproces. CONVERTEREN() wordt meestal gebruikt in datum/tijd-bewerkingen. Wanneer de gegevens in een niet-standaard formaat zijn, kunnen deze worden gebruikt voor binaire waardeconversie. Houd er rekening mee dat binaire gegevenstypen geen automatische conversie van gegevenstypen ondersteunen zonder de juiste parameterwaarden. Dan zal SQL Server een uitzondering genereren.

Als we kijken naar de CONVERT() methodedefinitie, we zien dat er twee verplichte en één optionele parameter nodig zijn.

De eerste parameter is het doelgegevenstype en de tweede is de waarde waarvan we willen converteren. De derde parameter kan in ons geval de waarde 1 . hebben of 2 . Waarde 1 betekent dat CONVERTEREN() moet de invoertekenreeks beschouwen als een hexadecimale tekenreeks in tekstformaat, en waarde 2 betekent dat je de 0x . wilt overslaan voorvoegsel.

Bekijk de voorbeelden die dat gedrag vertonen:

DECLARE @MyString NVARCHAR(500)='0x48657854657374';

SELECT CONVERT(VARBINARY(MAX), @MyString );    
-- String value is directly converted to binary value - we wanted is to change the datatype 
-- and not convert "0x.." prefix to the hexadecimal value

SELECT CONVERT(VARBINARY(MAX), @MyString, 1);  

Verschil tussen BINAIR en VARBINAIR

Met binaire gegevens kunnen we twee soorten gegevenstypen gebruiken:vaste grootte en variabele grootte. Of ze zijn BINAIR en VARBINAIR.

Als we de variabele met een vaste grootte gebruiken, wordt de inhoud altijd uitgebreid tot de gedefinieerde grootte met een opvulling van 0x00 … – er is geen opvulling in variabele lengte. Bij het gebruik van de sombewerking op deze variabelen wordt geen optelling uitgevoerd. Waarden worden aan elkaar toegevoegd. Hetzelfde is als met stringtypes.

Om het gedrag van prefixen te demonstreren, gebruiken we twee eenvoudige voorbeelden met de binaire sombewerking:

SELECT CAST('T' AS BINARY(1)) + CAST('e' AS BINARY(1)) + CAST('s' AS BINARY(1)) + CAST('t' AS BINARY(1)); 
SELECT CAST('T' AS BINARY(2)) + CAST('e' AS BINARY(2)) + CAST('s' AS BINARY(2)) + CAST('t' AS BINARY(2)); 

Elke waarde in de BINARY(2)-instructie wordt gefixeerd met 0x00 waarden.

Gehele waarden gebruiken met binaire gegevenstypen

SQL Server wordt geleverd met ingebouwde methoden om te converteren tussen numerieke typen en binaire typen. We hebben dit aangetoond waar we de Test . hebben omgedraaid tekenreeks in het binaire formaat en dan terug naar het BIGINT-formaat, zonder de functie ASCII() te gebruiken:

SELECT CAST('Test' AS VARBINARY(MAX));
SELECT CAST(CAST('Test' AS VARBINARY(MAX)) AS BIGINT);

Eenvoudige conversie tussen karakter en hexadecimale waarden

Om te converteren tussen charter- en hexadecimale waarden, is het handig om een ​​aangepaste functie te schrijven die deze bewerking consistent zou uitvoeren. Een mogelijke benadering is hieronder:

-- DROP FUNCTION dbo.FN_CH_HEX(@InputValue CHAR(1)

CREATE OR ALTER FUNCTION dbo.FN_CH_HEX(@InputValue CHAR(1))
RETURNS CHAR(2)
AS
BEGIN
    RETURN(CONVERT(CHAR(2), CAST(@InputValue AS BINARY(1)), 2));
END;

-- SELECT dbo.FN_CH_HEX('A') 

Deze keer gebruikten we de parameterwaarde 2 in de CONVERTEREN() functie. Het laat zien dat deze bewerking niet moet worden toegewezen aan ASCII-code en moet worden weergegeven zonder de 0x… voorvoegsel.

Voorbeeld case study:foto's opslaan in SQL Server binair type

We benaderen dit probleem meestal door een aangepaste Windows-/webtoepassing te implementeren of een aangepast SSIS-pakket met C#-code te schrijven. In dit voorbeeld gebruik ik alleen de SQL-taal. Het kan handiger zijn als je geen toegang hebt tot de front-end tools van de database.

Om afbeeldingen in de databasetabel op te slaan, moeten we een tabel maken waarin ze kunnen worden bewaard. De tabel moet kolommen bevatten met de naam van de afbeelding en de binaire inhoud van de afbeelding:

-- DROP TABLE T_BINARY_DATA 

CREATE TABLE T_BINARY_DATA 
(
   PICTURE_ID INT IDENTITY(1,1) PRIMARY KEY,
   PICTURE_NAME NVARCHAR(100),
   PICTURE_FILE_NAME NVARCHAR(500),
   PICTURE_DATA VARBINARY(MAX)
)
GO

Om het laden van binaire gegevens naar de SQL Server-instantie mogelijk te maken, moeten we de server configureren met twee opties:

  • Schakel de optie OLE-automatiseringsprocedures in
  • Het BulkAdmin-privilege toekennen aan de gebruiker die het image-importproces uitvoert.

Het onderstaande script zal de taak uitvoeren onder de gebruiker met hoge bevoegdheden van de SQL Server-instantie:

USE MASTER
GO
EXEC sp_configure 'show advanced options', 1; 
GO
RECONFIGURE; 
GO
EXEC sp_configure 'Ole Automation Procedures', 1; 
GO
RECONFIGURE; 
GO
-- Add 'bulkadmin' to the correct user
ALTER SERVER ROLE [bulkadmin] ADD MEMBER [NT AUTHORITY\SYSTEM] 
GO 

Nu kunnen we beginnen met het schrijven van de import- en exportprocedure:

-- DROP PROCEDURE dbo.proc_ImportBinary 
-- DROP PROCEDURE dbo.proc_ExportBinary 

CREATE PROCEDURE dbo.proc_ImportBinary 
(
     @PICTURE_NAME      NVARCHAR(100)
   , @FOLDER_PATH       NVARCHAR(500)
   , @PICTURE_FILE_NAME NVARCHAR(500)
   )
AS
BEGIN
   DECLARE @OutputPath NVARCHAR(4000);
   DECLARE @TSQLDYN    NVARCHAR(4000);
   
   SET @OutputPath = CONCAT(@OutputPath,'\',@PICTURE_FILE_NAME)
   SET @TSQLDYN = 'INSERT INTO T_BINARY_DATA(PICTURE_NAME,PICTURE_FILE_NAME,PICTURE_DATA) '
                + 'SELECT ' + '''' + @PICTURE_NAME + '''' + ',' + '''' + @PICTURE_FILE_NAME + '''' + ', * ' 
				+ '  FROM Openrowset( Bulk ' + '''' + @OutputPath + '''' + ', Single_Blob) as img'

   EXEC (@TSQLDYN)   
END
GO


CREATE PROCEDURE dbo.proc_ExportBinary (
     @PICTURE_NAME      NVARCHAR(100)
   , @FOLDER_PATH       NVARCHAR(500)
   , @PICTURE_FILE_NAME NVARCHAR(500)
   )
AS
BEGIN
   DECLARE @Binary     VARBINARY (max);
   DECLARE @OutputPath NVARCHAR(4000);
   DECLARE @Obj        INT
 
   SELECT @Binary = (
         SELECT CONVERT(VARBINARY(max), PICTURE_DATA , 1)
           FROM T_BINARY_DATA 
          WHERE PICTURE_NAME  = @PICTURE_NAME
         );
 
   SET @OutputPath = CONCAT(@FOLDER_PATH, '\', @PICTURE_FILE_NAME);
         
    BEGIN TRY
     EXEC sp_OACreate 'ADODB.Stream', @Obj OUTPUT;
     EXEC sp_OASetProperty @Obj ,'Type',1;
     EXEC sp_OAMethod @Obj,'Open';
     EXEC sp_OAMethod @Obj,'Write', NULL, @Binary;
     EXEC sp_OAMethod @Obj,'SaveToFile', NULL, @OutputPath, 2;
     EXEC sp_OAMethod @Obj,'Close';
     EXEC sp_OADestroy @Obj;
    END TRY
    
 BEGIN CATCH
  EXEC sp_OADestroy @Obj;
 END CATCH
 
   SET NOCOUNT OFF
END
GO

Nu kunnen we deze procedures op een zeer eenvoudige manier vanuit elke clienttoepassing gebruiken.

Stel dat we afbeeldingen hebben in de C:\Pictures\Inp map. Om deze afbeeldingen te laden, moeten we de volgende code uitvoeren:

-- Load picture to table row
exec dbo.proc_ImportBinary ‘MyPic’, ‘C:\Pictures\Inp’, ‘MyPic.jpg’ 

Op dezelfde manier kunnen we gegevens exporteren naar de C:\Pictures\Out map:

exec dbo.proc_ExportBinary ‘MyPic’, ‘C:\Pictures\Out’, ‘MyPic.jpg’

Conclusie

De keuze tussen binaire objecten of alternatieve manieren om binaire gegevens in een database op te slaan (bijvoorbeeld bestandspaden in een database opslaan en ophalen van de schijf/cloudopslag) hangt van meerdere factoren af.

De algemene regel is dat als het bestand kleiner is dan 256 kilobytes, u het in de VARBINARY-kolommen moet opslaan. Als binaire bestanden groter zijn dan één megabyte, moet u ze op het bestandssysteem opslaan. Als u FILESTREAM beschikbaar heeft in SQL Server-versies 2008 en hoger, houdt het de bestanden onder transactiebeheer als een logisch onderdeel van de database.

Als u besluit binaire bestanden op te slaan in de SQL Server-tabel, gebruik dan een aparte tabel alleen voor binaire inhoud. Vervolgens kunt u de opslaglocatie optimaliseren en toegang krijgen tot de engine, waarschijnlijk door afzonderlijke bestanden en bestandsgroepen voor deze tabel te gebruiken. De gedetailleerde informatie is beschikbaar in het officiële Microsoft-artikel.

Test in ieder geval beide benaderingen en gebruik degene die het beste bij u past.


  1. Een deel van een string in MySQL vervangen

  2. Hoe kun je in SQL groeperen in bereiken?

  3. Hoe vind ik de actieve poort van SQL Server?

  4. Waarom kan ik geen triggers maken voor objecten die eigendom zijn van SYS?