VB Чтение данных с SQL сервера на массив, запись в .CSV - PullRequest
0 голосов
/ 29 января 2020

Я пытаюсь считать данные с сервера SQL в массив. После этого я хотел бы записать каждую строку в отдельные файлы .csv.

Пока это мой код:

Imports System.Data.SqlClient

Public Class Form1
    Public SQLcn As New SqlConnection

    Public Function Connect() As Boolean
        SQLcn = New SqlConnection("Server = Server01;Database=PROD;User ID=user; Password = 123")

        Try
            SQLcn.Open()

            Return True

        Catch ex As Exception

            MessageBox.Show(ex.Message)
            Return False

        End Try
    End Function

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim SQLQuery As String
        Dim SQLcmd As SqlCommand
        Dim SQLrdr As SqlDataReader
        Dim NAVArray As New ArrayList()
        Call Connect()

        SQLQuery = "SELECT No_ FROM " & "dbo.Database" & " Where No_ LIKE '10007*'"

        SQLcmd = New SqlCommand(SQLQuery, SQLcn)
        SQLrdr = SQLcmd.ExecuteReader()

        While SQLrdr.Read()

            Dim dict As New Dictionary(Of String, Object)
            For count As Integer = 0 To (SQLrdr.FieldCount - 1)
                dict.Add(SQLrdr.GetName(count), SQLrdr(count))
            Next

            NAVArray.Add(dict)

        End While

        ExportCSV(NAVArray, "\\path\path\path")

        SQLcn.Close()

    End Sub

    Function ExportCSV(ByVal Daten As ArrayList, ByVal Pfad As String) As Boolean
        Dim Nummer As Integer

        For Each Nummer In Daten
            Dim csv As IO.StreamWriter = My.Computer.FileSystem.OpenTextFileWriter(Pfad & Nummer, False)

            csv.WriteLine("formatcount;formatname;printername;Beschreibung;")
            csv.WriteLine("1;\\path\path\path\Format1.fmt;")
            csv.Close()

        Next

        Return 0
    End Function

End Class

NAVArray даже не заполняется данными.

Кроме того, я не знаю, как записать данные в CSV.Writeline.

РЕДАКТИРОВАТЬ:

Новый код (работает до сих пор) выглядит следующим образом:

Option Infer On
Option Strict On

Imports System.Data.SqlClient

Imports System.IO

