FOR JSON路径在AZURE SQL上返回较少的行数

时间:2017-05-13 08:48:22

标签: sql azure-sql-database sql-server-2016

我正在使用AZURE SQL(SQL Server 2016)并创建一个查询来为我提供JSON对象的输出。我在查询结尾处添加了FOR JSON PATH

当我在不向查询添加FOR JSON PATH的情况下执行该过程时,我得到244行(我的表中没有记录);但是当我通过添加FOR JSON PATH来执行该过程时,我得到消息33行,并且我得到了被截断的JSON对象。

我使用不同类型的查询对此进行了测试,包括简单查询仅选择10列,但我总是使用FOR JSON PATH获得较少的行数,并且最后截断JSON对象。

这是我的查询

SELECT 
    [Id]
    ,[countryCode]
    ,[CountryName]
    ,[FIPS]
    ,[ISO1]
    ,[ISO2]
    ,[ISONo]
    ,[capital]
    ,[region]
    ,[currency]
    ,[currencyCode]
    ,[population]
    ,[timeZone]
    ,[timeZoneCode]
    ,[ISDCode]
    ,[currencySymbol]
FROM 
    [dbo].[countryDB]

以上查询返回2行。

我使用以下查询来获取JSON中的输出

SELECT 
    [Id]
    ,[countryCode]
    ,[CountryName]
    ,[FIPS]
    ,[ISO1]
    ,[ISO2]
    ,[ISONo]
    ,[capital]
    ,[region]
    ,[currency]
    ,[currencyCode]
    ,[population]
    ,[timeZone]
    ,[timeZoneCode]
    ,[ISDCode]
    ,[currencySymbol]
FROM 
    [dbo].[countryDB] 
FOR JSON PATH

以上查询返回33行,输出为

