0

SQL2005 データベース ファイルに格納する必要がある C#.net のオブジェクト (複数のテキスト ファイルから作成) のリストがあります。残念ながら、テーブル値パラメーターは SQL2008 で始まったため、役に立ちません。MSDN から、「複数のデータ値を区切り文字列または XML ドキュメントにまとめて、それらのテキスト値をプロシージャまたはステートメントに渡す」という方法があることがわかりましたが、ストアド プロシージャは初めてで、それ以上の助けが必要です。ストアド プロシージャを作成して 1 つのレコードを作成し、リストをループして追加できることはわかっていますが、それは避けようとしています。ありがとう。

Input file example (Other files contain pricing and availability):
Matnr   ShortDescription    LongDescription ManufPartNo Manufacturer    ManufacturerGlobalDescr GTIN    ProdFamilyID    ProdFamily  ProdClassID ProdClass   ProdSubClassID  ProdSubClass    ArticleCreationDate CNETavailable   CNETid  ListPrice   Weight  Length  Width   Heigth  NoReturn    MayRequireAuthorization EndUserInformation  FreightPolicyException
10000000    A&D ENGINEERING SMALL ADULT CUFF FOR UA-767PBT  UA-279  A&D ENGINEERING A&D ENG 093764011542    GENERAL General TDINTERNL   TD Internal TDINTERNL   TD Internal 2012-05-13 12:18:43 N       18.000  .350                N   N   N   N
10000001    A&D ENGINEERING MEDIUM ADULT CUFF FOR UA-767PBT UA-280  A&D ENGINEERING A&D ENG 093764046070    GENERAL General TDINTERNL   TD Internal TDINTERNL   TD Internal 2012-05-13 12:18:43 N       18.000  .450                N   N   N   N

いくつかのデータベース ファイル フィールド:

EffectiveDate           varchar(50)
MfgName                 varchar(500)
MfgPartNbr              varchar(500)
Cost                    varchar(200)
QtyOnHand               varchar(200)
4

3 に答える 3

2

単一の文字列から複数の値を非常に簡単に分割できます。「列」を区切るためにコンマを使用し、「行」を区切るためにセミコロンを使用して、次のように文字列をまとめることができるとします。

foo, 20120101, 26; bar, 20120612, 32

(これは、コロンとセミコロンがデータに自然に出現しないことを前提としています。出現する場合は、他の区切り文字を選択する必要があります。)

次のような分割ルーチンを作成できます。これには、元の文字列に表示される値の順序を決定できる出力列が含まれます。

CREATE FUNCTION dbo.SplitStrings
(
    @List       NVARCHAR(MAX),
    @Delimiter  NVARCHAR(255)
)
RETURNS TABLE
AS
    RETURN (SELECT Number = ROW_NUMBER() OVER (ORDER BY Number),
        Item FROM (SELECT Number, Item = LTRIM(RTRIM(SUBSTRING(@List, Number, 
        CHARINDEX(@Delimiter, @List + @Delimiter, Number) - Number)))
    FROM (SELECT ROW_NUMBER() OVER (ORDER BY [object_id])
        FROM sys.all_objects) AS n(Number)
    WHERE Number <= CONVERT(INT, LEN(@List))
        AND SUBSTRING(@Delimiter + @List, Number, 1) = @Delimiter
    ) AS y);
GO

次に、次のようにクエリを実行できます (単純化と説明のために、3 つのプロパティのみを処理していますが、これを 11 または n に推定できます)。

DECLARE @x NVARCHAR(MAX); -- a parameter to your stored procedure

SET @x = N'foo, 20120101, 26; bar, 20120612, 32';

;WITH x AS 
(
    SELECT ID = s.Number, InnerID = y.Number, y.Item 
    -- parameter and "row" delimiter here:
    FROM dbo.SplitStrings(@x, ';') AS s
    -- output and "column" delimiter here:
    CROSS APPLY dbo.SplitStrings(s.Item, ',') AS y
)
SELECT 
    prop1 = x.Item, 
    prop2 = x2.Item, 
    prop3 = x3.Item
FROM x 
INNER JOIN x AS x2 
ON x.InnerID = x2.InnerID - 1
AND x.ID = x2.ID
INNER JOIN x AS x3
ON x2.InnerID = x3.InnerID - 1
AND x2.ID = x3.ID
WHERE x.InnerID = 1
ORDER BY x.ID;

