2

我有一个来自非常复杂的 SQL 查询的大型结果集。在这些值中,一个string代表一个位置(稍后将帮助我确定该值来自的页面位置),一个int是根据该行中的其他值为每一行计算的优先级编号,另一个string包含一个值我必须记住以后展示。

问题是 sql 查询非常复杂(它有 UNIONS、JOINS 和带有别名的复杂计算),以至于我无法在逻辑上将其他任何东西放入其中,而不会弄乱它的工作方式。

我只想说,在完成查询并执行计算之后,我需要一些聚合函数可能会解决的问题,但这不是一个选项,因为所有列都不是来自其他聚合函数。

几天来我一直在思考如何遍历结果,将一对值存储在一个列表中(或两个单独的列表以某种方式捆绑在一起),其中一个值是每个位置的所有优先级值的总和并且另一个值是一个不同的位置值(即,当结果循环通过时,它不会创建另一个具有以前使用过的位置值的列表项,但是,它仍然需要所有其他的总和来自相同位置的优先级值)。此外,结果需要按优先级以降序排列(因此使用两个列表存在问题)。

例子:

编辑:我忘了,保留的值应该是 sql 查询中具有最高优先级的行中的值。

如果我有以下结果:

  location                      priority                               value  

--------------------------------------------------------------------------------
   page1                           1                                  some text!
   page2                           3                                  more text!
   page2                           4                               even more text!
   page3                           3                                  text again
   page3                           1                                     text
   page3                           1                              still more text!
   page4                           6                                     text

如果我能够做我想做的事,我将能够在迭代后(并按此顺序)实现类似的目标:

  location                      priority                               value  

--------------------------------------------------------------------------------
   page2                           7                               even more text!
   page4                           6                                    text
   page3                           5                                  text again
   page1                           1                                  some text!

我做了一个又一个的研究,但绝对没有什么能真正接近解决这个困境。

即使是强大的 C# 语言,我所要求的是否也太难了?

我考虑过的事情:

循环遍历 sql 结果并检查每个位置是否有重复,将所有优先级值加在一起,并将这两个加值存储在两个或三个单独的列表中。

为什么我仍然需要帮助

我不能使用 foreach,因为逻辑没有成功,我不能使用for循环,因为我不能访问 IEnumerable (或存储Database.Open.Query()索引返回内容的任何类型。(这是有道理的) ,当然)。另外,我需要按优先级排序,但不能让一个列表与其他列表不同步。


使用 LINQ 选择和存储我需要的内容

为什么我仍然需要帮助

我不知道 LINQ(根本不知道!)主要是因为我不懂 lambda 表达式(不管我读了多少)。


使用实例化的类来存储名称/值对

为什么我仍然需要帮助

我不仅希望对这类事情进行排序是不可能的,而且我现在知道如何.cs在我的 C#.net 网页中使用 WebMatrix 环境中的文件,但我主要只使用过静态类,还需要一些进修课程关于构造函数以及如何正确设置它。


不知何故将此功能融入已经相当大且复杂的 SQL 查询中

为什么我仍然需要帮助

虽然这可能是我理想的功能所在,但我再次强调这不是一个选项。我曾尝试使用聚合函数,但只得到一个错误,说明并非所有其他列都来自聚合函数。


根据第一个查询结果集中的值进行另一个查询

为什么我仍然需要帮助

我不能仅根据一列(即位置)选择不同的结果。


假设我可以得到正确的循环逻辑,将值存储在 3 维数组中

为什么我仍然需要帮助

我不能声明数组,因为在需要使用它之前我不知道它的所有维度。

4

2 回答 2

4

你的帖子在很多方面让我感到惊讶,比如说“主要使用静态类”和“期望实例化一个类/对象是不可能的”......你说的真的很奇怪。我只能引用查尔斯·巴贝奇的一句话来回应:

我无法正确理解会引发这样一个问题的那种混乱的想法。

无论如何..正如您所说,您发现 lambdas 很难,让我们以经典的“手动”方式追踪问题。

假设您有一个包含 LOCATIONS 和 PRIORITIES 的 ROWS 列表。

List<DataRow> rows = .... ; // datatable, sqldatareader, whatever

你说你需要:

  • 唯一位置列表
  • 与总结的优先级配对的位置“列表”

让我们从第一个目标开始。

要收集唯一“值”的列表,HashSet 非常完美:

HashSet<string> locations = new HashSet<string>();
foreach(var row in rows)
    locations.Add( (string)rows["LOCATION"] );

好吧,仅此而已。之后,locations哈希集将只记住所有唯一位置。“添加”不会导致重复元素。HashSet 检查并“唯一化”放入其中的所有值。小棘手的事情是哈希集没有[index]运算符。您必须枚举哈希集以获取值:

