Я привык (из Ады с использованием libpq) к

  • открыть курсор

  • получить некоторые ключевые ценности

  • используйте эти ключевые значения в качестве параметров привязки для других операторов.

Но вместо этого я получаю исключение Npgsql.NpgsqlOperationInProgressException.

Однажды я получил эту работу с sql-сервером, но решил это, добавив '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();

Да, я мог бы прочитать первый оператор в списке и перебрать его, но у меня есть довольно старый код, созданный, как указано выше.

/ Бьорн

1
bnl 22 Окт 2018 в 23:46

2 ответа

Лучший ответ

Проблема в том, что 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 #. Это будет намного удобнее для базы данных, а для больших наборов данных должно быть немного быстрее.

0
Hambone 23 Окт 2018 в 20:57
52937540