Эффективный способ получить уникальные записи из данных - PullRequest
1 голос
/ 13 августа 2011

У меня есть DataTable с несколькими столбцами, включая AccountNumber, Year и Month.Я экспортирую информацию из этой таблицы в книгу Excel.Поскольку эта таблица потенциально может быть очень большой, я должен проверить количество записей в таблице (поскольку в Excel может быть только 65536 строк или что-то в этом роде. Если исходная таблица достаточно мала, мне нужно поместить все записив одном листе. Если существует слишком много записей для одного листа, мне нужно разделить записи на несколько листов на основе AccountNumber. Кроме того, если существует слишком много записей для определенного AccountNumber, то мне нужно разделить этот AccountNumber на несколько листовна основе года. Если в определенном году по-прежнему слишком много записей, я должен разделить их по месяцам.

Например:

Если у меня есть 500 000 записей, я должен разделить ихпо AccountNumber, получая:

Имя рабочего листа ---- Количество записей

  • 1111 ---- 150 000
  • 2222 ---- 50 000
  • 3333 ---- 100 000

Тогда мне нужно будет разделить учетные записи 1111 и 3333 на несколько рабочих листов на основеГод.Тогда у меня было бы что-то вроде этого:

Имя листа ---- Количество записей

  • 1111 - 2010 ---- 50 000
  • 1111 - 2011 ---- 100 000
  • 2222 ---- 50 000
  • 3333-2010 ---- 50 000
  • 3333-2011 ---- 50 000

Тогда, так как 1111 - 2011 все еще слишком велик, я должен был бы разделить его на месяц, в итоге получив:

Имя рабочего листа ---- Количество записей

  • 1111-2010 ---- 50 000
  • 1111-201105 ---- 30 000
  • 1111-201106 ---- 30 000
  • 1111-201107 ----40 000
  • 2222 ---- 50 000
  • 3333-2010 ---- 50 000
  • 3333-2011 ---- 50 000

Код, который используется для создания файла Excel, является проектом, написанным моей компанией.Для простоты функция принимает DataTable и записывает записи в DataTable в формате электронной таблицы Excel.Любые идеи о том, как я могу сделать это, не делая больше звонков в базу данных?Заранее спасибо.

Ответы [ 2 ]

0 голосов
/ 14 августа 2011

Вы можете использовать LINQ-to-DataSet , чтобы сгруппировать DataRows соответственно и добавить их в отдельный DataTables с количеством строк меньше 65536.

Посмотрите на эту работувыборка, которая также генерирует правильные имена файлов / таблиц данных:

Private Shared sampleAccountNumbers As List(Of Int32) = {1111, 2222, 3333, 4444}.ToList
Private Const MAX_ROWS = 65536
Private tblSource As New DataTable()
Private allResultTables As New List(Of DataTable)

Private Sub SplitTableRows()
    Dim accQuery = _
        From row In tblSource
        Group row By AccountNumber = row("AccountNumber") Into AccNumGroup = Group
    For Each acc In accQuery
        If acc.AccNumGroup.Count > MAX_ROWS Then
            Dim yearQuery = _
               From row In acc.AccNumGroup
               Group row By Year = row("Year") Into YearGroup = Group
            For Each y In yearQuery
                If y.YearGroup.Count > MAX_ROWS Then
                    Dim monthQuery = _
                       From row In y.YearGroup
                       Group row By Month = row("Month") Into MonthGroup = Group
                    For Each m In monthQuery
                        If m.MonthGroup.Count > MAX_ROWS Then
                            'split by days or whatever...'
                        Else
                            Dim tblMonth = m.MonthGroup.CopyToDataTable()
                            tblMonth.TableName = String.Format("{0}-{1}{2}", acc.AccountNumber, y.Year, m.Month)
                            allResultTables.Add(tblMonth)
                        End If
                    Next
                Else
                    Dim tblYear = y.YearGroup.CopyToDataTable()
                    tblYear.TableName = String.Format("{0}-{1}", acc.AccountNumber, y.Year)
                    allResultTables.Add(tblYear)
                End If
            Next
        Else
            Dim tblAcc = acc.AccNumGroup.CopyToDataTable()
            tblAcc.TableName = acc.AccountNumber
            allResultTables.Add(tblAcc)
        End If
    Next
End Sub

Private Sub BtnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnStart.Click
    InitSourceDataTable()
    If tblSource.Rows.Count > MAX_ROWS Then
        SplitTableRows()
    Else
        allResultTables.Add(tblSource)
    End If
    For Each tbl In allResultTables
        'call your generate-excel-method...'
    Next
End Sub

Private Sub InitSourceDataTable()
    Dim rndAccNum As New Random(Date.Now.Millisecond)
    Dim rndYear As New Random(Date.Now.Millisecond)
    Dim rndMonth As New Random(Date.Now.Millisecond)
    tblSource.Columns.Add(New DataColumn("ID", GetType(Integer)))
    tblSource.Columns.Add(New DataColumn("AccountNumber", GetType(Integer)))
    tblSource.Columns.Add(New DataColumn("Year", GetType(Integer)))
    tblSource.Columns.Add(New DataColumn("Month", GetType(Integer)))
    For i As Int32 = 1 To 500000
        Dim newRow = tblSource.NewRow
        newRow("ID") = i
        newRow("AccountNumber") = sampleAccountNumbers(rndAccNum.Next(0, sampleAccountNumbers.Count))
        newRow("Year") = rndAccNum.Next(2005, 2012)
        newRow("Month") = rndMonth.Next(1, 13)
        tblSource.Rows.Add(newRow)
    Next
End Sub

В этой выборке случайным образом используются 4 статических номера счета в период 2005-2012 годов с 500 000 записей.Он генерирует 28 DataTables и клонирует все DataRows всего за 1,6 секунды, поскольку LINQ-to-DataSet работает полностью в памяти.

0 голосов
/ 13 августа 2011

Вы извлекаете данные из базы данных специально для этой операции? Если это так, используйте SELECT DISTINCT и поместите индекс базы данных в соответствующие столбцы. Таким образом, вам не нужно беспокоиться об этом - СУБД отфильтрует дублирующиеся строки для вас. Все, что вам остается сделать, - это перебирать строки и группировать их, как вы хотите.

Если вы боретесь с группировкой строк, вы можете добавить COUNT () к предложениям select и group by, и СУБД сообщит вам, сколько строк соответствует категории:

SELECT *, COUNT(*)AS row_count GROUP BY accountid, year, month, etc...;

и ваш ряд будет выглядеть так:

c1   c2   c3   row_count
---- ---- ---- ---------
xxx, xxx, xxx, 1
yyy, yyy, yyy, 2
yyy, yyy, zzz, 2
...