1

私は2つのテーブルを持っていてTest1Corr_table

Test1 テーブル作成スクリプト:

CREATE TABLE [dbo].[Test1](
    [id] [bigint] NOT NULL,
    [Country] [varchar](3) NULL,
    [PeriodKey] [varchar](max) NULL,
    [a] [varchar](3) NULL,
    [b] [varchar](3) NULL,
    [c] [varchar](3) NULL
) 

Test1データ:

id  Country  PeriodKey  a   b   c
1   E      201201   1   5   9
1   E      201202   1   5   9
3   G      201203   3   7   11
4   H      201204   4   8   12

Corr_tableスクリプトを作成:

CREATE TABLE [dbo].[corr_table](
    [Country] [varchar](5) NULL,
    [id] [bigint] NULL,
    [Field] [varchar](10) NULL,
    [Value] [varchar](50) NULL,
    [Start_date] [varchar](50) NULL,
    [End_date] [varchar](50) NULL
) 

corr_tableデータ:

Country     id  Field   Value   Start_date  End_date
E            1  a   4       201201  201202
E            1  b   6       201201  201202

さて、このクエリを書くと、

select
    a = case when x.Field = 'a' then x.value else a end,
    b = case when x.Field = 'b' then x.value else b end,
    y.*
from 
    dbo.Test1 y,dbo.corr_table x
where  
     y.id = 1
     and y.Country = 'E'
     and y.PeriodKey in (201201)

次の結果が得られます。

a   b   id  Country  PeriodKey  a   b   c
4   5   1   E    201201         1   5   9
1   6   1   E    201201         1   5   9

一方、私は以下の結果を期待しています:

a   b   id    Country   PeriodKey   a   b   c
4   6   1   E    201201         1   5   9

両方の列が単一の行で更新されないのはなぜですか? 一度に1つの列のみを更新していますが、両方の列を更新する必要があります

つまり、a は 4、b は 6 を 1 行に並べる必要があります。しかし、1つだけ更新するのはなぜですか?

4

2 に答える 2

0

クエリが2行を返す理由

クエリが期待する行ではなく2つの行を返す理由を理解するには、SQLServerがクエリを実行するときに理論的に実行する論理的な手順を理解するのに役立ちます。

最初の論理的なステップは、FROM句を処理することです。クエリは、2つのテーブル間の相互結合を指定し、8行を含む中間仮想テーブル(これを呼び出します)を生成しdbo.Test1ます。dbo.corr_tableV1

ID  COUNTRY PERIODKEY   A   B   C   FIELD   VALUE   START_DATE  END_DATE
1   E   201201  1   5   9   a   4   201201  201202
1   E   201202  1   5   9   a   4   201201  201202
3   G   201203  3   7   11  a   4   201201  201202
4   H   201204  4   8   12  a   4   201201  201202
1   E   201201  1   5   9   b   6   201201  201202
1   E   201202  1   5   9   b   6   201201  201202
3   G   201203  3   7   11  b   6   201201  201202
4   H   201204  4   8   12  b   6   201201  201202

2番目の論理ステップは、WHERE句を処理することです。クエリは、IDが1、国が「E」、PeriodKeyが201201の行のみを渡すように指定しています。中間テーブルの2つの行がこの条件を満たすと、別の中間テーブルにデータが入力されます(これを呼び出しますV2)。

ID  COUNTRY PERIODKEY   A   B   C   FIELD   VALUE   START_DATE  END_DATE
1   E   201201  1   5   9   a   4   201201  201202
1   E   201201  1   5   9   b   6   201201  201202

3番目の最後の論理ステップは、SELECT句を処理することです。クエリでは、2つの新しい列が既存の列の値に基づいて計算され、テーブルのすべての列がa変更されずに返されるように指定されています。SELECT句は基本的に、結果セットの構造を定義する列のリストです。結果セットに含まれる行数は制御されません。この中間テーブル(これを呼びましょう)は、結果セットと同じです。bdbo.Test1V3

a   b   id  Country  PeriodKey  a   b   c
4   5   1   E    201201         1   5   9
1   6   1   E    201201         1   5   9

両方の2つの行にV2は、結果セットに表示されると予想される1つの行の要素が含まれています。これらの列の値はの1つの行からのみコピーされたため、ベーステーブルのすべての列dbo.Test1には同じ値が含まれていますdbo.Test1a最初の列の値は、のb2つの異なる行からコピーされdbo.corr_tableます。

これらの2つの行をグループ化できればV2、期待に一致する1つの行を作成できます。幸い、これはSQLで簡単に表現できます。

期待される結果セットを作成する方法

SQLでは、SELECTステートメントにGROUP BY句があり、複数の行をグループを表す1つの行にグループ化します。論理的には、WHERE句の後、SELECT句の前に処理されます。

クエリにGROUPBY句を追加し、計算された列ごとに集計関数を呼び出しました。このクエリは、期待される結果を生成します。

SELECT
  MAX(
    CASE
      WHEN dbo.corr_table.Field = 'a'
      THEN dbo.corr_table.Value
    END
  ) AS corr_a,
  MAX(
    CASE
      WHEN dbo.corr_table.Field = 'b'
      THEN dbo.corr_table.Value
    END
  ) AS corr_b,
  dbo.Test1.*
FROM dbo.Test1
INNER JOIN dbo.corr_table ON
  dbo.Test1.id = dbo.corr_table.id
WHERE
  dbo.Test1.id = 1
  and dbo.Test1.Country = 'E'
  and dbo.Test1.PeriodKey in (201201)
GROUP BY
  dbo.Test1.id,
  dbo.Test1.Country,
  dbo.Test1.PeriodKey,
  dbo.Test1.a,
  dbo.Test1.b,
  dbo.Test1.c;

今は説明する時間がありませんが、なぜこれが機能するのかを説明して、後で答えを拡張します。今のところ、論理クエリ処理とSELECTステートメントについて読むことをお勧めします。Itzik Ben-Ganは、論理的な手順を説明する役立つPDFフローチャートを公開しました。sqlwithmanoj.wordpress.comからコピーした以下の画像として複製されています:

ここに画像の説明を入力してください

于 2012-07-02T13:41:26.167 に答える
0

@marc_s のコメントをより明確にするために、結果の SQL は次のようになります。

select
    a = case when x.Field = 'a' then x.value else a end,
    b = case when x.Field = 'b' then x.value else b end,
    y.*
from 
    dbo.Test1 y
    INNER JOIN dbo.corr_table x ON y.Country = x.Country
where  
     y.id = 1
     and y.Country = 'E'
     and y.PeriodKey in (201201)

また、関係構造が明確になるように、データ モデルの列名をもう少し明示的にする必要があります。結合条件を推測する必要がありました。

于 2012-07-02T13:02:01.807 に答える