[{"Id":1,"countryCode":"AD","CountryName":"Andorra","FIPS":"AN","ISO1":"AD","ISO2":"AND","ISONo":20,"capital":"Andorra la Vella","region":"Europe","currency":"Euro","currencyCode":"EUR","population":67627,"timeZone":2.00,"timeZoneCode":"DST","ISDCode":"+376"},{"Id":2,"countryCode":"AE","CountryName":"United Arab Emirates","FIPS":"AE","ISO1":"AE","ISO2":"ARE","ISONo":784,"capital":"Abu Dhabi","region":"Middle East","currency":"UAE Dirham","currencyCode":"AED","population":2407460,"timeZone":4.00,"timeZoneCode":"STD","ISDCode":"+971"},{"Id":3,"countryCode":"AF","CountryName":"Afghanistan","FIPS":"AF","ISO1":"AF","ISO2":"AFG","ISONo":4,"capital":"Kabul","region":"Asia","currency":"Afghani","currencyCode":"AFA","population":26813057,"timeZone":4.50,"timeZoneCode":"STD","ISDCode":"+93"},{"Id":4,"countryCode":"AG","CountryName":"Antigua and Barbuda","FIPS":"AC","ISO1":"AG","ISO2":"ATG","ISONo":28,"capital":"Saint Johns","region":"Central America and the Caribbean","currency":"East Caribbean Dollar","currencyCode":"205","population":66970,"timeZone":-4.00,"timeZoneCode":"STD","ISDCode":"+1"},{"Id":5,"countryCode":"AI","CountryName":"Anguilla","FIPS":"AV","ISO1":"AI","ISO2":"AIA","ISONo":660,"capital":"The Valley","region":"Central America and the Caribbean","currency":"East Caribbean Dollar","currencyCode":"205","population":12132,"timeZone":-4.00,"timeZoneCode":"STD","ISDCode":"+1"},{"Id":6,"countryCode":"AL","CountryName":"Albania","FIPS":"AL","ISO1":"AL","ISO2":"ALB","ISONo":8,"capital":"Tirana","region":"Europe","currency":"Lek","currencyCode":"ALL","population":3510484,"timeZone":2.00,"timeZoneCode":"DST","ISDCode":"+355"},{"Id":7,"countryCode":"AM","CountryName":"Armenia","FIPS":"AM","ISO1":"AM","ISO2":"ARM","ISONo":51,"capital":"Yerevan","region":"Commonwealth of Independent States","currency":"Armenian Dram","currencyCode":"AMD","population":3336100,"timeZone":5.00,"timeZoneCode":"DST","ISDCode":"+374"},{"Id":8,"countryCode":"AN","CountryName":"Netherlands Antilles","FIPS":"NT","ISO1":"AN","ISO2":

我试图直接在JSON中获取输出

5 个答案:

答案 0 :(得分:9)

当将FOR JSON查询返回给客户端时,JSON文本将作为单列结果集返回。 JSON被分成固定长度的字符串并通过多行发送。

在SSMS中很难看到这一点,因为SSMS在“结果到网格”中连接了你的结果,并截断了“结果到文本”中的每一行。

为什么呢?不知道。我的猜测是只有.NET客户端知道如何有效地从SQL Server读取大流,99%的用户仍然只是缓冲整个对象。在多行上打破JSON为客户端提供了一个简单的API来逐步读取数据。事实上,事实上的标准JSON库不在BCL中,这意味着SqlClient实际上不能拥有一流的JSON API。

无论如何,从C#开始,你可以使用这样的东西来读取结果:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp3
{
    class SqlJSONReader: TextReader
    {
        SqlDataReader rdr;
        string currentLine = "";
        int currentPos = 0;
        public SqlJSONReader(SqlDataReader rdr)
        {
            this.rdr = rdr;
        }
        public override int Peek()
        {
            return GetChar(false);
        }
        public override int Read()
        {
            return GetChar(true);
        }
        public  int GetChar(bool Advance)
        {
            while (currentLine.Length == currentPos)
            {
                if (!rdr.Read())
                {
                    return -1;
                }
                currentLine = rdr.GetString(0);
                currentPos = 0;
            }
            int rv =  (int)currentLine[currentPos];
            if (Advance) currentPos += 1;
            return rv;
        }

        public override void Close()
        {
            rdr.Close();
        }

    }

    class Program
    {

        static void Main(string[] args)
        {
            using (var con = new SqlConnection("server=.;database=master;Integrated Security=true"))
            {
                con.Open();
                var sql = @"
select o.object_id as [obj.Id], replicate('n', 2000) as [obj.foo], c.name as [obj.col.name]
from sys.objects o
join sys.columns c 
  on c.object_id = o.object_id
for json path;
"
;
                var cmd = new SqlCommand(sql, con);
                var sr = new StringBuilder();
                using (var rdr = cmd.ExecuteReader())
                {
                    using (var tr = new SqlJSONReader(rdr))
                    {
                        using (var jr = new Newtonsoft.Json.JsonTextReader(tr))
                        {
                           while (jr.Read())
                            {
                                Console.WriteLine($" {jr.TokenType} : {jr.Value}");
                            }
                        }

                    }

                }
                Console.WriteLine(sr.ToString());
            }



        }
    }
}

答案 1 :(得分:0)

分离关注点表示返回一个字符串并分别解析JSON。下面的代码片段可以在不依赖于JSON.net的情况下使用,它可以单独使用,也可以使用不同的Json Deserializer(例如RestSharp中内置的)并且不需要SqlJSONReader类。

try {
     using (var conn = new SqlConnection(connectionString))
     using (var cmd = new SqlCommand(sql, conn)) {
        await conn.OpenAsync();
        logger.LogInformation("SQL:" + sql);
        var rdr = await cmd.ExecuteReaderAsync().ConfigureAwait(false);
        var result = "";
        var moreRows = rdr.HasRows;
        while (moreRows) {
            moreRows = await rdr.ReadAsync();
            if (moreRows) result += rdr.GetString(0);
        }
        return result;
     }
  }
  catch (Exception ex) {
     //logger.LogError($"Error accessing Db:{ex}");
     return null;
  }

答案 2 :(得分:0)

JSON路径的

sql查询结果是一个长字符串,分为多列或块 像这样的语句:“我想获取json路径的结果”

"i want"+
" to ge"+
"t resu"+
"lt of "+
"for js"+
"on path"

每个块等于sql中列的最大大小 因此,只需将它们全部列出即可

    public IHttpActionResult GetAdvertises()
    {

        var rEQUEST = db.Database.SqlQuery<string>("SELECT 
        ID,CITY_NAME,JSON_QUERY(ALBUM) AS ALBUM FOR JSON PATH").ToList();
        foreach(string req in rEQUEST)
        {
        HttpContext.Current.Response.Write(req);
        }

        return Ok();
    }

答案 3 :(得分:0)

感谢@David Browne。我发现我必须使用“打印”而不是“选择”

declare @json varchar(max) = (SELECT * FROM dbo.AppSettings FOR JSON AUTO)

print @json

答案 4 :(得分:0)

如果您的查询返回的数据多于2033个宪章,则将有行。每行包含2033个宪章数据,另一行包含剩余数据。因此,您需要合并以获取实际的json。如下面的代码示例所示。

dynamic jsonReturned = unitOfWork
        .Database
        .FetchProc<string>("storedProcedureGetSaleData", new { ProductId = productId });

    if (Enumerable.Count(jsonReturned) == 0)
    {
        return null;
    }

    dynamic combinedJson = "";
    foreach (var resultJsonRow in jsonReturned)
    {
        combinedJson += resultJsonRow;
    }

    return combinedJsonResult;