0

Char(13)+ Char(10)で区切られた、アドレスが1つのフィールドにある500k行のテーブルがあります。これを分割することを期待して、テーブルに5つのフィールドを追加しました。

オンラインで見つけたこの分割機能parsenameは、5つのパーツがあるために使用できず.、フィールドにある可能性があるため、うまく機能しているようです。

これはテーブル値の関数なので、行をループしてレコードを更新する必要があります。以前はカーソルまたはSQLを使用していましたが、これを行うにはc#を使用していましたが、cteまたはセットベースの回答である必要があります。これを行う。

4

2 に答える 2

3

いくつかのオプションがあります。

一時テーブルを作成し、アドレスを一時テーブルに解析してから、元のテーブルを一時テーブルに結合して更新することができます。

また

独自のT-SQL関数を記述し、次のようにupdateステートメント関数でそれらの関数を使用できます。

UPDATE myTable
   SET address1 = myGetAddress1Function(address),
       address2 = myGetAddress2Function(address)....
于 2013-03-13T15:06:06.150 に答える
3

したがって、いくつかのソースデータが与えられます:

CREATE TABLE dbo.Addresses
(
  AddressID INT IDENTITY(1,1),
  [Address] VARCHAR(255),
  Address1  VARCHAR(255),
  Address2  VARCHAR(255),
  Address3  VARCHAR(255),
  Address4  VARCHAR(255),
  Address5  VARCHAR(255)
);

INSERT dbo.Addresses([Address])
SELECT 'foo
bar'
UNION ALL SELECT 'add1
add2
add3
add4
add5';

アドレス部分を順番に返す関数を作成してみましょう。

CREATE FUNCTION dbo.SplitAddressOrdered
(
    @AddressID  INT,
    @List       VARCHAR(MAX),
    @Delimiter  VARCHAR(32)
)
RETURNS TABLE
AS
    RETURN 
    (
      SELECT  
          AddressID = @AddressID, 
          rn = ROW_NUMBER() OVER (ORDER BY Number), 
          AddressItem = 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, LEN(@Delimiter)) = @Delimiter
      ) AS y
    );
GO

これで、これを実行できます(クエリを5回実行する必要があります)。

DECLARE 
  @i INT = 1, 
  @sql NVARCHAR(MAX),
  @src NVARCHAR(MAX) = N';WITH x AS 
    (
      SELECT a.*, Original = s.AddressID, s.rn, s.AddressItem
      FROM dbo.Addresses AS a
      CROSS APPLY dbo.SplitAddressOrdered(a.AddressID, a.Address, 
        CHAR(13) + CHAR(10)) AS s WHERE rn = @i
    )';
WHILE @i <= 5
BEGIN
   SET @sql = @src + N'UPDATE x SET Address' + RTRIM(@i)
     + ' = CASE WHEN AddressID = Original AND rn = ' 
     + RTRIM(@i) + ' THEN AddressItem END;';

   EXEC sp_executesql @sql, N'@i INT', @i;

   SET @i += 1;
END

Address次に、列を削除できます。

ALTER TABLE dbo.Addresses DROP COLUMN [Address];

次に、テーブルには次のものがあります。

AddressID  Address1  Address2  Address3  Address4  Address5
---------  --------  --------  --------  --------  --------
1          foo       bar       NULL      NULL      NULL
2          add1      add2      add3      add4      add5

ループせずにその機能を利用する方法を紹介するよりも賢い人がいると確信しています。

また、特定の要素を簡単に引き出すことができるように、機能を少し変更することも想像できます...しばらくお待ちください...

編集

これは、それ自体はより高価ですが、5の代わりにテーブルの1つのパスを作成できるスカラー関数です。

CREATE FUNCTION dbo.ElementFromOrderedList
(
    @List       VARCHAR(MAX),
    @Delimiter  VARCHAR(32),
    @Index      SMALLINT
)
RETURNS VARCHAR(255)
AS
BEGIN
    RETURN 
    (
      SELECT Item 
        FROM (SELECT rn = ROW_NUMBER() OVER (ORDER BY 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, LEN(@Delimiter)) = @Delimiter
      ) AS y WHERE rn = @Index
    );
END
GO

上記の表(更新前およびドロップ前)が与えられた場合、更新は単純に次のようになります。

UPDATE dbo.Addresses
  SET Address1 = dbo.ElementFromOrderedList([Address], CHAR(13) + CHAR(10), 1),
      Address2 = dbo.ElementFromOrderedList([Address], CHAR(13) + CHAR(10), 2),
      Address3 = dbo.ElementFromOrderedList([Address], CHAR(13) + CHAR(10), 3),
      Address4 = dbo.ElementFromOrderedList([Address], CHAR(13) + CHAR(10), 4),
      Address5 = dbo.ElementFromOrderedList([Address], CHAR(13) + CHAR(10), 5);
于 2013-03-13T15:32:44.363 に答える