質問

私は次のような列が付いたテーブルを持っています(古いテーブルと呼んでいます):

id(int)、rank(int)、textlineNumber(int)、sometext(varchar)

PrimaryKeyはマルチパートです:id+rank+textlineNumber。

私はそれを別のテーブルに変換/結合しようとしています(newtableと呼んで)。

id(int)、rank(int)、combinedtext(varchar)

主キーはID+ランクです。

新しいテーブルのIDとランクはすでに埋め込まれていますが、Newtableの複合テキスト列を次の考慮事項で更新するクエリが必要です。

  1. 新しいテーブルに与えられたランクは古いテーブルに存在しない可能性があります。その場合、新しいテーブルのランクよりも大きくない古いテーブルから利用可能な最高のランクを選択する必要があります。
  2. CombinedText列は、最初の考慮事項から見つかったランクを使用して「TextLineNumber」の順に連結された古いテーブルの「sometext」列の文字列の連結です。

これがデータの例です。

年-http://i54.tinypic.com/jq0vmx.png

新着-http://i53.tinypic.com/dhfyn8.png

それが重要な場合は、MSSQL 2005を使用しています。私は現在、T-SQLとループ中にこれを行いますが、それは深刻なパフォーマンスボトルネックになります(10000列に約1分かかります)。

編集:CSVの拡張例データ:
年:

ID,Rank,LineNumber,SomeText
1,1,1,the qu  
1,1,2,ick br  
1,1,3,own  
1,2,1,some te  
1,2,2,xt  
1,3,1,sample  
2,7,1,jumped ov  
2,7,2,er the  
2,7,3,lazy  
2,13,1,samp  
2,13,2,le text  
3,1,1,ABC  
3,1,2,DEF  
3,1,3,GHI  
3,1,4,JKL  
3,50,1,XYZ

新しい:

ID,Rank,CombinedText
1,2,some text
2,13,sample text
2,14,sample text
3,4,ABCDEFGHIJKL
3,5,ABCDEFGHIJKL
3,50,XYZ
3,55,XYZ

編集2:
これが私が見つけたクエリの例です。

update newtable set combinedtext = 
coalesce ((select top 1 sometext from OldTable where OldTable.id=newtable.id and oldtable.rank=(select top 1 rank from oldtable where oldtable.id=newtable.id and oldtable.rank<=newtable.rank order by rank desc) and oldtable.linenumber=1),'') +
coalesce ((select top 1 sometext from OldTable where OldTable.id=newtable.id and oldtable.rank=(select top 1 rank from oldtable where oldtable.id=newtable.id and oldtable.rank<=newtable.rank order by rank desc) and oldtable.linenumber=2),'') +
coalesce ((select top 1 sometext from OldTable where OldTable.id=newtable.id and oldtable.rank=(select top 1 rank from oldtable where oldtable.id=newtable.id and oldtable.rank<=newtable.rank order by rank desc) and oldtable.linenumber=3),'') +
coalesce ((select top 1 sometext from OldTable where OldTable.id=newtable.id and oldtable.rank=(select top 1 rank from oldtable where oldtable.id=newtable.id and oldtable.rank<=newtable.rank order by rank desc) and oldtable.linenumber=4),'') +
coalesce ((select top 1 sometext from OldTable where OldTable.id=newtable.id and oldtable.rank=(select top 1 rank from oldtable where oldtable.id=newtable.id and oldtable.rank<=newtable.rank order by rank desc) and oldtable.linenumber=5),'')

また、5の最大線番号を想定していますが、そうではないかもしれません。それが必要な場合は、最大20の最大20までのLinenumbersをハードコーディングすることを気にしませんが、理想的には異なる方法で説明できるでしょう。 20秒未満(実際のデータ)を取得することが目標です...

役に立ちましたか?

解決

これは機能するはずです、私は後でそれをきれいにして、より効率的にします。

DECLARE @Old TABLE ( 
  id         INT, 
  rank       INT, 
  linenumber INT, 
  sometext   VARCHAR(1000)) 
DECLARE @New TABLE ( 
  id           INT, 
  rank         INT, 
  combinedtext VARCHAR(1000)) 


