1

さて、この問題は少し複雑なので、我慢してください。

データでいっぱいのテーブルがあります。テーブル列の1つはEntryDateです。1日に複数のエントリが存在する可能性があります。ただし、それぞれの日の最新のエントリであるすべての行を選択し、そのテーブルのすべての列を選択したいと思います。

列の1つは一意の識別子列ですが、主キーではありません(なぜそこにあるのかわかりません。これは、かなり古いシステムです)。デモンストレーションの目的で、テーブルが次のようになっていると言います。

create table ExampleTable (
    ID int identity(1,1) not null,
    PersonID int not null,
    StoreID int not null,
    Data1 int not null,
    Data2 int not null,
    EntryDate datetime not null
)

主キーはPersonIDとStoreIDにあり、これらは論理的に一意性を定義します。

さて、私が言ったように、私はその特定の日の最新のエントリであるすべての行を選択したいと思います(Person-Storeの組み合わせごとに)。これは非常に簡単です。

--Figure 1
select PersonID, StoreID, max(EntryDate)
from ExampleTable
group by PersonID, StoreID, dbo.dayof(EntryDate)

ここで、dbo.dayof()は、日時から時間コンポーネントを取り除く単純な関数です。ただし、これを行うと、残りの列が失われます。他の列を単純に含めることはできません。そうすると、group byそれらを含める必要があり、間違った結果が生成されるためです(特に、IDが一意であるため)。

私は自分がやりたいことをする汚いハックを見つけましたが、もっと良い方法があるはずです-これが私の現在の解決策です:

select
    cast(null as int) as ID,
    PersonID,
    StoreID,
    cast(null as int) as Data1,
    cast(null as int) as Data2,
    max(EntryDate) as EntryDate
into #StagingTable
from ExampleTable
group by PersonID, StoreID, dbo.dayof(EntryDate)

update Target set
    ID = Source.ID,
    Data1 = Source.Data1,
    Data2 = Source.Data2,
from #StagingTable as Target
inner join ExampleTable as Source
    on Source.PersonID = Target.PersonID
   and Source.StoreID = Target.StoreID
   and Source.EntryDate = Target.EntryDate

これで正しいデータが得られます#StagingTableが、よく見てください。null値を使用してテーブルを作成し、更新を実行して値を元に戻します。これを行うためのより良い方法は確かにありますか?初めてすべての値を取得する単一のステートメント?

selectそのオリジナル(図1)に正しく結合すると、自己結合などのトリックが実行されると私は信じています...しかし、このgroup by句をどのように使用しますか?クエリを実行するための正しい構文が見つかりません。

私はSQLにかなり慣れていないので、明らかな何かが欠けている可能性があります。助言がありますか?

(違いが生じる場合は、T-SQLでの作業)

4

1 に答える 1

2

本当に「エレガントな」方法はありません。このような Group By クエリをグループ化すると、サブクエリまたは一時テーブルが作成されます。

これはうまくいきます:

Select ID, A.PersonID, A.StoreID, Data1, Data2, A.EntryDate
From ExampleTable As A
Inner Join
    (select PersonID, StoreID, max(EntryDate) As EntryDate
    from ExampleTable
    group by PersonID, StoreID, dbo.dayof(EntryDate)) As B
  On ExampleTable.PersonID = B.PersonID 
    And ExampleTable.StoreID = B.StoreID 
    And ExampleTable.EntryDate = B.EntryDate

ただし、思いついたソリューションに過度に落ち込むべきではありません。一時テーブルの使用は決してエレガントに見えませんが、効率的です。元の 2 段階のソリューションが実際に私の 1 段階のソリューションよりも高速であっても、私は驚かないでしょう。(確実に知るにはテストする必要があります。)

于 2010-03-08T18:22:04.280 に答える