vb@rchiv
VB Classic
VB.NET
ADO.NET
VBA
C#
Erstellen von dynamischen Kontextmen?s - wann immer Sie sie brauchen!  
 vb@rchiv Quick-Search: Suche startenErweiterte Suche starten   Impressum  | Datenschutz  | vb@rchiv CD Vol.6  | Shop Copyright ©2000-2024
 
zurück
Rubrik: Variablen/Strings · Array/ArrayList   |   VB-Versionen: VB200824.02.09
DataTable-Spalte in Array übertragen

DataTable-Erweiterungen zur Übertragung des Inhalts numerischen Spalten in ein Array. Varianten für die Behandlung von Null-Werten. Demo für LINQ-Abfragen.

Autor:   Manfred BohnBewertung:     [ Jetzt bewerten ]Views:  16.184 
ohne HomepageSystem:  Win2k, WinXP, Win7, Win8, Win10, Win11kein Beispielprojekt 

Die Klasse Datatable (im Namespace: System.Data) "stellt eine Tabelle mit im Arbeitsspeicher befindlichen Daten dar" und "ist ein zentrales Objekt in der ADO.NET-Bibliothek".

Instanzen dieser Klasse werden meist verwendet, um Daten aus Datenbanken über einen Datenadapter abzurufen. Ein Tabellenschema (Spalten) kann aber auch per Code definiert und die Tabelle durch Hinzufügen von Zeilen mit Daten gefüllt werden (vgl. Routine 'FillTable').

Um Daten aus einer numerischen Tabellen-Spalte effizient weiterverarbeiten zu können, ist es oft zweckmäßig, sie zunächst in ein Array zu übertragen.

Die DataTable-Erweiterungsmethode GetCol und ihre Varianten erledigen diesen Job:

  • Es handelt sich um 'generische' Methoden, die für Spalten verwendbar sind, die 'Primitives', Decimals oder numerische Strings enthalten.
  • Die Daten können bei der Abfrage in einen anderen Datentyp konvertiert werden (Convert-Klasse); dabei kann es zu Genauigkeitsverlusten kommen (z.B. bei einschränkender Konvertierung).
  • Die Daten können in Zielarrays aus Nullable-Strukturen übertragen werden; solche Arrays enthalten fehlende Spalten-Werte (System.DBNull oder Nothing) als Nothing-Verweis. Alternativ ist die gefilterte Daten-Übertragung möglich (Erweiterung: 'GetCol1').
  • Die Abfragen sind jeweils durch ein LINQ-Kommando realisiert (Verwendung der ToArray-Erweiterung).

Die Erweiterung 'GetCols' übernimmt eine Liste von Spaltennamen und trägt die zugehörigen Daten in ein Array von Arrays ein. Fehlt die Namensliste, werden alle Tabellendaten ausgelesen. Das funktioniert aber nur, falls alle Tabellen-Spalten numerisch sind.

Falls Sie in der Tabelle eine Spalte mit Nullwerten abfragen wollen, aber weder Nullable-Strukturen verwenden noch diese Werte filtern möchten, steht als Alternative die Version 'GetColumn_DBL' zur Verfügung. Sie gibt STETS ein Double-Array zurück, in dem NULL-Werte durch den IEEE-Sonderwert 'Double.NaN' markiert sind. Bei Verwendung dieses Wertes gibt es einige wichtige Besonderheiten zu beachten:

  • Er ist wenig effizient.
  • Er muß zwingend durch die Funktion 'Double.IsNaN' identifiziert und verglichen werden.
  • Er stört Sortiervorgänge der Array.Sort-Methode (StandardComparer).

Die Anwendungsbeispiele zeigen die Aufrufe der verschiedenen Abfrage-Varianten. Bei der Angabe einer nicht vorhandenen Tabelle oder eines nicht vorhandenen Spaltennamens im Parameter 'ColumName' kommt es zu einer Ausnahme (bei den Funktionen die keinen Try/Catch-Block enthalten).
(Anmerkung: Die VB-IDE 'vervollständigt' die Eingabe des EntryType-Schlüsselworts 'Of' gerne zu 'OfType'. Das hat wohl nichts zu bedeuten. Die Rückgabe der Funktion 'GetCols' (Array of Arrays) wird von der VB-IDE als 'Nothing' angezeigt. Auch das hat nichts zu bedeuten.)

