【问题标题】:How To Find Highest Value In A Row And Return Column Header and it's value如何在一行中找到最高值并返回列标题及其值
【发布时间】:2018-07-29 02:53:58
【问题描述】:

想象一个实体框架数据库中有一行 5 个数值,我将如何检索该行的前 2 列,包括列的名称及其值?最好使用 LINQ。

例如:

a  b  c  d  e
0  4  5  9  2

前 2 个值是 9 和 5。我想检索值和列名 c 和 d。

一个更实际的例子:

var row = table.Where(model => model.Title.Contains(a.Title));

这一行将给我一个包含许多数值的单行。 我想要以下内容,

row.list().OrderByDescendingOrder().top(2);

【问题讨论】:

  • 用您正在使用的数据库标记您的问题。

标签: c# sql database entity-framework linq


【解决方案1】:

我不知道你是如何在 linq 中做到这一点的,但这里有一个 SQL Server 查询:

select t.*, v2.*
from t cross apply
     (values ('a', a), ('b', b), ('c', c), ('d', d), ('e', e)
     ) v(col, val) cross apply
     (select max(case when seqnum = 1 then val end) as val1,
             max(case when seqnum = 1 then col end) as col1,
             max(case when seqnum = 2 then val end) as val2,
             max(case when seqnum = 3 then col end) as col2
      from (select v.*, row_number() over (order by val desc) as seqnum
            from v
           ) v
     ) v2;

编辑:

当然,你可以用大量的case 表达式来做到这一点,以获得最大值:

select t.*,
       (case when a >= b and a >= c and a >= d and a >= e then a
             when b >= c and b >= d and b >= e then b
             when c >= d and c >= e then c
             when d >= e then d
             else e
        end) as max_value,
       (case when a >= b and a >= c and a >= d and a >= e then 'a'
             when b >= c and b >= d and b >= e then 'b'
             when c >= d and c >= e then 'c'
             when d >= e then 'd'
             else 'e'
        end) as max_value_col          
from t;

问题在于将其扩展到 second 值,尤其是在存在重复值的情况下。

【讨论】:

  • 您好,谢谢您的建议。我试图应用这个查询但没有运气。难道没有一种更简单的方法可以从本质上检索具有最高值的列吗?
  • @Darius 。 . .查询的哪一部分导致了问题?
【解决方案2】:

看起来您想要pivot 这个数据,但使用的是 Linq 而不是 T-SQL。 (或其他一些 SQL 方言)

执行此操作的基本模式是使用SelectMany 将每一行转换为 一组键/值对,您可以在其上执行OrderByDescending

一个有点通用的模式如下:

// The values that we want to query.
// In your case, it's essentially the table that you're querying.
// I used an anonymous class for brevity.
var values = new[] {
    new { key = 99, a = 0, b = 4, c = 5, d = 9, e = 2 },
    new { key = 100, a = 0, b = 5, c = 3, d = 2, e = 10 }
};

// The query. I prefer to use the linq query syntax
// for actual SQL queries, but you should be able to translate
// this to the lambda format fairly easily.
var query = (from v in values
            // Transform each value in the object/row
            // to a name/value pair We include the key so that we
            // can distinguish different rows.
            // Because we need this query to be translated to SQL,
            // we have to use an anonymous class.
            from column in new[] { 
                new { key = v.key, name = "a", value= v.a },
                new { key = v.key, name = "b", value= v.b },
                new { key = v.key, name = "c", value= v.c },
                new { key = v.key, name = "d", value= v.d },
                new { key = v.key, name = "e", value= v.e }
            }

            // Group the same row values together
            group column by column.key into g

            // Inner select to grab the top two values from
            // each row
            let top2 = (
                from value in g
                orderby value.value descending
                select value
            ).Take(2)

            // Grab the results from the inner select
            // as a single-dimensional array
            from topValue in top2
            select topValue);

// Collapse the query to actual values.
var results = query.ToArray();

foreach(var value in results) {
    Console.WriteLine("Key: {0}, Name: {1}, Value: {2}", 
        value.key, 
        value.name, 
        value.value);
}

但是,由于您只有一行,因此逻辑变得更加简单:

// The value that was queried
var value = new { key = 99, a = 0, b = 4, c = 5, d = 9, e = 2 };

// Build a list of columns and their corresponding values.
// You could even use reflection to build this list.
// Additionally, you could use C# 7 tuples if you prefer.
var columns = new[] { 
    new { name = "a", value = value.a },
    new { name = "b", value = value.b },
    new { name = "c", value = value.c },
    new { name = "d", value = value.d },
    new { name = "e", value = value.e }
};

// Order the list by value descending, and take the first 2.
var top2 = columns.OrderByDescending(v => v.value).Take(2).ToArray();

foreach(var result in top2) {
    Console.WriteLine("Column: {0}, Value: {1}", result.name, result.value);
}

【讨论】:

  • 我想我可能在过去 10 个小时里一直坐在同一个位置试图解决这个问题,现在我应用了你的建议,我相信你已经解决了。非常感谢!
  • 将其标记为答案!
【解决方案3】:

所以您有一个项目集合,可以根据其中一个属性对其进行排序,并且您希望集合中的两个项目具有该排序属性的最大值?

var result = myItems
    .OrderByDescending(myItem => myItem.MyProperty)
    .Take(2);

一句话:按照 MyProperty 的降序对整个集合进行排序,并从结果中取出前两项,这将是 MyProperty 值最大的两项。

这将返回两个完整的 myItem 对象。通常,将比您实际计划使用的更多属性从对象传输到本地内存并不是一个好主意。使用 Select 确保只传输您计划使用的值:

var bestSellingProducts = products
    .OrderByDescending(product=> product.Orders.Count())
    .Select(product => new
    {   // select only the properties you plan to use, for instance
        Id = product.Id,
        Name = product.Name,
        Stock = product.Stock
        Price = product.Price,
    });
    .Take(2);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-12
    • 1970-01-01
    • 2014-10-29
    • 2021-03-22
    • 1970-01-01
    • 1970-01-01
    • 2018-11-25
    相关资源
    最近更新 更多