【问题标题】:SQL returning incorrect amount of rowsSQL 返回不正确的行数
【发布时间】:2018-05-11 08:20:08
【问题描述】:

我正在尝试使用 SQL 命令并使用数据读取器从我的 MS Access 数据库中获取 2 行数据,但它只返回一行数据。我不完全知道数据读取器是如何工作的,所以我认为这可能是我用它错误编码的东西。 SQL 命令应该没问题,因为当我在 MS Access Query 中运行它时它可以工作。你知道我的代码有什么问题吗? [编辑:我实际上并没有尝试获取行数,这只是为了测试。在我贴的代码 sn-p 下面,我的程序实际上将数据加载到一个数组中,以便可以比较两个整数并选择最小的一个。]

if (passageID != 1)
        {
            Connect(fileName);

            OleDbCommand com = new OleDbCommand();
            com.Connection = cxn;
            com.CommandText = "SELECT PO.OptionID_FK FROM PassageOption AS PO WHERE PO.PassageID_FK = @passageID;";
            com.Parameters.AddWithValue("@passageID", passageID);


            OleDbDataReader r = com.ExecuteReader();

            int numRows = r.RowCount;

            if (r.HasRows)
            {
                int i = 0;
                int[] optionIDs = new int[2];

                while (r.Read())
                {
                    optionIDs[i] = (int)r[i]; // It gives me the following error, the second time it runs, when i = 1; System.IndexOutOfRangeException: 'Index was outside the bounds of the array.'
                    i++;
                }

                if (optionIDs[0] < optionIDs[1])
                {
                    j = optionIDs[0];
                }
                else
                {
                    j = optionIDs[1];
                }
            }
        }

【问题讨论】:

  • 您正在查看“FieldCount”。您需要行数。
  • 另外:将数据读取器放入using块会导致连接池泄漏。
  • ...请记住,没有行计数属性,因为这可能是一项昂贵的操作,因为它需要您迭代整个结果集。您真的需要获取行数,还是只是将其用于测试? (如果需要计数,最好使用SELECT COUNT... 查询...)
  • @UweKeim:我认为这取决于具体情况。如果 OP 确定只会返回 2 条记录,则循环遍历记录不太可能成为问题,并且可能不会比对计数的查询慢,然后是所需的查询。如果有可能返回数百万条记录 - 那将是另一回事。
  • @UweKeim 我实际上正在使用计数,仅用于测试目的。我需要在下面的代码中恢复的数据本身。我应该将其添加到代码 sn-p 中吗?

标签: c# sql oledbdatareader


【解决方案1】:

数据读取器在读取来自数据库的基础流中的所有数据之前,不知道您的选择查询将返回多少行。

FieldCount 属性返回查询中的字段数,它正好是您当前查询的一个。

要知道你需要一一阅读或使用数据表的行

int numRows = 0;
while(r.Read())
{
    // do your task with the current IDataRecord
    numRows++;
}

Console.WriteLine($"There are {numRows} rows");

或者填充一个DataTable

DataTable dt = new DataTable();
dt.Load(com.ExecuteReader());
Console.WriteLine($"There are {dt.Rows.Count} rows");

如果您打算使用返回的数据(在 reader 数组或 table rows 数组中),上述两种方法很有用,但如果您只想知道存在多少行,那么它会更好(尽管只有返回两行)以将您的查询更改为:

com.CommandText = @"SELECT COUNT(*) FROM PassageOption AS PO 
                    WHERE PO.PassageID_FK = @passageID;";
com.Parameters.AddWithValue("@passageID", passageID);
int numRows = (int)com.ExecuteScalar();

当你想要一行一个字段时不需要阅读器,只需 ExecuteScalar

编辑以更新您的上次编辑

此行失败

optionIDs[i] = (int)r[i]; 

因为您的查询中只有一个字段。索引器 i 应仅用于引用 optionIDs 数组,而不是从读取器中提取位置 1 的字段。位置1没有字段,直接用

optionIDs[i] = (int)r[0]; 

每次读取调用

【讨论】:

  • 您使用 foreach(DataRow row in dt.Rows) 遍历 DataTable.Rows,然后使用 Convert.ToInt32(row[0] 获取单个字段) 有很多方法可以做到这一点,但这是另一个问题的材料
  • 但是,填充数据表的操作使用相同的 OleDbDataReader。这对于只有两条记录和一个本地数据库(如 Access)是没有影响的,但如果用于大型结果集,这可能会影响性能。本质上,当在数据表上填充然后循环时,您在数据上循环了两次。更喜欢使用读取方法来提高性能或使用 ORM 来进一步简化事情
【解决方案2】:
int numRows = r.FieldCount;

FieldCount 属性获取行中的列数而不是记录数。

您从表中仅选择 OptionID_FK 单个列。 FieldCount 会告诉你 1。

没有。行数

OleDbDataReader r = com.ExecuteReader();
int rowCount = 0;
if (r.HasRows)  
{  
    while (r.Read())  
    {  
       rowCount++;     
    }  
}
r.Close(); 

【讨论】:

  • 或者干脆SELECT COUNT(*) FROM
  • 是的,这是可能的。你是对的。我试图只在他的问题细节中给出解决方案。 :)
【解决方案3】:

您的数据阅读器中只有一列,即您选择的列PO.OptionID_FK。因此,在您的循环中,当 i 为 1 时:

optionIDs[i] = (int)r[i]; // It gives me the following error, the second time it runs, when i = 1; System.IndexOutOfRangeException: 'Index was outside the bounds of the array.'

...您正在尝试从数据读取器 (r[i]) 中选择第二个 ,但该列不存在。

DataReader 的工作方式是,每当您执行r.read 时,您都会移动到下一行,并且您的r“数组”变量会使用新行中的所有列值进行刷新。数组索引r[n] 选择阅读器的第n 个,而不是第n 个。所以你应该使用:

optionIDs[i] = (int)r[0];

...这会将您的 optionIDs 值设置为 DataReader 当前行的第一(第零)列的值。

【讨论】:

  • 您好,我设法通过将 optionID 转换为将列名传递给读者的列表自行解决了这个问题,我该如何在帖子中说明这一点。抱歉,我是该网站的新手。
猜你喜欢
  • 1970-01-01
  • 2014-12-15
  • 1970-01-01
  • 1970-01-01
  • 2014-01-01
  • 2020-02-16
  • 1970-01-01
  • 2021-07-28
  • 1970-01-01
相关资源
最近更新 更多