0

私は次のテーブルを持っています

Groups
- Id
- Name

People
- Id
- GroupId
- EntryDate (DateTime)

ここで、最新のグループのPeopleエントリ日付でソートされたすべてのグループを取得したいと思います。

//pseudo code

select * from groups order by (select top 1 from people order by entrydate desc)

グループにLatestEntryDateフィールドを追加し、人が追加されたときにそれを更新する方がよいでしょうか?これは一般的なクエリになるためです。

4

2 に答える 2

2
SELECT g.Id, g.Name, MAX(p.EntryDate) AS LatestPeopleEntryDate
FROM Groups g
    INNER JOIN People p
        ON p.GroupId = g.Id
GROUP BY g.Id, g.Name
ORDER BY MAX(p.EntryDate)

いいえ、テーブルにLatestEntryDateフィールドを追加しません。Groupsこれは簡単に計算できます。

@danihpが指摘したように、ここでは左結合を使用することをお勧めします。上記のクエリでは、Peopleテーブルに値が存在する必要があります。何を使用するかは、特定の要件によって異なります。

SELECT g.Id, g.Name, MAX(p.EntryDate) AS LatestPeopleEntryDate
FROM Groups g
    LEFT JOIN People p
        ON p.GroupId = g.Id
GROUP BY g.Id, g.Name
ORDER BY MAX(p.EntryDate)

アップデート

Linqでこれを行うことについてのあなたの質問に答えるには、次のようになると思います。

var result = groups.Select(g => 
    new {
            g.Id, 
            g.Name, 
            LatestPeopleEntryDate = g.People.Max(p => p.EntryDate)
        });
于 2012-07-07T15:23:08.850 に答える
0

これは、3つのアプローチを示す非常に小さなサンプルデータを使用したテスト例です。

最適なクエリプランを取得するには:

People by(GroupID、EntryDate)に一意でないインデックスを付けます。

A.元の擬似コード(注文は行いますが日付は表示されません)を使用するか、

B.上位1つのサブクエリを使用して、日付を取得して表示します。

AとBのクエリプランは同じです。

Peopleテーブルへの左結合とmax()を使用すると、インデックス内の単一の行をプローブするのではなく、スキャン(GroupID内で最大)が最大値を取得します。

set nocount on
if object_id('Groups') is not null drop table Groups
if object_id('People') is not null drop table People
go

-- set up tables
create table Groups
(
    ID int primary key,
    Name varchar(20)
)

create table People 
(
    ID int,
    GroupID int,
    EntryDate datetime
)
-- make an index that is ordered by Group, EntryDate
create index IE_GroupDate on People(GroupID, EntryDate)

-- Sample data
insert into Groups (ID, Name)
values
    (1, 'Group1'),
    (2, 'Group2'),
    (3, 'GroupC')

insert into People (ID, GroupID, EntryDate)
values 
    (1, 1, '2012-01-01'),
    (2, 1, '2012-02-01'),
    (1, 3, '2007-12-31')

-- Queries
-- Equivalent to the original poster's intent.  Note that it doesn't actually
-- show the entry date
select *
from Groups G
order by (
    select top 1 EntryDate
    from People P
    where P.GroupID = G.ID order by EntryDate desc)

-- Same query (by query plan) but includes the EntryDate in the result set
select
    G.ID,
    G.Name,
    LatestEntryDate = Latest.EntryDate
from Groups G
outer apply (
    select top 1 EntryDate
    from People P
    where P.GroupID = G.ID
    order by EntryDate desc
) Latest
order by LatestEntryDate

-- Query using left join.  This causes a scan of the left join table to
-- compute the max.  (The optimizer isn't smart enough to turn this into 
-- a TOP 1)
select
    G.ID,
    G.Name,
    LatestEntryDate = max(P.EntryDate)
from Groups G
left join People P on P.GroupID = G.ID
group by G.ID, G.Name
order by max(P.EntryDate)
于 2012-07-07T21:54:02.773 に答える