結果:

prop1   prop2     prop3
------  --------  -------
foo     20120101  26
bar     20120612  32
于 2012-06-11T19:45:58.880 に答える
0

このような XML データ型を使用します...

declare @contentXML xml
set @contentXML=convert(xml,N'<ROOT><V a="124694"/><V a="124699"/><V a="124701"/></ROOT>')

SELECT  content_id,
  FROM  dbo.table c WITH (nolock) 
  JOIN @contentXML.nodes('/ROOT/V') AS R ( v ) ON c.content_id = R.v.value('@a', 'INT')

ストアド プロシージャを呼び出すと、次のようになります...

DbCommand dbCommand = database.GetStoredProcCommand("MyStroredProcedure);
database.AddInParameter(dbCommand, "dataPubXML", DbType.Xml, dataPublicationXml);

CREATE PROC dbo.usp_get_object_content
(
    @contentXML XML
)
AS 
BEGIN
    SET NOCOUNT ON

    SELECT  content_id,
      FROM    dbo.tblIVContent c WITH (nolock) 
      JOIN @contentXML.nodes('/ROOT/V') AS R ( v ) ON c.content_id = R.v.value('@a', 'INT')

 END

SQL Server は XML を非常に高速に解析しないため、SplitStrings 関数を使用するとパフォーマンスが向上する場合があります。代替手段を提供したかっただけです。

于 2012-06-11T20:04:44.623 に答える
0

いくつかのオプションを考えることができますが、そのうちの 1 つ (Split オプション) を入力していると、上記の @Bertrand 氏によって投稿されました。唯一の問題は、SQLは文字列操作が得意ではないということです。

したがって、別のオプションは、sproc が存在すると想定する #Temp テーブルを使用することです。次の効果を持つ動的 SQL を作成します。

CREATE TABLE #InsertData必要な形状でトランザクションを開始し、次を使用して、挿入するデータをループします。INSERT INTO #InsertData SELECT <values> UNION ALL SELECT <values>....

このアプローチにはいくつかの制限があります。その 1 つは、データ セットが非常に大きくなると、INSERT をバッチに分割する必要がある場合があることです。(私がこれを自分で学んだときに発生した特定のエラーを思い出せませんが、値のリストが非常に長い場合、SQL でエラーが発生しました。) ただし、解決策は簡単です。より少ない数の INSERT を生成するだけです。行ごとに。たとえば、10000の 1 ではなく、それぞれINSERT SELECTs1000 の 10 を実行できます。バッチ全体を 1 つのコマンドの一部として渡すこともできます。UNION ALLsINSERT SELECTUNION ALLs

これの利点は (一時テーブルの使用、長いコマンド文字列などのさまざまな欠点があるにもかかわらず)、すべての文字列処理を方程式のはるかに効率的な C# 側にオフロードし、追加の永続データベースを必要としないことです。オブジェクト (Split 関数。繰り返しますが、これらのいずれかを必要としない人がいる場合もあります)?

Split() 関数を使用する場合は、これを T-SQL UDF ではなく SQLCLR 関数にオフロードすることをお勧めします (上記のリンクで示されているパフォーマンス上の理由から)。

最後に、どの方法を選択しても、データに区切り記号を含む文字列を含めることができる場合は、さらに問題が発生することに注意してください (たとえば、Aaron の回答では、データが次の場合に問題が発生します。

'I pity the foo!', 20120101, 26; 'bar, I say, bar!', 20120612, 32

繰り返しになりますが、C# は T-SQL よりも文字列処理に優れているため、これを処理するために T-SQL UDF を使用しない方がよいでしょう。

編集

動的 INSERT オプションについては、次の点に注意してください。

ここでの入力が潜在的に危険な入力であり、使用前にクリーンアップする必要があるかどうかを判断する必要があります。このデータを簡単にパラメーター化することはできないため、これは重要なデータです。この戦略を使用した場所では、データの型についてすでに強力な保証がありました (特に、処理する整数 ID のリストをテーブルにシードするために使用したため、任意ではなく整数を繰り返し処理していました。信頼できない文字列)。同様の保証がない場合は、SQL インジェクションの危険性に注意してください。

于 2012-06-11T20:08:20.287 に答える