foreach(string loc in locations)
{
    Console.WriteLine(loc);
}

或将其转换/重写为列表:

List<string> locList = new List<string>(locations);
Console.WriteLine(locList[2]); // of course, assuming there were at least three..

让我们进入第二个目标。

要收集与行为类似“逻辑键”的某些事物相关的值列表,aDictionary<Key,Val>可能很有用。它允许您将“值”与一些“键”存储/关联,即:

Dictionary<string, double> dict = new Dictionary<string, double>();
dict["mamma"] = 123.45;
double d = dict["mamma"]; // d == 123.45

    字典[“妈妈”] += 101; // 可能的!双 e = dict[“妈妈”]; // d == 224.45

但是,当您尝试从未知键中读取时,它会愉快地抛出异常:

Dictionary<string, double> dict = new Dictionary<string, double>();
dict["mamma"] = 123.45;
double d = dict["daddy"]; // throws KeyNotBlarghException

    字典[“爸爸”] += 101; // 也会抛出!尝试读取旧/当前值!

因此,必须非常小心地使用它还不知道的“钥匙”。幸运的是,你总是可以询问字典是否已经知道一个键:

Dictionary<string, double> dict = new Dictionary<string, double>();
dict["mamma"] = 123.45;
bool knowIt = dict.ContainsKey("daddy"); // == false

因此,您可以在未知时轻松检查和初始化:

Dictionary<string, double> dict = new Dictionary<string, double>();
bool knowIt = dict.ContainsKey("daddy"); // == false
if( !knowIt )
    dict["daddy"] = 5;

dict["daddy"] += 101; // now 106

所以..让我们尝试根据位置总结优先级:

Dictionary<string, double> prioSums = new Dictionary<string, double>();
foreach(var row in rows)
{
    string location = (string)rows["LOCATION"];
    double priority  = (double)rows["PRIORITY"];

    if( ! prioSums.ContainsKey(location) )
        // make sure that dictionary knows the location
        prioSums[location] = 0.0;

    prioSums[location] += priority;
}

而且,真的,仅此而已。现在prioSums将知道所有位置和所有优先级总和:

var sss = prioSums["NewYork"];  // 9123, assuming NewYork was some location

但是,必须对所有位置进行硬编码是没有用的。因此,您还可以向字典询问它目前知道哪些键

foreach(string key in prioSums.Keys)
    Console.WriteLine(key);

你可以立即使用它:

foreach(string key in prioSums.Keys)
{
    Console.WriteLine(key);
    Console.WriteLine(prioSums[key]);
}

这应该打印所有位置及其所有总和。

您可能已经注意到一件有趣的事情:字典可以告诉您它记住了哪些键。因此,您不需要第一个目标中的 HashSet。简单地通过总结字典中的优先级,您可以免费获得唯一的位置列表:只需向字典询问它的键。

编辑:

我注意到您还有一些请求(例如降序排序或查找最高优先级值),但我想我现在将它们保留。如果您了解我如何使用字典来收集优先级,那么您将轻松构建一个类似Dictionary<string,string>的来收集位置的最高排名值。并且“降序”非常容易完成,只要你从字典中取出值并将它们排序为一个 ie 列表。所以我现在暂时跳过它。这个文本已经很远了;我认为博士:)

于 2013-07-11T22:17:32.380 回答
2

LINQ 确实是解决此类问题的工具。

假设您有一个变量pages,它是一个IEnumerable<Page>,其中Page是一个具有属性的类,location您可以这样做priorityvalue

var query = from page in pages
    group page by page.location into grp
    select new { location = grp.Key,
                 priority = grp.Sum(page => page.priority),
                 value = grp.OrderByDescending(page => page.priority)
                            .First().value
               }

你说你不懂LINQ,那么让我试着开始解释一下这句话。

这些行是 group by location,这导致 4 组页面,其中page.location是关键:

location  priority  value  
--------------------------------------
page1     1         some text!
page2     3         more text!
          4         even more text!
page3     1         text
          1         still more text!
          3         text again
page4     6         text

循环通过这select4 个组,并为每个组创建一个具有 3 个属性的匿名类型:

  1. location: 组的键
  2. priority: 一组优先级的总和
  3. valuevalue当其页面按优先级降序排序时,一组中的第一个。

Lamba 表达式是一种表达应该将哪个属性用于 LINQ 函数(如Sum. 简而言之,他们说“转换pagepage.priority”:page => page.priority

您希望这些新行按优先级降序排列,所以最后您可以这样做

result = query.OrderByDescending(x => x.priority).ToList();

只是一个任意占位符,表示手头集合中的x一项,query(同样在上面的查询中page可能是任何单词或字符)。

于 2013-07-11T23:10:52.823 回答