Um die Erweiterungen zu verwenden. muss das Modul 'mod_GetTableColumn' dem Projekt hinzugefügt werden.

Aufrufbeispiele:

' Demo-Tabelle erstellen und füllen
Dim dt As Data.DataTable = FillTable()
 
' Abfrage von numerische Spalten durch generische Methode
' (Zielarrays mit Nullable-Strukturen für fehlende Werte)
Dim Byt?() As Byte = dt.GetCol(Of Byte)("Sp_Byte")
Dim Integ?() As Integer = dt.GetCol(Of Integer)("Sp_Integer")
 
Dim col_name As String = dt.Columns(2).ColumnName
Dim Sng?() As Single = dt.GetCol(Of Single)(col_name)
 
' Zulässige Konvertierungen können bei 
' der Abfrage vorgenommen werden
Dim Dec_Sng?() As Decimal = _
dt.GetCol(Of Decimal)("Sp_Single")
 
' Die Abfrage von String-Spalten 
' mit numerischem Inhalt ist möglich
Dim Dec_Str?() As Decimal = dt.GetCol(Of Decimal)("Sp_String")
 
' alternative Abfrage-Variante (Fehlerbehandlung)
' (auch einschränkende Konvertierung ist zugelassen !!)
Dim ulng?(0) As ULong
If Not dt.GetCol("Sp_Single", ulng) Then
  MessageBox.Show("Abfrage scheitert")
End If
 
' Diese Variante bietet auch die Möglichkeit zum Sortieren
' Nothing wird im Array nach vorne sortiert
Dim shrt?(0) As Short
If Not dt.GetCol("Sp_String", shrt, True) Then
  MessageBox.Show("Abfrage scheitert")
End If
 
' Filternde Abfragevariante (Null-Werte sind entfernt)
Dim intg() As Integer = dt.GetCol1(Of Integer)("Sp_String")
 
' Summe der Spalte 'Sp_Integer' berechnen
' Erweiterungsmethode 'SUM' in Linq.Enumerable
Dim summe? As Integer = _
dt.GetCol(Of Integer)("Sp_Integer").Sum
 
' Die Erweiterungen in Linq.Enumerable stellen 
' Überladungen für Nullable-Strukturen bereit und filtern
' bei der Berechnung NULL-Werte automatisch aus
Dim ave? As Single = _
dt.GetCol(Of Single)("Sp_Single").Average
 
' Falls keine Werte in der Spalte vorliegen, entsteht ein
' Ergebnis-Array, das keine Elemente besitzt
Dim dbl() As Double = dt.GetCol1(Of Double)("Sp_Null")
 
' Mehrere Spalten in ein Array von Arrays eintragen
Dim dec_cols?()() As Decimal = dt.GetCols(Of Decimal) _
  ("Sp_Single", "Sp_Integer", "Sp_String")
 
' Die Daten der Spalte "Sp_Integer" stehen in dec_cols(1)
Dim dec_int?() As Decimal = dec_cols(1)
 
' Alle Spalten der Tabelle abfragen
Dim tab_cols?()() As Decimal = dt.GetCols(Of Decimal)()
 
' Die Daten der Spalte "Sp_Decimal" stehen in tab_cols(4)
Dim dec_val?() As Decimal = tab_cols(4)

Hier das Modul mit den Erweiterungen für die Übertragung numerischer Tabellen-Spalten in ein Array:

Option Strict On
Option Explicit On
Option Infer Off
 
Imports System.Data
Imports System.Linq
 
