
Originariamente inviata da
nman
........ adesso vado a dormire domani sera ti faccio sapere come è finita
Mi ci sono dovuto intestardire per farlo funzionare
premesso che il BULKINSERT specifico di SQLServer potrebbe essere la strada più corretta ma che io non ho preso in considerazione
per fare quel lavoro diversamente potresti usare Access,
ma non inteso come DB bensi solamente come depositario del codice necessario
(in effetti basterebbe solamente un file .vbs )
costruisciti questa demo:
1°)
la tabella di SQLServer che ricevera i dati
codice:
USE [Test]
GOSET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[T1](
[c1Id] [int] NOT NULL,
[c2dtm] [datetime] NULL,
[c3nvr] [nvarchar](50) NULL,
[c4nvr] [nvarchar](50) NULL,
[c5nvr] [nvarchar](50) NULL,
[c6nvr] [nvarchar](50) NULL,
[c7nvr] [nvarchar](50) NULL,
[c8nvr] [nvarchar](50) NULL,
CONSTRAINT [PK_T1] PRIMARY KEY CLUSTERED
(
[c1Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
2°)
Il file .txt di 3.6 GB lo ho creato e riempito via codice (Access)
questo ti crea un file di nome "Prova.txt" nella stessa cartella in cui risiede il file di Access
(i commenti e spiegazioni sono gia nel codice)
codice:
Public Sub CreaTxt()
' creo nella cartella corrente un file di nome "Prova.txt"
' che contiene 25.000.000 di record ( sono circa 3.6 GB )
' La numerazione va da 10.000.001 a 35.000.000 per rispettare
' la lunghezza delle stringhe per la successiva suddivisione in campi
' Attenzione non ho fatto il controllo di esistenza,
' quindi se hai gia un file di nome "Prova.txt" verra sovrascritto
Dim x As Long
Dim i As Long ' inizio numerazione 10.000.001
i = 10000001
Dim f As Long ' Fine numerazione 35.000.000
f = 35000000
' NB Per i primi test mettici magari 11000000 come valore di f
Open CurrentProject.Path & "\Pova.txt" For Output As #1
For x = i To f
Print #1, x & " " & Now() & " " & String(19, "a") & " " & String(19, "b") & " " & String(19, "c") & " " & String(19, "d") & " " & String(19, "e") & " " & String(19, "f")
Next x
Close #1
' Sono necessari alcuni minuti
MsgBox ("Fatto :) ")
End Sub
3°)
Per trasferite dal txt a SQLServer ho abbandonato tutto quanto implica la apertura totale del .txt
perché sulla mia nacchinina con 2GB di ram non potevo
pertanto solo del codice con 2 cicli che legge il .txt a blocchi di 300 record ne impacchetta una query di INSERT e la spedisce a mezzo di un PassTrought al SQL
(al solito i commenti e spiegazioni sono nel codice)
codice:
Public Sub Inse4()
Dim Start As Date ' questo serve solo per il calcolo del tempo
Start = Now
' Il modello della stringa di query che devo costruire
' INSERT INTO [dbo].[T1] ([c1Id] ,[c2dtm], [c3nvr], [c4nvr], [c5nvr], [c6nvr], [c7nvr], [c8nvr]) VALUES
' (10000000, N'2016-08-08 12:47:24', N'u3u', N'u4u', N'u5u', N'u6u',N'u7u', N'u8u'),
' (10000000, N'2016-08-08 12:47:24', N'u3u', N'u4u', N'u5u', N'u6u',N'u7u', N'u8u'),
' (10000000, N'2016-08-08 12:47:24', N'u3u', N'u4u', N'u5u', N'u6u',N'u7u', N'u8u')
' ;
' Definisco E PERSONALIZZO la connessione al DB
Dim Connes As String
Connes = "ODBC;DRIVER=SQL Server;SERVER=NomeServer;UID=yyy;PWD=xxxxx;DATABASE=Test"
' Definisco una query (in memoria) con cui inseriro i miei record
Dim Q As DAO.QueryDef
Set Q = DBEngine.Workspaces(0).Databases(0).CreateQueryDef("")
Q.ReturnsRecords = False
Q.Connect = Connes
Dim txtRec As String ' Il testo del record processato ( Ancora Senza distinzione di campi )
Dim n As Integer ' il numeratore del ciclo For Next
n = 1
Dim s As String ' la stringa SQL di INSERT
Dim p As Integer ' la dimensione del pacco di record ( il massimo del ciclo For Next )
p = 300 ' 300
' Necessario testare la query in relazioni alle dimensioni dei "pacchi" di record che si spediscono
' fare pacchi da 1 significa attivare 25.000.000 di volte la INSERT
' fare pacchi da 10.000 significa che il pacco ( anche in funzione delle dimensioni dei record )
' supera la capacita della RAM o delle stringhe
' Devi fare alcuni Test con i dati effettivi e massimizzare
' il pacco senza subire in errori ( 3035 Riserve di sistema insufficienti )
' apriamo il file .txt
Open CurrentProject.Path & "\Pova.txt" For Input As #1
' ora facciamo il 1° ciclo su tutti i 25.000.000 di record del .txt
' il secondo ciclo quando il pacco è pieno provvede alla INSERT
Do Until EOF(1) '1° ciclo inizio ----------------------------------
s = "INSERT INTO [dbo].[T1] ([c1Id] ,[c2dtm], [c3nvr], [c4nvr], [c5nvr], [c6nvr], [c7nvr], [c8nvr]) VALUES " & vbNewLine
Do Until n > p Or EOF(1) '2° ciclo inizio ---------------------------------
Input #1, txtRec ' Leggo 1 riga
s = s & "("
' Qui separo la riga del .txt in campi
s = s & "" & CLng(Mid(txtRec, 1, 8)) & ", "
s = s & "N'" & Format((CDate(Mid(txtRec, 10, 19))), "yyyy-dd-mm hh:nn:ss") & "', "
' non sono sicurissimo sulla formattazione, ma è una demo
s = s & "N'" & Mid(txtRec, 30, 19) & "', "
s = s & "N'" & Mid(txtRec, 50, 19) & "', "
s = s & "N'" & Mid(txtRec, 70, 19) & "', "
s = s & "N'" & Mid(txtRec, 90, 19) & "', "
s = s & "N'" & Mid(txtRec, 110, 19) & "', "
s = s & "N'" & Mid(txtRec, 130, 19) & "'"
' Fine della separazione in campi
s = s & "), " & vbNewLine
n = n + 1
Loop '2° ciclo fine ---------------------------------
n = 1
' chiudo la stringa sql e inserto
s = Left(s, ((InStrRev(s, ",")) - 1)) & vbNewLine & ";"
'Debug.Print s
Q.SQL = s
'Stop
Q.Execute
Loop '1° ciclo fine ----------------------------------
' chiudo tutto
Close #1
Q.Close
MsgBox ("Fatto in " & ((Now() - Start) * 1440) & " minuti")
End Sub
Facci sapere