我有一个表(ex的订单),它有多列。
\\ \b \c
现在我可以编写三个不同的查询来获取不同的值
products categories subcategories
--------------------------------------
prod1 cat1 sub1
prod1 cat2 sub2
prod2 cat3 sub6
prod1 cat1 sub1
prod5 cat2 sub8
prod2 cat1 sub1
prod1 cat7 sub3
prod8 cat2 sub2
prod2 cat3 sub1
同样我可以为别人写。
现在我需要在单个查询中获取每个列的不同值,结果需要看起来像
var prod = (from p in _context.orders select p.products).ToList().Distinct();
我的独特字段的ClassType如下所示
products categories subcategories
--------------------------------------
prod1 cat1 sub1
prod2 cat2 sub2
prod5 cat3 sub6
prod8 cat7 sub8
sub3
不确定如何以有效的方式执行此操作,以便我不必编写三种方法。该表位于数据库中(因此需要优化)
谢谢!
答案 0 :(得分:5)
使用Linq是绝对不可改变的要求吗?为什么需要在单个查询中返回它?
建议:使用SQL。 可以在一个查询中完成,但您不喜欢该查询。我假设使用SQL Server(对于其他DBMS可以采用不同的方式)。
WITH V AS (
SELECT DISTINCT
V.*
FROM
Orders O
CROSS APPLY (
VALUES (1, O.Products), (2, O.Categories), (3, O.Subcategories)
) V (Which, Value)
),
Nums AS (
SELECT
Num = Row_Number() OVER (PARTITION BY V.Which ORDER BY V.Value),
V.Which,
V.Value
FROM
V
)
SELECT
Products = P.[1],
Categories = P.[2],
Subcategories = P.[3]
FROM
Nums N
PIVOT (Max(N.Value) FOR N.Which IN ([1], [2], [3])) P
;
输出:
Products Categories Subcategories
-------- ---------- -------------
prod1 cat1 sub1
prod2 cat2 sub2
prod5 cat3 sub3
prod8 cat7 sub6
null null sub8
如果您受到约束并决定使用Linq,那么我无法帮助您使用查询式语法。我只知道C#代码风格的语法,但这里就是这样。不幸的是,我不认为这会对你有任何好处,因为我不得不使用一些非常时髦的东西来使它工作。它使用的技术与上面的SQL查询基本相同,只是在Linq中没有PIVOT
的等价物,除了自定义类之外,没有真正的自然行对象。
using System;
using System.Collections.Generic;
using System.Linq;
public class Program {
public static void Main() {
var data = new List<Order> {
new Order("prod1", "cat1", "sub1"),
new Order("prod1", "cat2", "sub2"),
new Order("prod2", "cat3", "sub6"),
new Order("prod1", "cat1", "sub1"),
new Order("prod5", "cat2", "sub8"),
new Order("prod2", "cat1", "sub1"),
new Order("prod1", "cat7", "sub3"),
new Order("prod8", "cat2", "sub2"),
new Order("prod2", "cat3", "sub1")
};
int max = 0;
var items = data
.SelectMany(o => new List<KeyValuePair<int, string>> {
new KeyValuePair<int, string>(1, o.Products),
new KeyValuePair<int, string>(2, o.Categories),
new KeyValuePair<int, string>(3, o.Subcategories)
})
.Distinct()
.GroupBy(d => d.Key)
.Select(g => {
var l = g.Select(d => d.Value).ToList();
max = Math.Max(max, l.Count);
return l;
})
.ToList();
Enumerable
.Range(0, max)
.Select(i => new {
p = items[0].ItemAtOrDefault(i, null),
c = items[1].ItemAtOrDefault(i, null),
s = items[2].ItemAtOrDefault(i, null)
})
.ToList()
.ForEach(row => Console.WriteLine($"p: {row.p}, c: {row.c}, s: {row.s}"));
}
}
public static class ListExtensions {
public static T ItemAtOrDefault<T>(this List<T> list, int index, T defaultValue)
=> index >= list.Count ? defaultValue : list[index];
}
public class Order {
public Order(string products, string categories, string subcategories) {
Products = products;
Categories = categories;
Subcategories = subcategories;
}
public string Products { get; set; }
public string Categories { get; set; }
public string Subcategories { get; set; }
}
我想我们可以交换这个
.Select(i => new {
p = items[0].ItemAtOrDefault(i, null),
c = items[1].ItemAtOrDefault(i, null),
s = items[2].ItemAtOrDefault(i, null)
})
为此:
.Select(i => new Order(
items[0].ItemAtOrDefault(i, null),
items[1].ItemAtOrDefault(i, null),
items[2].ItemAtOrDefault(i, null)
))
然后在输出部分使用该类的属性。
答案 1 :(得分:0)
据我所知,您将无法在单个查询中执行此操作。在考虑如何使用C#进行思考之前,请考虑如何在SQL中执行此操作;我可能错了,但对我来说,无论如何你都会写3个查询。
如果您发现一些性能问题,这是您的实际代码:
var prod = (from p in _context.orders select p.products).ToList().Distinct();
您可能希望首先删除.ToList()
扩展方法beacuse,将所有记录检索到内存,然后才应用区别。
那是因为您的查询表达式(from p in ...
)返回IQueryable
并且在其上调用.ToList()
使其成为强制当前形成运行SQL查询并将结果带入内存。IEnumerable
。
这种情况的区别在于:延期执行
请参阅:https://www.c-sharpcorner.com/UploadFile/rahul4_saxena/ienumerable-vs-iqueryable/