从 DataReader 列中查找最长的字符串

Posted

技术标签:

【中文标题】从 DataReader 列中查找最长的字符串【英文标题】:Find longest string from DataReader column 【发布时间】:2019-07-18 12:43:31 【问题描述】:

是否可以创建一个 Linq 来检索 DataReader 列的最长字符串值?列数据应转换为字符串,然后返回最长的字符串。

到目前为止,我所知道的是如何使用可枚举的 DataTable 获得相同的东西(正如我所问的 here),例如:

string maxString = dt
  .AsEnumerable()
  .Select(row => row[mycolumn].ToString())
  .OrderByDescending(st => st.Length)
  .FirstOrDefault();

我尝试过像这样组合 DataReader 的上层解决方案:

var enumerable = reader
  .Cast<IDataRecord>();

string max_string = enumerable
  .Select(record => record.GetName(col).ToString())
  .Aggregate((s, a) => a.Length > s.Length ? a : s);

不幸的是,这不起作用,我明白了

序列不包含 at 中的元素 System.Linq.Enumerable.Aggregate

错误。提前感谢您的帮助:)

编辑:我正在寻找一种解决方案,无需直接从 DataReader 对象将数据加载到 Datatable 等中。我试图避免“内存不足异常”,因为数据很大。

Power Mouse 建议的最新尝试(它返回正确的值,但仅来自第 1 列):

     for (int col = 0; col < reader.FieldCount; col++)
     
         string col_name = reader.GetName(col).ToString();
         var enumerable = reader.Cast<IDataRecord>();

         string max_string = enumerable.Where(x => enumerable.Max(y => y[col_name].ToString()
                             .Length) == x[col_name].ToString().Length)
                             .FirstOrDefault()?[col_name].ToString();

         Console.WriteLine("max string of column is : " + max_string);
      

【问题讨论】:

Sequence contains no elements 这意味着什么?另见***.com/questions/8867867/…。 这似乎应该在源头完成,即select top 1 [SomeColumn] from [SomeTable]order by len([SomeColumn]) desc ? @Marc Gravell,我将这个选项留给场景如果我没有找到 Linq 的解决方案,因为 DataReader 读取的查询不是那么小,所以使用“order by”进行计算需要很多时间,恕我直言。 @Lucy82 如果查询不是那么小,那就更有理由在源头执行它并且只通过网络带回一行,而不是带回 tons网络上的数据只是为了丢弃除一行之外的所有数据 我认为如果你使用sql查询得到你想要的结果会更好 【参考方案1】:

所以根据您的原始要求:当您使用 DataReader 时,您需要在特定列中找到最长的文本。 请查看示例

string storedString = String.Empty;
    SqlConnection connection = new SqlConnection(this.Connection.ConnectionString);
    using (connection)
    
        string SQLcommand = "select * FROM (VALUES(1, 'xxx' ), (2, 'really long string xxxxxx'), (3, 'short string'), (4, 'another string')) t (id, fName)";
        SqlCommand command = new SqlCommand(SQLcommand, connection);
        connection.Open();
        SqlDataReader reader = command.ExecuteReader();
        while (reader.Read())
        
            storedString = reader.Cast<IDataRecord>()
                            .Where(w=> w.GetOrdinal("fName").ToString().Length == reader.Cast<IDataRecord>()
                                                                                        .Max(m => m.GetOrdinal("fName")
                                                                                        .ToString().Length))
                            .Select(s=> s.GetString(1))
                            .FirstOrDefault();
        


    
    Console.WriteLine($"The longest string: storedString. charcount= storedString.Length");

结果将是: 最长字符串:真长字符串xxxxxx。字符数= 25

正如您所解释的,您需要检查多个列:

string storedNameString = String.Empty;
    string storedName2String = String.Empty;
    SqlConnection connection = new SqlConnection(this.Connection.ConnectionString);
    using (connection)
    
        string SQLcommand = "select * FROM (VALUES(1, 'xxx', 'dddddd' ), (2, 'really long string xxxxxx','dfghdt'), (3, 'short string', 'anothercolumn long string'), (4, 'another string', 'test')) t (id, fName, fName2)";
        SqlCommand command = new SqlCommand(SQLcommand, connection);
        connection.Open();
        SqlDataReader reader = command.ExecuteReader();
        while (reader.Read())
        
            string fName = reader.GetString(reader.GetOrdinal("fName")).ToString();
            if(fName.Length >= storedNameString.Length)
                storedNameString = fName;

            string fName2 = reader.GetString(reader.GetOrdinal("fName2")).ToString();
            if (fName2.Length >= storedName2String.Length)
                storedName2String = fName2;
        
    
    Console.WriteLine($"The longest string: storedNameString. charcount= storedNameString.Length");
    Console.WriteLine($"The longest string: storedName2String. charcount= storedName2String.Length");

【讨论】:

我已将代码配置为与多个数据读取器一起使用,但您的建议不起作用,它会引发异常“无法将“System.DateTime”类型的对象转换为“System.String”类型'”。除此之外,它不处理空值。所以我回到了我开始的地方:( 第二个选项有效,但我想知道 LINQ 是否工作得更快,因为它很慢。【参考方案2】:

我解决了我的问题,不幸的是没有 LINQ。问题在于,使用 DataReader,您不能像使用 DataTable 一旦存储在内存中那样简单地遍历行和列,而是在 reader.Read() 方法运行时必须执行某种相同的逻辑。

所以,我能想到的最好办法是在 .Read() 方法运行时将列索引及其字符串值存储到字典中。

这样做,您必须小心字符串空格和空值。这是我的解决方案,对我来说效果很好:

 Dictionary<int, string> col_values = new Dictionary<int, string>();

 using (OracleDataReader reader = cmd.ExecuteReader())
 
      for (int i = 0; i < reader.FieldCount; i++)
      
          //First add indexes to Dictionary 
          // I add column names here - didn't test for string.Empty !!
          col_values.Add(i, string.Empty);
      

      //Then read row by row and modify Dictionary - If text is larger than string.Empty
      //Dictionary must be .ToArray(), or else you'll have an error for modifying collection
      while (reader.Read())
      
          foreach (var item in col_values.ToArray())
          
             string rdr_text = reader[item.Key].ToString().Trim()??string.Empty;

             if (item.Value.Length<rdr_text.Length)
             
                 col_values[item.Key] = rdr_text;
             
          
      

      foreach (var item in col_values)
      
         //...And here we have all longest strings stored, for each column...Job done
      
 

为了我的目的,这个迭代在 4 分钟内读取了大约 2.3 mio 行和 12 列。它并不快,但至少它有效。如果有人有更好/更快的想法,请提供答案。

【讨论】:

以上是关于从 DataReader 列中查找最长的字符串的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 pandas-datareader 从 Yahoo 查找任何索引

从 DataReader 检索 SqlGeography 类型时如何解决 InvalidCastException?

将最长字段放在dataframe列中

如果列中的前一个单元格为空,DataReader 不会在 Excel 单元格中看到数据

如何使用Java中的给定字符串值从数组列表中查找最长前缀?

无效的 XML 字符错误 - 如何从 VARCHAR2 数据库列中查找无效字符?