Member 12885549 Ответов: 2

Удалите новое повторяющееся значение, основанное на двух столбцах .Чистое ядро


У меня есть огромная таблица транзакций в базе данных azure, куда мы импортируем файлы с +1 миллионом объектов.

public class Transaction
   {
       [Key]
       public int Id { get; set; }
       public int TransactionId { get; set; }
       public DateTime Date { get; set; }
       public decimal Price { get; set; }
       public int UserId { get; set; }
       public string Product { get; set; }
       public int ClientId { get; set; }
       public int Uploaed { get; set; }
       public string UniqueId { get; set; }
       public string Custom1 { get; set; }
       public string Custom2 { get; set; }
       public string Custom3{ get; set; }

   }


после импорта всех новых данных я беру все новые идентификаторы транзакций и беру все идентификаторы транзакций для этого клиента из базы данных.

Что я уже пробовал:

// ids from import
        string transactionsString = string.Join(",", transactionIdsCsv);
        var result = await   _transactionsDataRepository.GetByTransactionIdsAndClientId(transactionIdsCsv.ToArray(), clientId);
        // ids from repository
        string transactionsDBString = string.Join(",", result.ToList());

        // remove rows in db where duplicate transactions ids and clientId=ClientId


но я изо всех сил пытаюсь найти наиболее эффективный способ. Я хотел сделать что-то вроде удалить из сделок, где ИД транзакции в (transactionsDBString) и идентификатора ClientID = параметр ClientID ` но что бы удалить оба значения, и я хочу, только новое значение, которое будет удалено (и старое значение, чтобы остаться)

но будет ли это хорошим способом? даже выборка `var result = await _transactionsDataRepository... - это может занять много времени, так как там миллионы строк.

2 Ответов

Рейтинг:
2

Maciej Los

Что ж...

Цитата:
после импорта все новые данные я беру все новые идентификаторы транзакций и беру все идентификаторы транзакций для этого клиента из базы данных.
...
но я изо всех сил пытаюсь найти наиболее эффективный способ. Я хотел этого. сделайте что-нибудь вроде удалить из проводки `where transactionId IN (transactionsDBString) and clientId = ClientID ` но это удалило бы оба значения, и я хочу только новое значение будет удалено (а старое останется)


Я бы предпочел избежать импорта дубликатов данных. Итак, создайте метод/хранимую процедуру, которая будет вставлять только те данные, которые не дублируются. Что-то вроде:
INSERT INTO ExistingTable (...)
SELECT ...
FROM ImportedData IMDA
WHERE NOT EXISTS(
SELECT ...
FROM ExistingData EXDA
WHERE IMDA.ClientID = EXDA.ClientID AND IMDA.TransactionID = EXDA.TransactionID)


Когда вы это сделаете, вы никогда не будете вынуждены удалять дубликаты данных.

Для получения более подробной информации, пожалуйста, смотрите: EXISTS (Transact-SQL) - SQL Server | Microsoft Docs[^]

Удачи вам!


Рейтинг:
17

Richard Deeming

В SQL Server вам понадобится что-то вроде:

WITH cteTransactions As
(
    SELECT
        Id,
        ROW_NUMBER() OVER (PARTITION BY ClientId, TransactionId ORDER BY Id) As RN
    FROM
        Transactions
)
DELETE
FROM
    T
FROM
    Transactions As T
    INNER JOIN cteTransactions As D
    ON D.Id = T.Id
    And D.RN > 1
;
ROW_NUMBER (Transact-SQL) - SQL Server | Microsoft Docs[^]

Вы можете выполнить необработанную команду SQL в ядре Entity Framework с помощью context.Database.ExecuteSqlRaw метод расширения:
RelationalDatabaseFacadeExtensions.Метод ExecuteSqlRaw (Microsoft.EntityFrameworkCore) | Microsoft Docs[^]


Maciej Los

Ух ты!
5ed!

Member 12885549

Вау, это потрясающее решение! Я пытался написать процедуру с слиянием, но это бьет все!

Richard Deeming

Он оставляет значение с самым низким идентификатором.

Если вы хотите оставить самый высокий идентификатор вместо этого, измените его:

ORDER BY Id
к:
ORDER BY Id DESC

Member 12885549

Спасибо! ты-герой!