在 .NET Core 中运行多个 sql 查询以获取矩阵结果

Posted

技术标签:

【中文标题】在 .NET Core 中运行多个 sql 查询以获取矩阵结果【英文标题】:Running multiple sql queries to get matrix results in .NET Core 【发布时间】:2020-10-19 11:20:42 【问题描述】:

我正在尝试从数据库中获取结果以生成某种矩阵结果以发送回前端。关键是我有 X 轴和 Y 轴的百分位值,我将其分成 10 个部分以获得 10x10 表。为了获得每个值,我计算不同的用户 ID,所以它类似于 1-1、1-2 ... 10-10。

这是我目前想要改进的代码(虽然尚未完成,只是我目前的想法),因为一个接一个地运行 100 个查询似乎不是一个好的解决方案。但是,我有点卡住如何使性能更好,以及是否应该在长度为 100 的字典或多维矩阵数组中返回结果以使其成为良好的实践代码。提前感谢任何人的提示,我的代码如下:

public async Task GenerateMatrix(List<double> x, string xAxis, List<double> y, string yAxis, Parameters parameters)
        
            IDictionary<string, string> xDict = GenerateRanges(x, parameters.XAxis);
            IDictionary<string, string> yDict = GenerateRanges(y, parameters.YAxis);
            
            var innerJoin = GenerateInnerJoin(parameters);
            var whereClauses = GenerateWhereClause(parameters);
            
            var sql = $@"SELECT COUNT(DISTINCT [dbo].[nameof(Table)].[nameof(Table.UserId)]) FROM [dbo].[nameof(Table)] innerJoin ";
            if (whereClauses.Any())
            
                sql += " WHERE " + string.Join(" AND ", whereClauses);
            
            
            for (int i = 0; i < x.Count; i++)
            
                var queryToExecute = "";
                for (int j = 0; j < y.Count; j++)
                
                    queryToExecute = sql + " AND " + xDict.Values.ElementAt(i) + " AND " + yDict.Values.ElementAt(j);
                    var userCount = await Store().QueryScalar<int>(queryToExecute);
                
            
            
            return null;
        

        private IDictionary<string, string> GenerateRanges(List<double> axis, string columnTitle)
        
            IDictionary<string, string> d = new Dictionary<string, string>();
            for (int i = 0; i < axis.Count; i++)
            
                var rangeSql = $@" [dbo].[nameof(Table)].[columnTitle]";
                if (i == 0)
                
                    d.Add(axis[i].ToString(), rangeSql + " < " + axis[i]);
                
                else if (i == axis.Count - 1)
                
                    d.Add(axis[i] + "+", rangeSql + " > " + axis[i]);
                
                else
                
                    d.Add(axis[i-1] + "-" + axis[i], rangeSql + " > " + axis[i-1] + " AND " + rangeSql + " < " + axis[i]);
                
            
            return d;
        

sql 看起来像这样:

SELECT 
    COUNT(DISTINCT [dbo].[Table].[UserId]) 
FROM [Table] 
WHERE  Table.[ClientId] = '2' 
    AND  [dbo].[Table].[ProbabilityAlive] < 0.1 
    AND  [dbo].[Table].[SpendAverage] < 24.86

所以会有 10000 行这样的行。 ProbabilityAliveSpendAverage 是来自前端的列标题,可能还有其他列标题。 对于这两列,我计算百分位值,然后我将其分成十部分,一个是 X 轴,另一个是 Y 轴。然后我使用上面的 sql 查询来获取每个矩阵值的值,因为矩阵是 10x10,所以它变成了 100 个查询。

