繁体   English   中英

使用Npgsql的多个游标?

[英]multiple cursor using Npgsql?

我习惯了(从Ada使用libpq)到

  • 打开游标

  • 得到一些关键值

  • 将这些键值用作其他语句的绑定参数。

但是我却得到了Npgsql.NpgsqlOperationInProgressException。

我曾经使用sql-server进行此操作,但是通过在连接字符串中添加“ MARS”(多个活动记录集)解决了该问题

我可以在这里做类似的事情吗?

这是我想做的事情:

            conn.Open();

        // Define a query
        NpgsqlCommand cmdGetSelectionIds = new NpgsqlCommand("select distinct(R.SELECTIONID) from ARUNNERS R, AMARKETS M " +
                                              "where true " +
                                              "and M.MARKETID = R.MARKETID " +
                                              "and M.MARKETTYPE = 'WIN' " +
                                              "and R.STATUS <> 'REMOVED'", conn);


        NpgsqlCommand cmdNumWins = new NpgsqlCommand("select count('a') from ARUNNERS R, AMARKETS M " +
                                              "where true " +
                                              "and M.MARKETID = R.MARKETID " +
                                              "and R.SELECTIONID = @selid " +
                                              "and M.MARKETTYPE = 'WIN' " +
                                              "and R.STATUS = 'WINNER'", conn);

        NpgsqlCommand cmdNumPlcs = new NpgsqlCommand("select count('a') from ARUNNERS R, AMARKETS M " +
                                              "where true " +
                                              "and M.MARKETID = R.MARKETID " +
                                              "and R.SELECTIONID = @selid " +
                                              "and M.MARKETTYPE = 'PLACE' " +
                                              "and R.STATUS = 'WINNER'", conn);

        NpgsqlCommand cmdNumLosses = new NpgsqlCommand("select count('a') from ARUNNERS R, AMARKETS M " +
                                              "where true " +
                                              "and M.MARKETID = R.MARKETID " +
                                              "and R.SELECTIONID = @selid " +
                                              "and M.MARKETTYPE = 'WIN' " +
                                              "and R.STATUS = 'LOSER'", conn);

        NpgsqlDataReader drGetSelectionIds = cmdGetSelectionIds.ExecuteReader();

        while (drGetSelectionIds.Read())
        {
            selid = drGetSelectionIds.GetInt32(0);


            cmdNumWins.Parameters.AddWithValue("selid", selid);
            using (NpgsqlDataReader drNumWins = cmdNumWins.ExecuteReader())
            { 
                if (drNumWins.Read()) numWins = drNumWins.GetInt32(0);
            }

            using (NpgsqlDataReader drNumPlcs = cmdNumPlcs.ExecuteReader())
            {
                if (drNumPlcs.Read()) numPlcs = drNumPlcs.GetInt32(0);
            }

            using (NpgsqlDataReader drNumLosses = cmdNumLosses.ExecuteReader()) {
                if (drNumLosses.Read()) numPlcs = drNumLosses.GetInt32(0);
            }

            Console.Write("selid : {0} \t num W {1} \t num P {2} num L {3} \t points {4}\n", selid, numWins, numPlcs, numLosses, (3.0*numWins + numPlcs )/(numWins+numLosses));


        }
        // Close connection
        conn.Close();

是的,我可以将第一条语句读入列表并循环遍历,但是我确实有一些像上面那样构建的旧代码。

/比约恩

问题在于NpgSql只允许一次打开一个数据读取器。 如果您遇到需要同时针对同一连接打开多个数据读取器的情况,那么我认为可能会有更好的方法来达到最终目标。

因此,免责声明...不要这样做。 但是,如果您想做上面描述的事情,这将是实现它的一种方式:

cmdNumWins.Parameters.Add(new NpgsqlParameter("@selid", NpgsqlDbType.Integer));
cmdNumPlcs.Parameters.Add(new NpgsqlParameter("@selid", NpgsqlDbType.Integer));
cmdNumLosses.Parameters.Add(new NpgsqlParameter("@selid", NpgsqlDbType.Integer));

List<int> idList = new List<int>();

using (NpgsqlDataReader drGetSelectionIds = cmdGetSelectionIds.ExecuteReader())
{
    while (drGetSelectionIds.Read())
        idList.Add(drGetSelectionIds.GetInt32(0));

    drGetSelectionIds.Close();
}

foreach (int selid in idList)
{
    cmdNumWins.Parameters[0].Value = selid;
    cmdNumPlcs.Parameters[0].Value = selid;
    cmdNumLosses.Parameters[0].Value = selid;

    numWins = Convert.ToInt32(cmdNumWins.ExecuteScalar());
    numPlcs = Convert.ToInt32(cmdNumPlcs.ExecuteScalar());
    numLosses = Convert.ToInt32(cmdNumLosses.ExecuteScalar());

    Console.Write("selid : {0} \t num W {1} \t num P {2} num L {3} \t points {4}\n", selid, 
        numWins, numPlcs, numLosses, (3.0 * numWins + numPlcs) / (numWins + numLosses));
}

更好的方法是将所有操作作为一个查询来完成:

select
  r.selectionid,
  count (1) filter (where m.markettype = 'WIN' and r.status = 'WINNER') as win,
  count (1) fitler (where m.markettype = 'PLACE' and r.status = 'WINNER') as place,
  count (1) filter (where m.markettype = 'WIN' and r.status = 'LOSER') as lose
from
  arunners r
  join amarkets m on m.marketid = r.marketid
where
  r.status != 'REMOVED'
group by
  r.selectionid

我可能已经错过了一些关于您的逻辑的细微差别,但希望您能理解。 这应该一口气快速有效地完成C#逻辑的工作。 这将对数据库友好得多,对于大型数据集,它应该更快一些。

如上文所述,Npgsql实际上只允许在给定的连接上同时打开一个数据读取器(与MSSQL的MARS功能不同)。 但是,您可以自己手动使用服务器端游标来做一些类似的事情 换句话说,您可以运行一个查询并从其游标中获取X行,然后根据第一个查询的输出执行第二个查询。 您随时可以返回第一个查询,并获取X个以上的行,等等。

换句话说,虽然Npgsql不允许同时有多个阅读器 ,但PostgreSQL确实允许同时有多个查询 (或游标)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM