2011-07-25 4 views
32

Je souhaite afficher les résultats d'une instruction SELECT en tant qu'objet JSON.SQL Server SELECT vers la fonction JSON

Je voudrais que ce soit un Fonction et non une procédure stockée !

Par exemple, l'utilisateur tableau ci-dessous

id name  active 
1  Bob Jones 1 
2  John Smith 0 

seraient retournés comme ceci:

[{"id":1,"name":"Bob Jones","active":1},{"id":2,"name":"John Smith","active":0}] 

Merci à l'avance.

+2

Ce n'est pas vraiment quelque chose qui est approprié avec une simple requête SQL. Il est plus logique de le faire avec une sorte de programme qui se trouve devant votre base de données. Quel langage de programmation utilisez-vous pour afficher ces données? – schizodactyl

+0

http://www.adampresley.com/2010/07/experimenting-with-sql-to-json-in-sql.html a un exemple de le faire avec une fonction CLR pour analyser une réponse XML en JSON. Je ne sais pas si vous trouverez une solution viable en T-SQL pur. – Yuck

+1

Et ... qu'avez-vous essayé jusqu'ici? Cela ressemble plus à une * enchère * qu'à une question ... –

Répondre

63

Vous pouvez utiliser for xml path, .: par exemple

declare @t table(id int, name nvarchar(max), active bit) 
insert @t values (1, 'Bob Jones', 1), (2, 'John Smith', 0) 

select '[' + STUFF((
     select 
      ',{"id":' + cast(id as varchar(max)) 
      + ',"name":"' + name + '"' 
      + ',"active":' + cast(active as varchar(max)) 
      +'}' 

     from @t t1 
     for xml path(''), type 
    ).value('.', 'varchar(max)'), 1, 1, '') + ']' 

Sortie:

[{"id":1,"name":"Bob Jones","active":1},{"id":2,"name":"John Smith","active":0}] 
+0

J'aime ce que vous avez fait ici. Mais le contenu de la table pourrait changer. Une fois, il pourrait être id, nom, actif. Une autre fois, il pourrait être ID, nom, email, date, etc .. – jamesmhaley

+0

@sparkyfied: Je ne pense pas que vous pouvez aider cela. Vous aurez les mêmes problèmes si vous videz XML et que le contenu change. – Yuck

+0

@yuck, serait-il possible de le faire dans une boucle des colonnes de sortie du nom de la colonne et la valeur (ne veut pas un fragment de code, je veux juste savoir si c'est possible) – jamesmhaley

10

Alors d'abord, je tiens à remercier Kirill Polishchuk pour l'exemple de code essentiel ... Merci! J'ai pris cela et suis allé construire une procédure pour faire ce que j'ai besoin de faire, et c'est de me donner une sortie JSON basée sur "tout" jeu de résultats je veux dire objet de table (pas variable) dans SQL Server .

Idéalement, je voudrais cela comme une fonction, mais en raison de limitations sur ce que vous pouvez faire dans une fonction, cette partie devra attendre ... peut-être v2. :)

Et oui, l'enregistrement d'une procédure étendue (CLR) est certainement plus facile, mais je voulais éviter cette voie pour l'instant.

PS: pour les tables temporaires, vient de mettre en 'tempdb .. # nom_table'