因此,我想获得 100 个整数值,我仍在试图弄清楚是否最好将数据放入字典中,然后将具有范围 xy 和值的键作为选择结果(例如 "0-1", 5472"),或者是否把它放在多维数组或其他东西中。我有xDict,其中包含范围作为键,例如“0-1”,然后是 sql 语句 ProbabilityAlive > 0 AND ProbabilityALive yDict 为 Y 轴添加相同的值。然后我有两个列表 xy 包含 10 个用于这些范围的双精度值

【问题讨论】:

这是一个 100% 的 SQL 问题,但缺少实际的 SQL 查询。用样本数据和结果解释你真正想做的事情。也许您所需要的只是GROUP BY 子句中的WITH ROLLUP 表达式 是的@AndrewMorton 您尚未解释数据的外观或您的期望。该代码根本没有帮助。只有第一段和查询是相关的,但它们似乎不相关。什么百分位? T-SQL 具有像PERCENTILE_DISC 这样的百分位函数,可用于连续返回各种百分位。您可以创建一个返回 100 行的查询,其中包含您想要的 X、Y 和百分位数数据,但是您想要什么 do? X 和 Y 值从何而来? 您是否尝试为ProbabilityAliveProbabilityAlive 字段生成存储桶并为每个组合生成唯一客户的百分位数(或百分比?)? 并非如此。你描述的是代码,而不是你真正想要得到的输出,数据是什么样的,以及期望的输出是什么 【参考方案1】:

您似乎想要计算 ProbabilityAliveSpendAverage 的特定范围内的用户数。

首先,您需要生成范围组合。在 SQL 中生成组合的简单方法是连接两个表或一组值。

如果您有两个表,其范围值如下:

create table  ProbabilityRanges
(
    LowBound decimal(3,2), UpperBound(3,2)
) 

create table SpendRanges
(
    LowBound decimal(3,2), UpperBound(3,2)
) 

您可以使用交叉连接来生成所有组合:

SELECT 
    SpendRanges.LowBound as SLow,
    SpendRanges.UpperBound as SUpper,
    ProbabilityRangers.LowBound as PLow, 
    ProbabilityRanges.UpperBound as PUpper
FROM ProbabilityRanges CROSS JOIN SpeedRanges

您可以使用这些组合来过滤和计算另一个表中在这些范围内的行:

SELECT 
    SpendRanges.LowBound as SpendValue,
    SpendRanges.LowBound as ProbabilityValue, 
    Count(DISTINCT UserID) as Count
FROM SomeTable CROSS JOIN ProbabilityRanges CROSS JOIN SpeedRanges
Where 
    SomeTable.ClientID=2 
    AND SomeTable.SpendAverage >=SpeedRanges.LowBound 
        AND SpendAverage < SpeedRanges.UpperBound
    AND SomeTable.ProbabilityAlive >= ProbabilityRangers.LowBound 
        AND   SomeTable.ProbabilityAlive < ProbabilityRanges.UpperBound
GROUP BY SpendRanges.LowBound,SpendRanges.LowBound

可以为特定数量的箱动态创建边界,例如使用数字表。你必须提供更多关于你真正想要的信息

【讨论】:

【参考方案2】:

只有两个维度,最容易做和维护,就是制作一个 TSQL 存储过程,输出你想要的元组(默认输出)。 将您从前端获得的输入作为参数传入。

如果您通过返回 JSON(或 XML)的 Web 服务 HTTP GET 获得该功能会怎样? 改用 TSQL 模拟它。

由于您可以直接访问 SQL Server,因此您调用“get”类型的存储过程并传递参数,并获得元组结果。 独立于您的 .Net 核心应用程序,易于编写和测试。也会很快。

type "get" = 只是一个只读 SP,我将我的命名为 USP_GET_method_name。 我还使用 SP 来保存 SQL 端验证,所以我称它们为 USP_PUT_method_name。

干杯

【讨论】:

这不能回答问题。也没有理由创建存储过程 - 它不会更改查询的执行方式或返回的内容。存储过程可用于将复杂代码从应用程序移至查询,但不会改变查询的实际作用 将 HTTP 和 HTTP 动词与数据库混合起来根本没有帮助 我很不同意,TSQL 比在 .Net 中循环更擅长将矩阵式输出直接渲染为元组以供 .Net 使用。命名约定以区分与前端相关的 SP,与纯后端相关的 SP。 FWIW,这与我们对 SSIS(使用 SP)所做的非常相似。 您没有回答问题。您刚刚描述了您的自定义命名约定。 SSIS 与 html 或执行分析查询无关,它是一个 ETL 工具 实际上想发表评论而不是答案,但我还没有足够的声誉

以上是关于在 .NET Core 中运行多个 sql 查询以获取矩阵结果的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET Core,以查询字符串为模板的 Web API RouteAttribute

如何在 asp.net core 中编写一个高性能的 sql 查询应用程序?

通过 ASP.NET Core Web API 使用存储过程从 SQL Server 返回多个行集

在 ASP.NET MVC 中向控制器传递多个参数;此外,在 LINQ-to-SQL 中生成动态查询

编码 ASP.NET Core 和 SQL Server 的问题

OUTPUT INSERTED Id/SCOPE_IDENTITY() 在 C# (ASP.NET Core Razor Pages) SQL 查询中返回 null,在 SQL Server Mana