.net 从datatable获取唯一记录的有效方法

.net 从datatable获取唯一记录的有效方法,.net,vb.net,visual-studio-2010,datatable,dataview,.net,Vb.net,Visual Studio 2010,Datatable,Dataview,我有一个包含多个列的数据表,包括AccountNumber、Year和Month。我正在将此表中的信息导出到Excel工作簿。由于这个表可能非常大,我必须检查表中的记录数,因为Excel只能有65536行或类似的行。如果原始表足够小,我需要将所有记录放在一个工作表中。如果一个工作表中的记录太多,我需要根据AccountNumber将这些记录分为多个工作表。此外,如果特定AccountNumber的记录太多,则我需要根据年份将该AccountNumber拆分为多个工作表。如果某一特定年份仍有太多记

我有一个包含多个列的数据表,包括AccountNumber、Year和Month。我正在将此表中的信息导出到Excel工作簿。由于这个表可能非常大,我必须检查表中的记录数,因为Excel只能有65536行或类似的行。如果原始表足够小,我需要将所有记录放在一个工作表中。如果一个工作表中的记录太多,我需要根据AccountNumber将这些记录分为多个工作表。此外,如果特定AccountNumber的记录太多,则我需要根据年份将该AccountNumber拆分为多个工作表。如果某一特定年份仍有太多记录,则我必须按月将其拆分

例如:

如果我总共有500000条记录,我必须按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并以Excel电子表格的格式写出DataTable中的记录。有没有关于如何不用再调用数据库就能做到这一点的想法?提前感谢。

您是否专门为此操作从数据库中提取数据?如果是,请使用SELECT DISTINCT并在相关列上放置数据库索引。这样,您就不必担心了——DBMS将为您过滤掉重复的行。剩下要做的就是遍历这些行,并根据需要对它们进行分组

如果难以对行进行分组,可以将COUNT添加到select和group by子句中,DBMS将告诉您有多少行适合该类别:

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
您可以使用来相应地对数据行进行分组,并将它们添加到行数少于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

此样本在2005-2012年期间随机使用4个静态帐号,记录为500.000条。由于LINQ to DATASE完全在内存中工作,它只需1,6秒即可生成28个数据表并克隆所有数据行。

仅供参考,Excel 2007及更高版本可以有100万行。是的,但我们公司的一些PC仍在使用2003屏幕,因此升级它们可能更容易;我非常同意,但遗憾的是,这不取决于我:不,Excel生成并不是这个DataTable的唯一用途。Excel不是一个数据库。Excel是正确的选择吗?考虑使用Access或CSV文件。它正在生成一个Excel报表以供销售人员使用。非常感谢。我不得不改变一些小细节,但这是一个很大的帮助。