Даже хороший запрос не смог отловить повторяющиеся строки в Oracle - PullRequest
0 голосов
/ 31 января 2019

Речь идет о проверке повторяющихся строк после вставки.Я знаю, что вы скажете, почему бы не проверить сначала, прежде чем вставлять, но мы не можем сделать это по некоторым причинам.Мы используем Oracle 12c.

При нахождении более чем одной записи (номер транзакции и поставщик уникальны), первая запись с самое раннее время должна быть передана как статус «Успешно», адругие записи с последним временем должны быть отклонены как статус «Дублировать».

См. рисунок ниже.

enter image description here

enter image description here

Этот запрос кажется полезным, но иногда он не находит дубликатстрока.Когда я запускаю консольное приложение (C #) для загрузки 1000 данных, я получаю 2 дубликата из 1000. В производстве у нас получилось менее 15 дубликатов из 50 000. Я знаю, это неплохо, но есть ли способ сделатьлучше, чем этот запрос?ВСЕХ ДУБЛИКОВ ВСЕ!

БД Oracle, похоже, вышла из-под контроля, или я что-то не так с этим запросом?Должны ли мы создать индекс для этого запроса?Любой совет?

function checkDuplicate(i_vendor varchar2,i_transactionnumber varchar2, i_txId 
raw) return number 
is
    transactionId raw(16);
    o_result number;
BEGIN
    select tx.id into transactionId from (select tx.id,row_number() over (order by tx.trans_time asc) as seqnum
    from test_tx_log tx
    where tx.transactionnumber = i_transactionnumber and lower(tx.vendor) = lower(i_vendor)) tx where seqnum = 1;

    o_result := CASE transactionId = i_txId WHEN true THEN 1 ELSE 0 END;

    return o_result;

 END;

Мой стол:

  Create TABLE test_tx_log
  (
   id                  RAW(16) not null,
   status              VARCHAR2 (300) NOT NULL,
   trans_time          TIMESTAMP NOT NULL,
   receiptnumber       VARCHAR2 (100) NULL,
   transactionnumber   VARCHAR2 (120) NULL,
   customerreference   VARCHAR2 (100) NULL,
   vendor              VARCHAR2 (100) NULL
   ) ;

C #

    public bool CheckDuplicate3()
    {
        DbConnection connection = null;
        try
        {
            connection = GetFactory().CreateConnection();
            if (connection != null)
            {
                connection.ConnectionString = "user id=XXXX;password=XXXX;data source=XXXX";
                connection.Open();
                using (DbCommand command = connection.CreateCommand())
                {
                    command.CommandText = "mca_test_package.checkDuplicate";
                    command.CommandType = CommandType.StoredProcedure;
                    command.AddParameter("o_result", DbType.Decimal, 0, ParameterDirection.ReturnValue);
                    command.AddParameter("i_vendor", DbType.String, tx.Vendor);
                    command.AddParameter("i_transactionnumber", DbType.String, tx.TransactionNumber.Trim());
                    command.AddParameter("i_txId", DbType.Binary, tx.Id.ToByteArray(), ParameterDirection.Input, 16);
                    command.ExecuteNonQuery();
                    var result = Convert.ToInt32(command.Parameters["o_result"].Value);

                    if (result == 1)
                    {
                        tx.status = "Success";
                        Console.WriteLine("No Duplicate {0}", tx);
                    }
                    else
                    {
                        Console.WriteLine("Duplicate {0}", tx);
                        tx.status = "RejectedDuplicate";
                    }
                }

                using (DbCommand command = connection.CreateCommand())
                {
                    command.CommandType = CommandType.Text;
                    command.CommandText = "update test_tx_log tx set tx.status = :status where id = :id";
                    command.AddParameter("status", DbType.String, tx.status);
                    //command.AddParameter("id", DbType.Decimal, tx.Id);
                    command.AddParameter("id", DbType.Binary, tx.Id.ToByteArray());
                    command.ExecuteNonQuery();
                }
            }
            return true;
        }
        finally
        {
            if (connection != null)
                connection.Close();
        }
    }

1 Ответ

0 голосов
/ 01 февраля 2019

Изменить (select tx.id,row_number() over (order by tx.trans_time asc) as seqnum

на

(select tx.id,row_number() over (order by tx.trans_time, tx.id asc) as seqnum

Сортировать по trans_time, tx.id, а не просто trans_time.

Без заказа погарантированный порядок не возвращается, поэтому порядок идентификатора в вашем запросе является случайным в течение trans_time.

В вашем примере, когда вы вызываете функцию с первым идентификатором, первый идентификатор является первым последовательностью и совпадает.

Когда вы вызываете функцию со вторым идентификатором, второй идентификатор является первым seqnum и также совпадает.

Добавление идентификатора к заказу гарантирует, что идентификатор 1 равен seqnum 1 для обоих вызовов в пределахсамое раннее время трансляции.

...