Public Module mod_GetTableColumn
  ''' <summary>Abfrage einer Tabellenspalte 
  ''' (incl. Nullwerte)</summary>
  ''' <typeparam name="T">Typ der Rückgabe</typeparam>
  ''' <param name="Table">Tabelle</param>
  ''' <param name="ColumnName">Name der Tabellenspalte</param>
  ''' <returns>Array mit Werten der Tabellenspalte</returns>
  <System.Runtime.CompilerServices.Extension()> _
  Public Function GetCol(Of T As Structure) ( _
    ByVal Table As System.Data.DataTable, _
    ByVal ColumnName As String) As T?()
 
    Dim cv As New T 'Hilsvariable für TypInferenz (Rückgabe)
    Return (From row As System.Data.DataRow In Table _
      Let colval As Nullable(Of T) = _
      Get_T(row.Item(ColumnName), cv) _
      Select colval).ToArray
  End Function
  ''' <summary>Abfrage einer Tabellenspalte 
  ''' (Filter für Nullwerte)</summary>
  ''' <typeparam name="T">Typ der Rückgabe</typeparam>
  ''' <param name="Table">Tabelle</param>
  ''' <param name="ColumnName">Name der Tabellenspalte</param>
  ''' <returns>Array mit Werten der Tabellenspalte</returns>
  <System.Runtime.CompilerServices.Extension()> _
  Public Function GetCol1(Of T As Structure) ( _
    ByVal Table As System.Data.DataTable, _
    ByVal ColumnName As String) As T()
 
    Dim cv As New T 'Hilsvariable für TypInferenz (Rückgabe)
    Return (From row As System.Data.DataRow In Table _
      Let colval As Nullable(Of T) = _
      Get_T(row.Item(ColumnName), cv) _
      Where Not colval Is Nothing _
      Let colval_filter As T = CType(colval, T) _
      Select colval_filter).ToArray
  End Function
  ''' <summary>Kontrollierte Abfrage einer Tabellenspalte 
  ''' (incl. Nullwerte)</summary>
  ''' <typeparam name="T">Typ der Rückgabe</typeparam>
  ''' <param name="Table">Tabelle</param>
  ''' <param name="ColumnName">Name der Tabellenspalte</param>
  ''' <param name="SortAscending">Daten ansteigend sortieren?</param>
  ''' <param name="col_vals">Array mit Spalten-Werten</param>
  <System.Runtime.CompilerServices.Extension()> _
  Public Function GetCol(Of T As Structure) ( _
    ByVal Table As System.Data.DataTable, _
    ByVal ColumnName As String, ByRef col_vals As T?(), _
    Optional ByVal SortAscending As Boolean = False) As Boolean
 
    Dim cv As New T 'Hilfsvariable für TypInferenz
    Try
      If Not SortAscending Then
        col_vals = (From row As System.Data.DataRow In Table _
          Let colval As Nullable(Of T) = _
          Get_T(row.Item(ColumnName), cv) _
          Select colval).ToArray
      Else
        col_vals = (From row As System.Data.DataRow In Table _
          Let colval As Nullable(Of T) = _
          Get_T(row.Item(ColumnName), cv) _
          Order By colval Select colval).ToArray
      End If
      Return True
    Catch
      ReDim col_vals(0)
      Return False
    End Try
  End Function
  ''' <summary>Abfrage der numerischen Spalten in einer Tabelle 
  ''' </summary>
  ''' <typeparam name="T">Rückgabe-Datentyp</typeparam>
  ''' <param name="Table">abzufragende Tabelle</param>
  ''' <param name="ColumnNames">Liste der Spaltennamen</param>
  ''' <returns>Array aus Arrays mit Spaltenwerten</returns>
  <System.Runtime.CompilerServices.Extension()> _
  Public Function GetCols(Of T As Structure) ( _
    ByVal Table As System.Data.DataTable, _
    ByVal ParamArray ColumnNames() As String) As T?()()
 
    Dim cz As Integer = ColumnNames.Length - 1
    Dim cze As Integer = cz
    If cz < 0 Then cze = Table.Columns.Count - 1
    Dim cs?(cze)() As T
    If cz > 0 Then
      For i As Integer = 0 To ColumnNames.Length - 1
        cs(i) = Table.GetCol(Of T)(ColumnNames(i))
      Next i
    Else
      For i As Integer = 0 To Table.Columns.Count - 1
        cs(i) = Table.GetCol(Of T)(Table.Columns(i).ColumnName)
      Next i
    End If
    Return cs
  End Function
  Private Function Get_T(Of T1, T2 As Structure) ( _
    ByVal colval As T1, ByVal cv As T2) As T2?
 
    ' Umwandlung eines Wertes, der Null sein kann
    ' in eine Nullable-Struktur des Typs T2
 
    If System.DBNull.Value.Equals(colval) Then
      Return Nothing
    Else
      Return CType(Convert.ChangeType(colval, GetType(T2)), T2)
    End If
  End Function
  ''' <summary>Auslesen einer numerischen Datenspalte</summary>
  ''' <param name="Table">Datentabelle</param>
  ''' <param name="ColumnName">Name der Tabellen-Spalte</param>
  ''' <param name="OrderedAscendíng">Ansteigend sortieren?</param>
  ''' <returns>Spalteninhalt als Double-Array</returns>
  <System.Runtime.CompilerServices.Extension()> _
  Public Function GetColumn_DBL ( _
    ByVal Table As System.Data.DataTable, _
    ByVal ColumnName As String, _
    Optional ByVal OrderedAscendíng As Boolean = False) As Double()
 
    If Not OrderedAscendíng Then
      Return (From row As System.Data.DataRow In Table _
        Let colval As Double = _
        CDbl(GetDouble(row.Item(ColumnName))) _
        Select colval).ToArray
    Else
      ' ansteigend sortierte Daten
      Return (From row As System.Data.DataRow In Table _
        Let colval As Double = _
        CDbl(GetDouble(row.Item(ColumnName))) _
        Order By colval Select colval).ToArray
    End If
  End Function
  Private Function GetDouble(Of T)(ByVal colval As T) As Double
 
    ' EntryWert in Double wandeln
    ' Hilfsfunktion für GetColumn_DBL
 
    If System.DBNull.Value.Equals(colval) Then
      Return Double.NaN
    Else
      Return CType(Convert.ChangeType (colval, TypeCode.Double), Double)
    End If
  End Function
  Public Function FillTable() As System.Data.DataTable
 
    ' DataTable-Instanz erstellen 
    ' und mit einigen Spalten versehen
    ' für die Aufrufbeispiele
 
    Dim dt As New System.Data.DataTable("Test-Tabelle")
    dt.Columns.Add("Sp_Byte", GetType(Byte))
    dt.Columns.Add("Sp_Integer", GetType(Integer))
    dt.Columns.Add("Sp_Single", GetType(Single))
    dt.Columns.Add("Sp_String", GetType(String))
    dt.Columns.Add("Sp_Decimal", GetType(Decimal))
    dt.Columns.Add("Sp_Null", GetType(Integer))
 
    Dim N As Integer = 10 ' Zeilenzahl
 
    ' Einige Datenzeilen eintragen 
    For i As Integer = 1 To N
      If i Mod 2 = 0 Then
        ' Fehlende Werte in Sp_Single und Sp_String
        dt.Rows.Add(i, (100 - i) ^ 2, System.DBNull.Value, _
          Nothing, (N + 1 - i) * 12345678.12345678, _
          System.DBNull.Value)
      Else
        dt.Rows.Add(i, i, Microsoft.VisualBasic.Rnd, _
          CDbl(100 * i), (N + 1 - i) * 12345678.12345678, _
          System.DBNull.Value)
      End If
    Next i
    ' Rückgabe
    Return dt
  End Function