;WITH combinedresults(ctid, id, rank, linenumber, combinedtext) 
     AS (SELECT 0, 
                id, 
                rank, 
                linenumber, 
                CAST (sometext AS VARCHAR(8000)) 
         FROM   @Old o 
         WHERE  NOT EXISTS (SELECT TOP 1 1 
                            FROM   @Old 
                            WHERE  id = o.id 
                                   AND rank = o.rank 
                                   AND linenumber < o.linenumber) 
         UNION ALL 
         SELECT ctid + 1, 
                o.id, 
                o.rank, 
                o.linenumber, 
                ct.combinedtext + o.sometext 
         FROM   @Old o 
                INNER JOIN combinedresults ct 
                  ON ct.id = o.id 
                     AND ct.rank = o.rank 
         WHERE  o.linenumber > ct.linenumber) 

UPDATE n 
SET    combinedtext = ct.combinedtext 
FROM   @New n 
       INNER JOIN (SELECT n.id, 
                          n.rank, 
                          MAX(o.rank) orank 
                   FROM   @new n 
                          INNER JOIN @Old o 
                            ON n.id = o.id 
                               AND o.rank <= n.rank 
                   GROUP  BY n.id, 
                             n.rank) r 
         ON n.id = r.id 
            AND n.rank = r.rank 
       INNER JOIN (SELECT id, 
                          ct.rank, 
                          MAX(ctid) ctid 
                   FROM   combinedresults ct 
                   GROUP  BY ct.id, 
                             ct.rank) r2 
         ON r2.id = r.id 
            AND r2.rank = r.orank 
       INNER JOIN combinedresults ct 
         ON r.id = ct.id 
            AND ct.rank = r.orank 
            AND ct.ctid = r2.ctid 

SELECT * 
FROM   @New 

他のヒント

関数内のカーソルを使用して値を一緒に刺す関数を作成できますが、それはあなたの唯一のオプションに関するものです。これを実現するには、行ごとに処理する必要があります。

私はまだCTEが上手ではないので、カーソルなしでより伝統的なアプローチを使用して、質問に対する私の質問です。

要件#2は、あるカテゴリでグループ化された列の値のコンマ分離された連結を作成する必要があるというプロジェクトを思い出させます。私が使用したソリューションは、提供されたカテゴリIDを使用して連結された文字列を生成するためにUDFを必要としました。

以下は、IDパラメーターとランクパラメーターを使用した適応されたUDFです。

CREATE FUNCTION fnCombinedText
(
    @ID int,
    @Rank int
)
RETURNS varchar(MAX)
AS
BEGIN

DECLARE @CombinedText varchar(MAX)
SET @CombinedText = ''

SELECT @CombinedText = @CombinedText + SomeText
FROM oldTable
WHERE [ID] = @ID 
AND [Rank] = @Rank
ORDER BY [Rank]

RETURN @CombinedText

END

要件#1は、すべての明確な等しいまたはそれ以下のランクでニューテーブルランクをジョーにし、最高/トップマッチを取得することで達成できます。

CREATE TABLE #RankMap
(
    newID int,
    newRank int,
    oldID int,
    oldRank int
)
INSERT INTO #RankMap
SELECT newID, newRank, oldID, oldRank
FROM
(
    SELECT
        n.id AS newID,
        n.rank AS newRank,
        o.id AS oldID,
        o.rank as oldRank,
        RANK() OVER(PARTITION BY n.rank ORDER BY o.rank DESC) AS topRank
    FROM
        newtable AS n 
        LEFT OUTER JOIN (SELECT DISTINCT id, rank FROM oldtable) AS o
            ON n.id = o.id
            AND n.rank >= o.rank
) AS matchEqualLess
WHERE topRank = 1

マッピングされた古いランクができたので、UDFを使用してcombinedTextを生成できます。

SELECT
    newID,
    newRank,
    dbo.fnCombinedText(oldID, oldRank) AS CombinedText
FROM #RankMap

--Below is the resultset:
newID       newRank     CombinedText
----------- ----------- --------------------
1           2           some text
3           4           ABCDEFGHIJKL
3           5           ABCDEFGHIJKL
2           13          sample text
2           14          sample text
3           50          XYZ
3           55          XYZ

このソリューションの主な欠点は、UDF fncombinedText()への各呼び出しが基本的に古いテーブルの個別の選択であることです。このアプローチは、よりスケーラブルなCTEクエリに移植できると思います。そして、私も本当にCTEのマスターに取り掛かるべきだと思います。

ライセンス: CC-BY-SA帰属
所属していません dba.stackexchange
scroll top