XML ファイルと SqlBulkCopy を使用してデータを挿入しようとしています。宛先テーブルは、次のように設定された時系列テーブルです
create table TimeSeries (
Id uniqueidentifier constraint DF_TimeSeries_Id default (newid()) not null,
ObjectId uniqueidentifier not null,
[Date] datetime not null,
Value float(53) not null,
[Type] varchar (4) not null,
[Source] varchar (4) not null,
LastUpdate datetime constraint DF_TimeSeries_LastUpdate default (getdate()) not null,
TypeIndex smallint constraint DF_TimeSeries_TypeIndex default (0) not null,
constraint PK_TimeSeries primary key clustered ([Date] asc, ObjectId asc, [Type] asc, [Source] asc, TypeIndex asc) with (fillfactor = 80)
);
go
create nonclustered index [IX_TimeSeries_ObjectId_Type_Date_Source]
on TimeSeries(ObjectId asc, [Type] asc, [Date] asc, [Source] asc)
include(Value) with (fillfactor = 80);
go
create nonclustered index [IX_TimeSeries_ObjectId_Date]
on TimeSeries(ObjectId asc, [Date] asc)
include(Value) with (fillfactor = 80);
go
create table Beacons
(
BeaconId uniqueidentifier not null default newid(),
[Description] varchar(50) not null,
LocationX float not null,
LocationY float not null,
Altitude float not null
constraint PK_Beacons primary key clustered (BeaconId)
)
go
create index IX_Beacons on Beacons (BeaconId)
go
create table SnowGauges
(
SnowGaugeId uniqueidentifier not null default newid(),
[Description] varchar(50) not null
constraint PK_SnowGauges primary key clustered (SnowGaugeId)
)
go
create index IX_SnowGauges on SnowGauges (SnowGaugeId)
go
insert into Beacons ([Description], LocationX, LocationY, Altitude)
values ('Dunkery', 51.162, -3.586, 519), ('Prestwich', 53.527, -2.279, 76)
insert into SnowGauges ([Description]) values ('Val d''Isère')
select * from Beacons
select * from SnowGauges
ご覧のとおり、あらゆる種類の時系列を TimeSeries に格納したいと考えています。これは、温度、圧力、生物学的データなどです。いずれにせよ、一意の識別子、ソース、およびタイプによって時系列を識別できます。この一意の識別子は任意のテーブルを参照できるため、ObjectId に設定された外部キーはありません。
このスクリプトの最後に、2 つのビーコンと 1 つのスノーゲージを挿入し、それらの時系列を埋めたいと思います。そのための XML ファイルの形式は次のとおりです。
<?xml version="1.0" encoding="utf-8" ?>
<TimeSeries>
<TimeSeries ObjectId="186CA33E-AC1C-4220-81DE-C7CD32F40C1A" Date="09/06/2013 07:00:00" Value="9.2" Source = "Met Office" Type = "Temperature"/>
<TimeSeries ObjectId="186CA33E-AC1C-4220-81DE-C7CD32F40C1A" Date="09/06/2013 10:00:00" Value="8.8" Source = "Met Office" Type = "Temperature"/>
<TimeSeries ObjectId="186CA33E-AC1C-4220-81DE-C7CD32F40C1A" Date="09/06/2013 13:00:00" Value="8.7" Source = "Met Office" Type = "Temperature"/>
<TimeSeries ObjectId="186CA33E-AC1C-4220-81DE-C7CD32F40C1A" Date="09/06/2013 07:00:00" Value="1" Source = "Met Office" Type = "UV"/>
<TimeSeries ObjectId="186CA33E-AC1C-4220-81DE-C7CD32F40C1A" Date="09/06/2013 10:00:00" Value="3" Source = "Met Office" Type = "UV"/>
<TimeSeries ObjectId="186CA33E-AC1C-4220-81DE-C7CD32F40C1A" Date="09/06/2013 13:00:00" Value="5" Source = "Met Office" Type = "UV"/>
<TimeSeries ObjectId="AFB81E51-18B0-4696-9C2F-E6E9EEC1B647" Date="09/06/2013 07:00:00" Value="5.8" Source = "Met Office" Type = "Temperature"/>
<TimeSeries ObjectId="AFB81E51-18B0-4696-9C2F-E6E9EEC1B647" Date="09/06/2013 10:00:00" Value="6.3" Source = "Met Office" Type = "Temperature"/>
<TimeSeries ObjectId="AFB81E51-18B0-4696-9C2F-E6E9EEC1B647" Date="09/06/2013 13:00:00" Value="6.5" Source = "Met Office" Type = "Temperature"/>
<TimeSeries ObjectId="50E52A2B-D719-4341-A451-110D0874D26D" Date="07/06/2013 00:00:00" Value="80.5" Source = "Meteo France" Type = "SnowMeter"/>
<TimeSeries ObjectId="50E52A2B-D719-4341-A451-110D0874D26D" Date="08/06/2013 00:00:00" Value="80.5" Source = "Meteo France" Type = "SnowMeter"/>
</TimeSeries>
最初のスクリプトを実行すると、ObjectId が異なることが予想され、XML ファイルでそれらを更新する必要があります。したがって、そこからはすべてが簡単で、単純な C# プログラムがデータを挿入するジョブを実行するはずです。C# コードを見てみましょう。
using System;
using System.Data;
using System.Data.SqlClient;
using System.IO;
namespace XMLBulkInsert
{
class Program
{
const string XMLFILE_PATH = @"C:\Workspaces\Ws1\R\TimeSeries\TimeSeries.xml";
const string CONNECTION_STRING = @"Server=RISK1;Database=DevStat;Trusted_Connection=True;";
static void Main(string[] args)
{
StreamReader xmlFile = new StreamReader(XMLFILE_PATH);
DataSet ds = new DataSet();
Console.Write("Read file... ");
ds.ReadXml(xmlFile);
DataTable sourceData = ds.Tables[0];
Console.WriteLine("Done !");
using (SqlConnection sourceConnection = new SqlConnection(CONNECTION_STRING))
{
sourceConnection.Open();
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(sourceConnection.ConnectionString))
{
bulkCopy.ColumnMappings.Add("ObjectId", "ObjectId");
bulkCopy.ColumnMappings.Add("Date", "Date");
bulkCopy.ColumnMappings.Add("Value", "Value");
bulkCopy.ColumnMappings.Add("Source", "Source");
bulkCopy.ColumnMappings.Add("Type", "Type");
bulkCopy.DestinationTableName = "TimeSeries";
try
{
Console.Write("Insert data... ");
bulkCopy.WriteToServer(sourceData);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
xmlFile.Close();
sourceConnection.Close();
}
}
}
Console.WriteLine("Insertion completed, please Press Enter...");
Console.ReadLine();
}
}
}
このプログラムを実行すると、次の例外が返されます。列を一意の識別子にするようにマッピングを設定する方法がないようです。このコードを挿入しようとしましds.Tables[0].Columns[0].DataType = typeof(Guid);
たが、成功しませんでした.Netは、テーブルに行データがあると列のタイプを変更できません。
SQlBulkCopy で大きな例外がありましたが、今は少し行き詰まりを感じています。XML 形式の何百万ものデータがあり、この一意の識別子が原因でそれらのいずれも挿入できません。
一意の識別子を受け入れるためにこのクラスを設定する方法を知っている人はいますか?