-1

My question is to know if it is possible from T-SQL to create a JSON file in previous versions of 2016, since from this version it already brings the function implicitly, but in my case I am using SQL Server 2014.

Is there a way to parse it from XML to JSON or create a function?

Here's an example of an XML File with objects inside him processing by SP.

ALTER PROCEDURE [dbo].[sp_Socio_IntegracionPOST] @Codigo nvarchar(20), @Query int
AS
BEGIN

    DECLARE @socio xml,@direccion xml,@contacto xml
  SET NOCOUNT ON;

  --Este query consulta el socio de negocio
  IF (@Query = 1)
  BEGIN

  SET @direccion = (SELECT 
      SUCURSAL AS AddressName,
      DIRECCION AS Street,
      mun.NombreMunicipio AS 'Block',
      FORMAT(CONVERT(int, codciudad), '00000') AS ZipCode,
      mun.NombreMunicipio AS City,
      'CO' AS County,
      'CO' AS Country,
      dep.IdSAP AS 'State',
      NULL AS AddressType,
      RTRIM(dir.CODIGO) AS BPCode,
      CONVERT(date, GETDATE()) AS CreateDate,
      CONVERT(char(8), GETDATE(), 108) AS CreateTime,
      FORMAT(CONVERT(int, codciudad), '00000') AS U_HBT_MunMed,
      CASE
        WHEN DEFECTO_FACTURA = 1 THEN 'Y'
        ELSE 'N'
      END AS U_HBT_DirMM
    FROM tblmvto_direccion dir
    INNER JOIN tblMunicipios mun
      ON dir.CODCIUDAD = mun.CodMunc
    INNER JOIN tblDepartamentos dep
      ON dir.DEPARTAMENTO = dep.NombreDepartamento
    WHERE dir.CODIGO = @Codigo
    FOR XML PATH ('Row'))

    SET @contacto = (SELECT 
      RTRIM(contac.CODIGO) AS CardCode,
      CONCAT(RTRIM(contac.PrimerNombre), RTRIM(' ' + contac.SegundoNombre), RTRIM(' ' + contac.PrimerApellido), RTRIM(' ' + contac.SegundoApellido)) AS 'Name',
      contac.Telefono AS Phone1,
      contac.TelefonoMovil as MobilePhone,
      contac.CorreoContacto AS E_Mail,
      'E' AS Gender,
      'Y' AS Active,
      contac.PrimerNombre AS FirstName,
      contac.SegundoNombre AS MiddleName,
      CONCAT(RTRIM(contac.PrimerApellido), RTRIM(' ' + contac.SegundoApellido)) AS LastName,
      CONVERT(date, GETDATE()) AS CreateDate,
      CONVERT(char(8), GETDATE(), 108) AS CreateTime
    FROM tblmvto_contactos contac
    WHERE contac.CODIGO = @Codigo
    FOR XML PATH('Row'))

    SET @contacto = CONVERT(xml, '<ContactEmployees>'+CAST(@contacto AS nvarchar(MAX))+'</ContactEmployees>')
    SET @direccion = CONVERT(xml, '<BPAddresses>'+CAST(@direccion AS nvarchar(MAX))+'</BPAddresses>')


      SET @socio = (SELECT top 1
      RTRIM(sn.codigo) AS CardCode,
      RTRIM(sn.nit) as FederalTaxID,
      CONCAT(RTRIM(sn.nombre), RTRIM(' ' + sn.nombre1), RTRIM(' ' + sn.apellido), RTRIM(' ' + sn.apellido1)) AS CardName,
      [dbo].[FN_Validar_CardType_SocioNegocio](sn.escliente, sn.esprovee, sn.esempleado) AS CardType,
      CASE
        WHEN sn.GranContribuyente = 1 THEN 'S'
        ELSE 'N'
      END AS U_GraCont,
      RTRIM(sn.celular) AS Phone1,
      CONCAT(rtrim(sn.nombre), RTRIM(' ' + sn.nombre1)) AS U_HBT_Nombres,
      RTRIM(sn.apellido) AS U_HBT_Apellido1,
      RTRIM(sn.apellido1) AS U_HBT_Apellido2,
      sn.Nacionalidad AS U_HBT_Nacional,
      CASE
        WHEN sn.codtipoper = 'O-SIN' THEN 1
        ELSE CONVERT(int, sn.codtipoper)
      END AS U_HBT_TipEnt,
      FORMAT(CONVERT(int, sn.codciudad), '00000') AS U_HBT_MunMed,
      CASE
        WHEN ti.IdSAP = 'O-SIN' THEN '13'
        ELSE ti.IdSAP
      END AS U_HBT_TipDoc,
      CASE
        WHEN tc.IdSAP = 'O-SIN' OR
          tc.IdSAP IS NULL THEN 'RS'
        ELSE tc.IdSAP
      END AS U_HBT_RegTrib,
      CASE
        WHEN sn.Autorretenedor = 0 THEN 'N'
        ELSE 'Y'
      END AS U_HBT_AutRet,
      CASE
        WHEN rf.IdSAP = 'O-SIN' THEN 'R-99-PN'
        ELSE rf.IdSAP
      END AS U_HBT_RegFis,
      mp.IdSAP AS U_HBT_MedPag
    FROM tblsocio_negocios sn
    INNER JOIN tbltipo_identificacion ti
      ON sn.codtipo = ti.codtipo
    INNER JOIN tbltipo_contribuyente tc
      ON sn.codcontribuye = tc.codcontribuye
    INNER JOIN tblregimenfiscal rf
      ON sn.RegimenFiscal = rf.Id
    INNER JOIN tblMedioPago mp
      ON sn.MedioPago = mp.Id
    WHERE sn.codigo = @Codigo
    FOR XML PATH ('BusinessPartner'))
    SELECT CAST( CAST(@socio AS nvarchar(MAX)) + '(Objeto)' +  CAST(@contacto AS nvarchar(MAX)) + '(Objeto)' + CAST(@direccion AS nvarchar(MAX)) as nvarchar(max))
  END