End Module

Dieser Tipp wurde bereits 16.184 mal aufgerufen.

Voriger Tipp   |   Zufälliger Tipp   |   Nächster Tipp

Über diesen Tipp im Forum diskutieren
Haben Sie Fragen oder Anregungen zu diesem Tipp, können Sie gerne mit anderen darüber in unserem Forum diskutieren.

Neue Diskussion eröffnen

nach obenzurück


Anzeige

Kauftipp Unser Dauerbrenner!Diesen und auch alle anderen Tipps & Tricks finden Sie auch auf unserer aktuellen vb@rchiv  Vol.6

Ein absolutes Muss - Geballtes Wissen aus mehr als 8 Jahren vb@rchiv!
- nahezu alle Tipps & Tricks und Workshops mit Beispielprojekten
- Symbol-Galerie mit mehr als 3.200 Icons im modernen Look
Weitere Infos - 4 Entwickler-Vollversionen (u.a. sevFTP für .NET), Online-Update-Funktion u.v.m.
 
   

Druckansicht Druckansicht Copyright ©2000-2024 vb@rchiv Dieter Otter
Alle Rechte vorbehalten.
Microsoft, Windows und Visual Basic sind entweder eingetragene Marken oder Marken der Microsoft Corporation in den USA und/oder anderen Ländern. Weitere auf dieser Homepage aufgeführten Produkt- und Firmennamen können geschützte Marken ihrer jeweiligen Inhaber sein.

Diese Seiten wurden optimiert für eine Bildschirmauflösung von mind. 1280x1024 Pixel