Ici, il est:

  /* 
      Author:   Goran Biljetina 
      Create date: 03/13/2013 
      Description: consume a table object (not table var), output it as JSON Properties string 
      */ 

      /* 
      --> example run 
      -- EXEC dbo.JSONreturn @tblObjNameFQ='[database].[schema].[object_name_table]'; 
      */ 

      CREATE PROCEDURE dbo.JSONreturn 
      (
      @committedRead bit = 0 --> if 1 then committed else uncommitted read 
      ,@debugmode bit = 0 --> if 1 display certain outputs 
      ,@tblObjNameFQ varchar(128) --> fully qualified table object name, i.e. db.schema.object_name 
      ,@stringJSON nvarchar(max) = null OUTPUT 
      ) 

      AS 
      BEGIN 

       if @committedRead=0 
       begin 
        SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; --> evaluate if necessary in test phase 
       end 
        else if @committedRead=1 
         begin 
          SET TRANSACTION ISOLATION LEVEL READ COMMITTED; 
         end 

       SET NOCOUNT ON; 

       ---------------------------------------------------------------------------------------------------------- 
       if (PATINDEX('%[\.]%',@tblObjNameFQ)<1 AND patindex('%#%',@tblObjNameFQ)<1) OR LEN(@tblObjNameFQ)>(3*128) 
       begin 
        PRINT 'table (object) name not fully qualified or invalid!' 
        RETURN -1 
       end 


       declare 
       @objname varchar(128) 
       ,@dbname varchar(128) 
       ,@schema varchar(128) 
       ,@maxColNum int 
       ,@inc int 
       ,@dqsl_misc varchar(max) 
       ,@dsql_wrapper varchar(max) 
       ,@dsql_what varchar(max) 
       ,@dsql_where varchar(max) 
       ,@dsql_complete varchar(max) 


       create table #maxColNum (column_id int) 
       create table #ColPrep (colString varchar(max), column_id int) 
       create table #JSONoutput (string nvarchar(max)) 


       if patindex('%#%',@tblObjNameFQ)>0 
       begin 
        set @objname = (PARSENAME(@tblObjNameFQ,1)) 
        set @dbname = 'tempdb' 
       end 
       else if patindex('%#%',@tblObjNameFQ)<1 
        begin 
         set @dbname = SUBSTRING(@tblObjNameFQ,1,PATINDEX('%[\.]%',@tblObjNameFQ)-1) 
         set @objname = convert(varchar,(PARSENAME(@tblObjNameFQ,1))) 
         set @schema = convert(varchar,(PARSENAME(@tblObjNameFQ,2))) 
        end 

       --select @objname[@objname], @dbname[@dbname], @schema[@schema] 
       --select @dbname+'.'[email protected]+'.'[email protected] 

       set @dqsl_misc = 
       ' 
       select max(column_id) 
       from '[email protected]+'.sys.columns 
       where object_id = 
       (select object_id from '[email protected]+'.sys.objects where type = ''U'' and name like ''%'[email protected]+'%'') 
       ' 
       insert into #maxColNum 
       exec(@dqsl_misc) 

       set @maxColNum = (select column_id from #maxColNum) 
       set @dsql_what = '' 

       set @dsql_wrapper = 
       ' 
       select ''['' + STUFF((
         select 
          '',{''+<<REPLACE>> 
          +''}'' 
       ' 
       set @dsql_where = 
       ' 
         from '[email protected]+'.'+case when @schema is null then '' else @schema end+'.'[email protected]+' t1 
         for xml path(''''), type 
        ).value(''.'', ''varchar(max)''), 1, 1, '''') + '']'' 
       ' 

       set @dqsl_misc = 
       ' 
       select ''"''+sysc.name+''": '' 
         +case 
         when syst.name like ''%time%'' or syst.collationid is not null then ''"''''+cast(''+sysc.name+'' as varchar(max))+''''",'' 
         when syst.name = ''bit'' then ''''''+cast((case when ''+sysc.name+''=1 then ''''true'''' else ''''false'''' end) as varchar(max))+'''','' 
         else ''''''+cast(''+sysc.name+'' as varchar(max))+'''','' 
         end as colString, sysc.column_id 
       from '[email protected]+'.sys.columns sysc 
        join '[email protected]+'.sys.systypes syst 
         on sysc.system_type_id = syst.xtype and syst.xtype <> 240 and syst.name <> ''sysname'' 
       where object_id = (select object_id from '[email protected]+'.sys.objects where type = ''U'' and name like ''%'[email protected]+'%'') 
       order by sysc.column_id 
       ' 
       insert into #ColPrep 
       exec(@dqsl_misc) 

       set @inc = (select MIN(column_id) from #ColPrep) 


       while @inc<[email protected] 
       begin 

        set @dsql_what = @dsql_what+(select case 
               when @inc = @maxColNum then replace(colString,',','') 
               else colString end 
               from #ColPrep where column_id = @inc) 

        set @[email protected]+1 

        IF @inc>@maxColNum 
         set @dsql_what = ''''[email protected]_what+'''' 

        IF @inc>@maxColNum 
         BREAK 
        ELSE 
         CONTINUE 
       end 

       set @dsql_complete = REPLACE(@dsql_wrapper,'<<REPLACE>>',@dsql_what)[email protected]_where 

       insert into #JSONoutput 
       exec(@dsql_complete) 

       SET @stringJSON = (Select string from #JSONoutput) 
       ---------------------------------------------------------------------------------------------------------- 

      END 
+0

ohh j'ai oublié d'ajouter que oui, je vois des bugs et des incohérences ... mais j'ai lancé ça assez vite, mais je pensais juste que je dis, "ouais je sais". :) –

+0

Très bien! Je sais que vous le savez, mais il ne gère pas les champs date-heure, mais c'est OK. C'est très utile. – smoore4

16

Juste pour améliorer la réponse avec le dernier changement de technologie. avec le serveur sql 2016

select id, name ,active 
    from tableName 
     FOR JSON AUTO 
+1

Cela fonctionne avec SQL Server 2014 également – matadur

+0

@matadur autant que je peux voir, pour le soutien de JSON a été ajouté seulement en 2016, y at-il une mise à jour pour 2014 pour le permettre? – kerray

+0

Peut-être a-t-il été ajouté dans une mise à jour de Management Studio. J'ai SQL Server 2014 avec Management Studio 12.0.2000.8, et le FOR JSON fonctionne. – matadur