1

たとえば、学生が最大10の異なるテストを受けることができ、データベースの各テーブルに1つのテストに対するすべての学生の回答が格納されている調査を行っているとします。テーブルには、各テストにちなんでT1、T2、...、T10という名前が付けられています。各テーブルに、各学生を識別する主キー列「ユーザー名」があるとします。生徒は各テストを完了した場合と完了しなかった場合があるため、各生徒の各テーブルに記録がある場合とない場合があります。

学生ごとに1行(ユーザー名ごとに1行)で、すべてのテーブルからすべてのテストデータを返す正しいSQLクエリは何ですか?正しい結果を返す、可能な限り単純なクエリが必要です。また、最後のクエリでユーザー名フィールドを1つのユーザー名フィールドに統合したいと思います。

明確にするために、SQLには、 「select * [^ ExcludeColumn1][^ExcludeColumn2]」のような1つ以上のフィールドを除くすべての列を選択する構文をサポートしないという大きな制限があることを理解しています。最終クエリですべての列に具体的に名前を付けることを避けるために、RowIDのような名前の合体したユーザー名フィールドが最初に含まれている限り、すべてのユーザー名列をそこに残しておくことができます。

全体的なクエリに関しては、1つのオプションは、10個のテーブルすべてのユーザー名列ですべてユニオンを実行し、次にすべてのテーブルで個別のユーザー名を選択し、10個のテーブルすべてで個別のユーザー名のリストに対して一連の左結合を実行することです。 。その結果、各左結合が同じ個別のユーザー名のセットに対して実行される非常に単純なクエリになりますが、個別のユーザー名に対する個別の事前クエリは避けたいと思います。(それが最善の選択肢である場合でも、私に知らせてください)。次のようになります。

select * from
(select distinct coalesce(t1.Username,t2.Username,...,t10.Username) as RowID from t1,t2,t3,t4,t5,t6,t7,t8,t9,t10) distinct_usernames
left join t1 on t1.Username =  distinct_usernames.RowID
left join t2 on t2.Username =  distinct_usernames.RowID
...
left join t10 on t10.Username =  distinct_usernames.RowID

これは短くて簡単に記述できますが、非常に非効率的で、それぞれ5000行以上のテストテーブルで実行するには数時間かかるため、調整すると、数秒で実行される同等のバージョンは次のようになります。

select * from (
select distinct Username as RowID from (
select Username from t1
union all
select Username from t2
union all
...
select Username from t10
) all_usernames) distinct_usernames
left join t1 on t1.Username = distinct_usernames.RowID
left join t2 on t2.Username = distinct_usernames.RowID
...
left join t10 on t10.Username = distinct_usernames.RowID

上記のクエリが最も効率的で正しいクエリ(実行に数秒しかかからず、正しい結果セットを返す)かもしれないと思いますが、何らかの完全な結合で単純化できるかもしれないと思いました。問題は、完全結合が3つ以上のテーブルと混同されることです。これは、ユーザー名を事前に決定しないと、後続の各テーブルが先行するテーブルのいずれかとレコードを照合する必要があり、追加の各テーブルに「[previoustable count]+1"ユーザー名の一致に関する条件。

4

1 に答える 1

2

それが各テーブルで一意であると仮定するとUsername、2番目のクエリは、私が最初に試す方法ですが、削除distinctして単純に使用するunion(これは別個のものを意味します)というわずかな変更を加えたものunion allです。

select *
from (
        select Username from t1
        union
        select Username from t2
        union
        -- ...
        select Username from t10
    ) distinct_usernames
    left join t1 on t1.Username = distinct_usernames.Username
    left join t2 on t2.Username = distinct_usernames.Username
    -- ...
    left join t10 on t10.Username = distinct_usernames.Username

そこから、ユーザー名がインデックスに登録されていることを確認します。おそらく、クラスター化されたインデックスとして使用することもできます。また、過去にprocの開始時に一時テーブル(おそらくインデックス付きまたはインデックス付きビュー)として実装することで最適化の運がありましたdistinct_usernamesが、それが価値があるかどうかを判断するのはテストだけです。

完全な外部結合には、一連のor条件またはcoalesce引数が必要ですが、パフォーマンスがそこにあるかどうかを確認するために、いくつかのテーブルを試してみる価値があるかもしれません。私はあなたのクエリエンジンが何を最も好むかを推測することはできません。

また、必要な列名だけを取得するには、クエリを使用するsys.columnsinformation_schema.columns動的SQLを使用してクエリを文字列として作成し、それを実行します。

于 2013-02-25T20:21:35.590 に答える