7

必要な行を返すクエリがあります。例:

QuestionID  QuestionTitle  UpVotes  DownVotes  
==========  =============  =======  =========  
2142075     Win32: Cre...        0          0  
2232727     Win32: How...        2          0  
1870139     Wondows Ae...       12          0  

ここで、「作成者」(元のポスターや編集者など)のコンマ区切りのリストを含む列を返したいと思います。例えば:

QuestionID  QuestionTitle  UpVotes  DownVotes  Authors
==========  =============  =======  =========  ==========
2142075     Win32: Cre...        0          0  Ian Boyd  
2232727     Win32: How...        2          0  Ian Boyd, roygbiv
1870139     Wondows Ae...       12          0  Ian Boyd, Aaron Klotz, Jason Diller, danbystrom


フェイキング・イット

SQL Server 2000には集計操作がありませんCONCAT(AuthorName, ', ')。私はそれを偽造してきました。作成TOP 1者と作成者数に対して、単純な副選択を実行します。

QuestionID  QuestionTitle  UpVotes  DownVotes  FirstAuthor  AuthorCount  
==========  =============  =======  =========  ===========  =========== 
2142075     Win32: Cre...        0          0  Ian Boyd               1 
2232727     Win32: How...        2          0  Ian Boyd               2
1870139     Wondows Ae...       12          0  Ian Boyd               3

複数の作成者がいる場合は、ユーザーに省略記号( "…")を表示して、複数の作成者がいることを示します。たとえば、ユーザーには次のように表示されます。

QuestionID  QuestionTitle  UpVotes  DownVotes  Authors
==========  =============  =======  =========  ==========
2142075     Win32: Cre...        0          0  Ian Boyd
2232727     Win32: How...        2          0  Ian Boyd, …
1870139     Wondows Ae...       12          0  Ian Boyd, …

通常、質問は編集されないため、これで十分に機能します。つまり、99%のケースを完全にサポートし、1%のケースも半分しかサポートしていませ


スレッド化された再クエリ

より複雑でバグが発生しやすい解決策として、表示されたリストを繰り返し、リスト内の「質問」ごとにスレッドプールワーカースレッドを起動し、データベースに対してクエリを実行して作成者のリストを取得することを考えていました。 、次にリストをメモリに集約します。これは、リストが(ネイティブ)アプリケーションで最初に入力されることを意味します。その後、数千の個別のクエリを発行します。

しかし、それは恐ろしく、恐ろしく、ひどく、遅いでしょう。スレッドワークになるので、バグだらけは言うまでもありません。


うんうんうん

アダムメカニックは非常に明白に言います

SQL Serverでは、行を区切り文字列に連結しないでください。クライアント側で行います。

方法を教えてください、そして私はそれをします。


/泣く

私の元の「TOP1plusellipses」ソリューションと同じくらい速い(たとえば、1桁以内)より良いソリューションを誰かが考えることができますか?

たとえば、リーチ行に結果セットが関連付けられている結果セットを返す方法はありますか?したがって、「マスター」行ごとに、リストを含む「詳細」結果セットを取得できます。


ベストアンサーのコード

アダム・マハニックのソリューションへのケイドのリンクは私が一番好きです。魔法を介して動作するように見えるユーザー定義関数:

CREATE FUNCTION dbo.ConcatAuthors(@QuestionID int)
RETURNS VARCHAR(8000)
AS
BEGIN
    DECLARE @Output VARCHAR(8000)
    SET @Output = ''

    SELECT @Output =    CASE @Output 
                WHEN '' THEN AuthorName 
                ELSE @Output + ', ' + AuthorName 
                END
    FROM  (
        SELECT QuestionID, AuthorName, QuestionDate AS AuthorDate FROM Questions
        UNION
        SELECT QuestionID, EditorName, EditDate FROM QuestionEdits
    ) dt
    WHERE dt.QuestionID = @QuestionID
    ORDER BY AuthorDate

    RETURN @Output
END

T-SQLの使用法は次のとおりです。

SELECT QuestionID, QuestionTitle, UpVotes, DownVotes, dbo.ConcatAuthors(AuthorID)
FROM Questions
4

4 に答える 4

3

これらの記事を見てください:

http://dataeducation.com/rowset-string-concatenation-which-method-is-best/

http://www.simple-talk.com/sql/t-sql-programming/concatenating-row-values-in-transact-sql/(応答のPhilFactorのクロス結合ソリューションを参照してください-SQLServer2000で機能します)。

明らかに、SQL Server 2005では、FOR XMLのトリックが最も簡単で、最も柔軟性があり、一般的に最もパフォーマンスが高くなっています。

各行の行セットを返す限り、何らかの理由でそれを実行したい場合は、ストアドプロシージャで実行できますが、クライアントは最初の行セットのすべての行を消費してから、次の行に移動する必要があります。行セットを作成し、最初の行セットの最初の行に関連付けます。SPは、最初の行セットと同じセットでカーソルを開き、複数の選択を順番に実行して、すべての子行セットを生成する必要があります。これは私が行った手法ですが、すべてのデータが実際に必要な場合にのみ(たとえば、完全に入力されたツリービューで)。