Public Class Form1
    Public SQLcn As New SqlConnection

    Public Function GetData(databaseColumnNames As String()) As DataTable

        Dim dt As New DataTable()

        Dim csb As New SqlConnectionStringBuilder With {.DataSource = "NAVDB01",
                                                        .InitialCatalog = "NAV110_PROD",
                                                        .UserID = "paz",
                                                        .Password = "****"
                                                        }

        Dim columnNames = " " & String.Join(", ", databaseColumnNames.Select(Function(c) "[" & c & "]")) & " "

        Dim sql = "SELECT " & columnNames & " FROM [dbo.Part1 Part2$Item] WHERE No_ LIKE '10007%'"

        Using conn = New SqlConnection(csb.ConnectionString),
                cmd = New SqlCommand(sql, conn)

            Dim DAdap As New SqlDataAdapter(cmd)
            DAdap.Fill(dt)

        End Using

        Return dt


    End Function

    Function CsvLine(a As Object(), separator As Char) As String

        Dim b = a.Select(Function(x) x.ToString()).ToArray()

        For i = 0 To b.Count - 1

            If b(i).IndexOfAny({separator, Chr(42), Chr(10), Chr(13)}) >= 0 Then
                b(i) = b(i).Replace("""", """""")
                b(i) = """" & b(i) & """"
            End If
        Next

        Return String.Join(separator, b)

    End Function

    Sub WriteCsvFiles(destPath As String, headings As String(), dt As DataTable)
        Dim separator As Char = ";"c
        Dim header = String.Join(separator, headings)

        For Each r As DataRow In dt.Rows

            Dim destFile = Path.Combine(destPath, r(0).ToString().Trim() & ".csv")

            Using sw As New StreamWriter(destFile)
                sw.WriteLine(header)
                sw.WriteLine(CsvLine(r.ItemArray, separator))
            End Using

        Next

    End Sub
    Private Sub bnDatenVerarbeiten_Click() Handles bnDatenVerarbeiten.Click
        Dim destinationFolder = "\\fileserver02\Folder1"


        Dim columnsToUseSQL = {"Description"}
        Dim columnsToUseCSV = {"formatcount", "formatname", "printername", "Beschreibung"}
        Dim daten = GetData(columnsToUseSQL)


        WriteCsvFiles(destinationFolder, columnsToUseCSV, daten)


    End Sub
End Class

О дополнительном входе. Будет реализовано 5 полей: Formatcount As InputBox Formatname As Dropdown printername As Dropown (значение по умолчанию определяется именем Format) *

Поля, идущие прямо к CSV. : formatcount formatname имя_принтера

Поля с результатом отправляются в CSV. : itemnumber (результат, например, "Описание") credititor (result = "specialcode"; "countrycode")

EDIT2:

Текущее состояние:

Option Infer On
Option Strict On

Imports System.Data.SqlClient
Imports System.IO

Public Class Form1
    Public SQLcn As New SqlConnection

    Public Function GetData(databaseColumnNames As String()) As DataTable

        Dim dt As New DataTable()

        Dim csb As New SqlConnectionStringBuilder With {.DataSource = "Server01",
                                                        .InitialCatalog = "NAV110_PROD",
                                                        .UserID = "paz",
                                                        .Password = "***"
                                                        }

        Dim columnNames = " " & String.Join(", ", databaseColumnNames.Select(Function(c) "[" & c & "]")) & " "

        Dim sql = "SELECT " & columnNames & " FROM [dbo.Part1 Part2$Item] WHERE No_ LIKE '10007%'"

        Using conn = New SqlConnection(csb.ConnectionString),
                cmd = New SqlCommand(sql, conn)

            Dim DAdap As New SqlDataAdapter(cmd)
            DAdap.Fill(dt)

        End Using

        Return dt


    End Function

    Function CsvLine(a As Object(), separator As Char) As String

        Dim b = a.Select(Function(x) x.ToString()).ToArray()

        For i = 0 To b.Count - 1

            If b(i).IndexOfAny({separator, Chr(42), Chr(10), Chr(13)}) >= 0 Then
                b(i) = b(i).Replace("""", """""")
                b(i) = """" & b(i) & """"
            End If
        Next

        Return String.Join(separator, b)

    End Function

    Sub WriteCsvFiles(destPath As String, headings As String(), dt As DataTable)
        Dim separator As Char = ";"c
        Dim header = String.Join(separator, headings)

        For Each r As DataRow In dt.Rows
            Dim destFile = Path.Combine(destPath, r(0).ToString().Trim() & ".csv")

            Using sw As New StreamWriter(destFile)
                sw.WriteLine(header)
                sw.WriteLine(CsvLine(r.ItemArray, separator))
            End Using

        Next

    End Sub
    Private Sub bnDatenVerarbeiten_Click() Handles bnDatenVerarbeiten.Click
        Dim destinationFolder = "\\fileserver02\folder"
        Dim Anzahl = 1
        Dim Format = "\\fileserver02\folder2"
        Dim Drucker = "\\PRNSRV\Druckdruck"


        Dim columnsToUseSQL = {"Description", "Description 2"}
        Dim columnsToUseCSV = {"Beschreibung", "Beschreibung 2", "formatcount", "formatname", "printername"}
        Dim daten = GetData(columnsToUseSQL)

        daten.Columns.Add("formatcount", GetType(Integer))
        daten.Columns.Add("formatname", GetType(String))
        daten.Columns.Add("printername", GetType(String))

        daten.Rows.Add(daten.Rows(0).Item("Description"), daten.Rows(0).Item("Description 2"), Anzahl, Format, Drucker)


        WriteCsvFiles(destinationFolder, columnsToUseCSV, daten)


    End Sub

End Class

Ответы [ 2 ]

0 голосов
/ 29 января 2020

Похоже, что вы хотите выбрать 4 столбца из базы данных, поэтому для ответа на вопрос я создал таблицу с именем "Huber" с этими данными:

No_ formatcount formatname  printername Beschreibung
10007       1           Hello   World   Starting "entry".
100071      2           Yellow  Flower  NULL
100072      3           Grey    Rock    Let's have a ; here.

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

Существует стандарт для файлов CSV: RF C 4180 , поэтому мы могли бы также попытаться следовать этому .

Мне кажется, что в этом случае было бы проще извлечь данные в DataTable. Поскольку каждый элемент данных будет преобразован в строку для записи в файл CSV, при этом не будет проблем с данными NULL из базы данных.

При использовании базы данных лучше всего открыть соединение, выполните операция, избавьтесь от соединения. Оператор VB. NET Using позаботится об утилизации автоматически, даже если что-то пойдет не так. Метод DataAdapter.Fill выполняет открытие и закрытие для вас (фактически он оставляет соединение в том же состоянии, что и до его вызова). Не используйте ничего похожего на «Function Connect ()» в вопросе: это приведет к проблемам.

Учитывая все это, я использовал этот код:

Option Infer On
Option Strict On

Imports System.Data.SqlClient
Imports System.IO

Public Class Form1

    Function GetData(databaseColumnNames As String()) As DataTable
        Dim dt As New DataTable()

        Dim csb As New SqlConnectionStringBuilder With {.DataSource = "Server01",
                                                        .InitialCatalog = "PROD",
                                                        .UserID = "user",
                                                        .Password = "123"}

        ' Put the column names in square brackets in case a reserved word is used as a column name.
        ' Does not take into account using square brackets in a column name (don't do that).
        Dim columnNames = " " & String.Join(", ", databaseColumnNames.Select(Function(c) "[" & c & "]")) & " "

        Dim sql = "SELECT " & columnNames & " FROM dbo.[Huber] WHERE [No_] LIKE '10007%'"

        Using conn = New SqlConnection(csb.ConnectionString),
                cmd = New SqlCommand(sql, conn)

            Dim da As New SqlDataAdapter(cmd)
            da.Fill(dt)

        End Using

        Return dt

    End Function

    Function CsvLine(a As Object(), separator As Char) As String
        ' Ref: RFC 4180 "Common Format and MIME Type for Comma-Separated Values (CSV) Files"
        ' https://tools.ietf.org/html/rfc4180

        Dim b = a.Select(Function(x) x.ToString()).ToArray()

        For i = 0 To b.Count - 1
            ' If the field contains the separator, a double-quote, LF, or CR, then make adjustments:
            If b(i).IndexOfAny({separator, Chr(42), Chr(10), Chr(13)}) >= 0 Then
                b(i) = b(i).Replace("""", """""")
                b(i) = """" & b(i) & """"
            End If
        Next

        Return String.Join(separator, b)

    End Function

    Sub WriteCsvFiles(destPath As String, headings As String(), dt As DataTable)
        Dim separator As Char = ";"c
        Dim header = String.Join(separator, headings)

        For Each r As DataRow In dt.Rows
            ' Use the first column for the filename:
            Dim destFile = Path.Combine(destPath, r(0).ToString().Trim() & ".csv")

            Using sw As New StreamWriter(destFile)
                sw.WriteLine(header)
                sw.WriteLine(CsvLine(r.ItemArray, separator))
            End Using

        Next

    End Sub

    Private Sub bnDatenVerarbeiten_Click(sender As Object, e As EventArgs) Handles bnDatenVerarbeiten.Click
        Dim destinationFolder = "C:\Temp\Huber"
        Directory.CreateDirectory(destinationFolder)

        ' The names of the columns in the database...
        Dim columnsToUse = {"formatcount", "formatname", "printername", "Beschreibung"}
        Dim daten = GetData(columnsToUse)

        ' You could use different text for the headers if required.
        WriteCsvFiles(destinationFolder, columnsToUse, daten)

    End Sub

End Class

Чтобы получить 3 файла :

1.csv

formatcount;formatname;printername;Beschreibung
1         ;Hello;World;"Starting ""entry""."

2.csv

formatcount;formatname;printername;Beschreibung
2         ;Yellow;Flower;

3.csv

formatcount;formatname;printername;Beschreibung
3         ;Grey;Rock;"Let's have a ; here."

Надеюсь, я оставил достаточно настраиваемых частей, чтобы вы могли изменить его при необходимости.

NB Если запрос изменен для использования параметров, например, вы Возможно, вы захотите превратить 10007% в переменную, тогда вы должны будете использовать параметры SQL, чтобы защитить ее от SQL инъекции.

Относительно добавления столбцов в таблицу данных.

Добавление столбцов - хорошая идея, но вместо добавления строки с дополнительными данными, подобными этой:

daten.Rows.Add(daten.Rows(0).Item("Description"), daten.Rows(0).Item("Description 2"), Anzahl, Format, Drucker)

Вам необходимо добавьте дополнительные данные в каждую строку, например:

For i = 0 To daten.Rows.Count - 1
    daten.Rows(i)("formatcount") = Anzahl
    daten.Rows(i)("formatname") = Format
    daten.Rows(i)("printername") = Drucker
Next
0 голосов
/ 29 января 2020

Исходя из вашего кода, ваша функция ExportCSV должна быть похожа на приведенный ниже код.
Вы ошибаетесь в трактовках параметров. Ваш список массивов содержит типы словарей, а не целочисленные типы.
Также, если ваш список массивов пуст, обратите внимание на подпрограммы при получении данных или композиции запроса и т. Д. c.
Однако взгляните на этот код и попробуйте улучшить это в вашем сценарии.
Я надеюсь, что это может помочь вам.

Function ExportCSV(ByVal Daten As ArrayList, ByVal Pfad As String) As Boolean

    Dim CSVseparator As String = "|"
    Dim intProgressive As Integer = 0

    Try

        For Each mDict As Dictionary(Of String, Object) In Daten
            Using sr As StreamWriter = New StreamWriter(Pfad & "_" & intProgressive)
                Dim row As String = Join(mDict.Values.ToArray, CSVseparator)
                sr.Write(row)
                intProgressive += 1
            End Using
        Next

        Return True

    Catch ex As Exception
        Console.WriteLine(ex.ToString)
    End Try

    Return False
End Function
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...