END
Thom A
  • 88,727
  • 11
  • 45
  • 75
  • The short answer is "no". The long answer is, it's very messy (see duplicate). The real answer is that if you need to parse JSON in T-SQL, then upgrade to a version that supports JSON. – Thom A Jun 21 '22 at 15:05
  • 1
    Best way: upgrade to a version of SQL Server that's still supported. Second-best way: send data to a client as a rowset, and perform conversion to JSON on the client end. Least preferred way: any solution trying to do it in T-SQL without native support. Of those approaches, using a CLR function would at least be a mostly reliable way of doing it. Using sufficiently clever string manipulation is probably going to fail on corner cases, if you can even get it to work at all. – Jeroen Mostert Jun 21 '22 at 15:06
  • 1
    Sude note, the prefix `sp_` is reserved, by Microsoft, for **S**pecial / **S**ystem **P**rocedures. It should *not* be used for User Procedures. Doing so comes with a performance cost and the risk of your Procedure simply not working one day after an update/upgrade. Either use a different prefix or (possibly better) no prefix at all. [Is the sp_ prefix still a no-no?](https://sqlperformance.com/2012/10/t-sql-queries/sp_prefix) – Thom A Jun 21 '22 at 15:07
  • It's not easy to upgrade in a corporate environment. SQL Server is supported for ten years from the time of release so you have at least two more years of MS support. – benjamin moskovits Jun 21 '22 at 15:14
  • @benjaminmoskovits that's why I said it's no longer in mainstream support. And precisely because it's not easy to upgrade in a corporate environment, 2 years before End Of Life is *time to panic*. Unless you're a bank willing to pay more for a direct support contract with Microsoft than the cost of buying new iron and licenses. And then there's PCI and auditors that would frown upon using unsupported database versions – Panagiotis Kanavos Jun 21 '22 at 15:17
  • 1
    @MartinSmith oops, I meant 2017 – Panagiotis Kanavos Jun 21 '22 at 15:19
  • `I am using SQL Server 2014`. that version is no longer supported. The oldest version still in mainstream support is SQL Server 2017 - a 5 year old version. That means there are no patches or fixes for 2014 any more, only security fixes. Even extended support for 2014 ends in 2024. It's time to upgrade. If you're in a slow moving corporate environment, 2 years isn't as long as it sounds. – Panagiotis Kanavos Jun 21 '22 at 15:20
  • Having worked for Fortune 100 companies most of my life many organizations work on a ten-year cycle for SQL Server (essentially as long as MS is issuing security patches) because the product can pass audits. Ideally SQL Server should be updated sooner but I have yet to encounter a production environment where it is updated every five years. What you are suggesting is organizations update SQL Server every three years. I would love to see such a group. – benjamin moskovits Jun 21 '22 at 15:25

1 Answers1

-1

You can but it will take a little work. You can use C Sharp to create a CLR function that can be passed an nvarchar type and return an nvarchar type. There is no JSON type so it would have to be stored, typically, as a nvarchar(max).

On the C Sharp side it is not hard to do - look at serialization methods. Many users are hesitant to use the CLR but its a short learning curve and can be very useful. Please see the comments below for limitations of CLR.

benjamin moskovits
  • 5,261
  • 1
  • 12
  • 22
  • `it is not hard to do` actually it is, because SQLCLR is essentially .NET 3.5 minus. It doesn't support NuGet packages so it can't use JSON.NET. You can jump through some hooks to bundle some very old JSON.NET version, or use the non-compliant JSON serializers used before JSON.NET, but it's not worth it. The obsolete JavascriptSerializer for example didn't produce proper dates – Panagiotis Kanavos Jun 21 '22 at 15:15
  • @PanagiotisKanavos: it's not quite as bad as that. SQLCLR uses the 2.0 runtime on SQL Server 2005 through 2008 R2. From 2012 onwards it uses the 4.0 runtime. It's still no picnic to get arbitrary assemblies and their dependencies to work, but at least it's possible. – Jeroen Mostert Jun 21 '22 at 15:21
  • 1
    4.x without async is a bit of a problem. You'd have to go back far enough to find a JSON.NET version that run on 4.0, and then bundle it manually. Up to a point JSON.NET didn't produce ISO8601 date strings without extra configuration either. It's far safer to convert the data on the client rather than the server – Panagiotis Kanavos Jun 21 '22 at 15:29