そして、人々が何を言おうと、クライアント側でそれを行うことは、多くの場合、帯域幅の非常に大きな浪費です。なぜなら、すべての行を返し、クライアント側でループとブレークを行うことは、開始時に膨大な数の同一の列が転送されることを意味するからです。各行は、行の最後にある変化する列を取得するためだけのものです。

どこでそれを行うにしても、それはあなたのユースケースに基づいた情報に基づいた決定でなければなりません。

于 2010-03-09T16:15:27.047 に答える
1

私はこのソリューションへの3つのアプローチを試しました。1つはここに投稿されたもの、activexスクリプトとUDF関数です。

私にとって(速度的に)最も効果的なスクリプトは、追加のデータを連結するために複数のクエリを実行する奇妙なAxtive-Xスクリプトでした。

UDFの変換には平均22分かかり、Subqueryメソッド(ここに投稿)は約5m、activeXスクリプトは4m30かかりました。これは、私が捨てたいと思っていたスクリプトであったため、非常に煩わしいものでした。他の場所でさらにいくつかの効率を上げることができるかどうかを確認する必要があります。

私のスクリプトではによる順序付けが必要なため、余分な30は、データの格納に使用されているtempdbによって使用されていると思います。

大量のテキストデータを連結していることに注意してください。

于 2011-11-10T13:21:39.680 に答える
0

これがSQLServer2000で機能するかどうかはわかりませんが、試すことができます。

--combine parent and child, children are CSV onto parent row
CREATE TABLE #TableA (RowID int, Value1 varchar(5), Value2 varchar(5))
INSERT INTO #TableA VALUES (1,'aaaaa','A')
INSERT INTO #TableA VALUES (2,'bbbbb','B')
INSERT INTO #TableA VALUES (3,'ccccc','C')

CREATE TABLE #TableB (RowID int, TypeOf varchar(10))
INSERT INTO #TableB VALUES (1,'wood')
INSERT INTO #TableB VALUES (2,'wood')
INSERT INTO #TableB VALUES (2,'steel')
INSERT INTO #TableB VALUES (2,'rock')
INSERT INTO #TableB VALUES (3,'plastic')
INSERT INTO #TableB VALUES (3,'paper')


SELECT
    a.*,dt.CombinedValue
    FROM #TableA        a
        LEFT OUTER JOIN (SELECT
                             c1.RowID
                                 ,STUFF(
                                          (SELECT
                                               ', ' + TypeOf
                                               FROM (SELECT
                                                         a.RowID,a.Value1,a.Value2,b.TypeOf
                                                         FROM #TableA                 a
                                                             LEFT OUTER JOIN #TableB  b ON a.RowID=b.RowID
                                                    ) c2
                                               WHERE c2.rowid=c1.rowid
                                               ORDER BY c1.RowID, TypeOf
                                               FOR XML PATH('') 
                                          )
                                          ,1,2, ''
                                       ) AS CombinedValue
                             FROM (SELECT
                                       a.RowID,a.Value1,a.Value2,b.TypeOf
                                       FROM #TableA                 a
                                           LEFT OUTER JOIN #TableB  b ON a.RowID=b.RowID
                                  ) c1
                             GROUP BY RowID
                        ) dt ON a.RowID=dt.RowID

SQL Server 2005からの出力:

RowID       Value1 Value2 CombinedValue
----------- ------ ------ ------------------
1           aaaaa  A      wood
2           bbbbb  B      rock, steel, wood
3           ccccc  C      paper, plastic

(3 row(s) affected)

FORXMLPATHをFORXMLRAWに置き換えるEDITクエリ。これは、SQLServer2000で機能するはずです。

SELECT
    a.*,dt.CombinedValue
    FROM #TableA        a
        LEFT OUTER JOIN (SELECT
                             c1.RowID
                                 ,STUFF(REPLACE(REPLACE(
                                          (SELECT 
                                               ', ' + TypeOf as value
                                               FROM (SELECT
                                                         a.RowID,a.Value1,a.Value2,b.TypeOf
                                                         FROM #TableA                 a
                                                             LEFT OUTER JOIN #TableB  b ON a.RowID=b.RowID
                                                    ) c2
                                               WHERE c2.rowid=c1.rowid
                                               ORDER BY c1.RowID, TypeOf
                                               FOR XML RAW
                                          )
                                         ,'<row value="',''),'"/>','')
                                   , 1, 2, '') AS CombinedValue
                             FROM (SELECT
                                       a.RowID,a.Value1,a.Value2,b.TypeOf
                                       FROM #TableA                 a
                                           LEFT OUTER JOIN #TableB  b ON a.RowID=b.RowID
                                  ) c1
                             GROUP BY RowID
                        ) dt ON a.RowID=dt.RowID

OUTPUT、元のクエリと同じ

于 2010-03-09T16:42:34.403 に答える
0

このスクリプトもご覧ください。これは基本的に、CadeRouxが彼の投稿で言及したクロスジョインアプローチです。

上記のアプローチは非常にわかりやすく見えます。最初にビューを実行し、次にビューの値に基づいてステートメントを作成する必要があります。コードで動的に作成できる2番目のSQLステートメントは、簡単に使用できるはずです。

于 2010-03-09T16:44:21.160 に答える