【问题标题】:How can I get a JSON object from a SQL Server table?如何从 SQL Server 表中获取 JSON 对象?
【发布时间】:2009-10-13 18:36:11
【问题描述】:

我有一个要转换为 JSON 的视图。我可以使用什么 SQL 在服务器上生成需要返回的 JSON 字符串?

【问题讨论】:

    标签: javascript sql-server tsql string json


    【解决方案1】:
    -- 
    -- Author:      Thiago R. Santos                                           --
    -- Create date: Aug 3rd 2008                                                   --
    -- Description: Returns the contents of a given table                      --
    --              in JavaScript Object Notation.                             --
    -- Params:                                                                 --
    --      @table_name: the table to execute the query                        --
    --      @registries_per_request: equivalent to "select top N * from table" 
    -- 
    --                               replcing N by the actual number           
    -- Influenced by Thomas Frank's post MySQL to JSON @ January 23, 2007      --
    -- Post Url: http://www.thomasfrank.se/mysql_to_json.html                  --
    
    
    
    create procedure [dbo].[GetJSON]
    (
    @table_name varchar(50),
    @registries_per_request smallint = null
    )
    as
    begin
    if((select count(*) from information_schema.tables where table_name =   @table_name)     > 0)
    begin
        declare @json varchar(max),
                @line varchar(max),
                @columns varchar(max),
                @sql nvarchar(max),
                @columnNavigator varchar(50),
                @counter tinyint,
                @size varchar(10)
    
        if (@registries_per_request is null) 
        begin
            set @size = ''
        end
        else 
        begin
            set @size = 'top ' + convert(varchar, @registries_per_request)
        end
        set @columns = '{'
    
        declare schemaCursor cursor
        for select column_name from information_schema.columns where table_name = @table_name
        open    schemaCursor    
    
        fetch next from schemaCursor
        into  @columnNavigator
    
        select  @counter = count(*) from information_schema.columns where table_name = @table_name
    
        while @@fetch_status = 0
        begin
            set @columns = @columns + '''''' + @columnNavigator + ''''':'''''' + convert(varchar, ' + @columnNavigator + ') + '''''''
            set @counter = @counter - 1
            if(0 != @counter) 
            begin
                set @columns = @columns + ','
            end
    
            fetch next from schemaCursor
            into  @columnNavigator
        end 
    
        set @columns =  @columns + '}'
    
        close       schemaCursor
        deallocate  schemaCursor
    
        set @json = '['
    
        set @sql = 'select  ' + @size + '''' + @columns + ''' as json into tmpJsonTable from ' + @table_name
        exec sp_sqlexec @sql
    
        select  @counter = count(*) from tmpJsonTable
    
        declare tmpCur cursor
        for     select * from tmpJsonTable
        open    tmpCur
    
        fetch next from tmpCur
        into  @line
    
        while @@fetch_status = 0
        begin
            set @counter = @counter - 1
            set @json = @json + @line
            if ( 0 != @counter ) 
            begin
                set @json = @json + ','
            end
    
            fetch next from tmpCur
            into  @line
        end
    
        set @json = @json + ']'
    
        close       tmpCur
        deallocate  tmpCur
        drop table  tmpJsonTable
    
        select @json as json
    end
    end
    

    【讨论】:

    • 想把这个方便的小脚本分享给和我有同样问题的每个人。引用了脚本的作者。
    • 我是否错过了它应该转义数据的地方,以便在字符串中使用错误类型的引号时不会破坏 JSON?
    • 顺便问一下,有人在 SQL Server 中测试过吗?
    • @Alon 我已经测试过了,是的,它可以工作。 @Kev 我按原样发布了脚本,作为大多数有上述类似问题的人使用的起点。像所有脚本一样,通常还有改进的空间,因为我确信原作者所做的假设在其他人使用时可能不会延续。最重要的是,如果它对你有用,如果它没有,那么请随时编辑、改进和分享。
    • 我为上述查询添加了架构支持gist.github.com/mcauser/5250601
    【解决方案2】:

    我想这是可以做到的,但这似乎是一种非常冗长且容易出错的实现预期结果的方法。

    如果我是你,我会将问题分解为查看中间层框架的 ORM 技术(我假设是 ASP.NET?),然后从框架再次序列化为 JSON。失败的框架支持(即您不在 .NET 3+ 中)我仍然倾向于将数据库序列化为 XML,然后 XSLT 将 XML 转换为 JSON,因为 XML 非常很多 em> 在服务器上更容易使用。

    游戏的名称是关注点分离。

    【讨论】:

      【解决方案3】:

      以下版本是对这一概念的全面重新设计。如果我遗漏了什么,请添加注释,我会进行编辑调整。

      --
      -- Author:      Matthew D. Erwin (Snaptech, LLC)
      -- Create date: May 9, 2013                                                
      -- Description: Returns the contents of a given table                      
      --              in JavaScript Object Notation JSON - 
      --
      --              Very notably useful for generating MOCK .json files
      --              for testing or before RESTful services are completed.
      --
      --              This implementation:
      --                  *removed cursor (using FOR XML PATH(''))
      --                  *properly supports NULL vs quoted values
      --                  *supports dates in ISO 8601 - presuming UTC
      --                  *uses Data_Type and Is_Nullable info
      --                  *escapes '\'
      --                  *formats output with tabs/newlines
      --                  *can return final results as XML to bypass
      --                   truncation in SSMS
      --                  *supports schema (e.g. [dbo].[TableName]
      --                  *includes "recordCount" field
      -- Options:                                                                
      --      @table_name: the table to execute the query                        
      --      @limit: equivalent to "select top N * from table" 
      --      @ssms: flag to use if executing in Sql Server Management Studio
      --             to bypass result truncation limits.
      -- 
      -- Inspired primarily by the 2008 work of Thiago R. Santos which was influenced by Thomas Frank.
      -- Usage: [dbo].[GetJSON] @Table_name = 'MySchema.MyTable', @limit = 50, @ssms = 0
      
      create procedure [dbo].[GetJSON] (
          @table_name varchar(max), 
          @limit int = null,
          @ssms bit = 0
      )
      as
      begin
              declare @json varchar(max), @query varchar(max), @table_schema varchar(max) = null
      if( charindex('.', @table_name) > 0 )
      begin
          set @table_schema = replace(replace( substring(@table_name, 0, charindex('.',@table_name)), '[', ''), ']', '')
          set @table_name = replace(replace( substring(@table_name, charindex('.',@table_name) + 1,len(@table_name)), '[', ''), ']', '')
      end
      
      set @query = 
          'select ' + case when @limit is not null then 'top ' + cast(@limit as varchar(32)) + ' ' else '' end + '''{ '' + REVERSE(STUFF(REVERSE(''' +
          CAST((SELECT ' "' + column_name + '" : ' + 
              case when is_nullable = 'YES' 
                  then ''' + case when [' + column_name + '] is null then ''null'' else ' + 
                      case when data_type like '%char%' or data_type like '%text%' then '''"'' + ' else '' end + 
                      case when data_type like '%date%' then 'convert(varchar(23),[' + column_name + '], 126) + ''Z''' else 
                      'replace(replace(replace(replace(cast([' + column_name + '] as varchar(max)),''\'',''\\''),''"'',''\"''),char(10),''\n''),char(13),''\n'') ' end + 
                      case when data_type like '%char%' or data_type like '%text%' then '+ ''"''' else '' end + ' end + ''' 
                  else 
                      case when data_type like '%char%' or data_type like '%text%' then '"' else '' end + 
                      ''' + ' +
                      case when data_type like '%date%' then 'convert(varchar(23),[' + column_name + '], 126) + ''Z' else 
                      'replace(replace(replace(replace(cast([' + column_name + '] as varchar(max)),''\'',''\\''),''"'',''\"''),char(10),''\n''),char(13),''\n'') + ''' end +
                      case when data_type like '%char%' or data_type like '%text%' then '"' else '' end end + ',' AS [text()] 
                      from information_schema.columns where table_name = @table_name and (@table_schema is null or table_schema = @table_schema) FOR XML PATH('') ) as varchar(max)) +
                      '''),1,1,'''')) + '' }'' as json into tmpJsonTable from ' + @table_name + ' with(nolock) '
      exec sp_sqlexec @query
      
      set @json = 
          '{' + char(10) + char(9) +
          '"recordCount" : ' + Cast((select count(*) from tmpJsonTable) as varchar(32)) + ',' + char(10) + char(9) +
          '"records" : ' + char(10) + char(9) + char(9) + '[' + char(10)
          + REVERSE(STUFF(REVERSE(CAST((SELECT char(9) + char(9) + json + ',' + char(10) AS [text()] FROM tmpJsonTable FOR XML PATH('')) AS varchar(max))),1,2,''))
          + char(10) + char(9) + char(9) + ']' + char(10) + '}'
      
      drop table tmpJsonTable
      if( @ssms = 1 and len(@json) > 65535 ) --deal with Sql Server Management Studio text/grid truncation
          select cast('<json><![CDATA[' + @json + ']]></json>' as xml) as jsonString
      else
          select @json as jsonString
      end
      

      【讨论】:

        【解决方案4】:

        jlech 的答案还可以,但我不明白为什么不能使用类似于 UNPIVOT answer 中的技术直接从 VIEW 的元数据中生成,避免使用 CURSOR 和 SELECT INTO 临时表。

        【讨论】:

          【解决方案5】:

          不要破坏 OP 的问题,但我想知道在 SQL 中执行此操作是否是最佳/最合适的路线?在我看来,这可能更容易/更有效地在代码中完成。

          我最初也想知道同样的事情(这就是我找到这篇文章的方式),但在考虑了几分钟后,似乎使用采用数据集的实用程序/扩展方法可能会更好地完成 &返回结果 JSON 字符串。

          诚然,OP 可能有充分的理由需要走这条路。我只是在这里大声思考(打字)......

          【讨论】:

            猜你喜欢
            • 2021-09-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多