SQL SERVER:用于从表中获取最小值和最大值的视图

时间:2009-07-03 13:06:02

标签: sql

我有一个像这样的MSSQL Server表:

id (auto-increment)
amount
date
account_id

全天插入数据。我现在需要一个视图来获取每天每个帐户的期初和期末金额。 我的麻烦是创建一个快速查询来访问最小值和最大值。 使用in语句创建一个只能访问最小值的视图很好,但是获得最小值和最大值都很棘手。我尝试过使用with子句,但查询速度非常慢。

BTW我将视图映射到hibernate,因此存储过程和函数将不会以相同的方式工作(我知道)。

更新 我想从我收到的回复中我的问题并不清楚。我想获得每个帐户的期初和期末余额。最大值和最小值是指按日期和account_id分组时获取最大值和最小值(id)。 我希望在id等于最大ID(期末余额)时获得金额,以及当id等于每个帐户每天的最小ID(期初余额)时的金额。

5 个答案:

答案 0 :(得分:1)

SELECT account_id, date, MIN(amount), MAX(amount)
FROM <table>
GROUP BY account_id, date

你的问题肯定有些缺失。

答案 1 :(得分:1)

这样做,没有足够的数据来评估性能:

create table #accounts
   (
   id           integer identity,
   account_id   integer,
   amount       decimal(18,3),
   tran_date    datetime
   )
go

insert into #accounts values (1,124.56,'06/01/2009 09:34:56');
insert into #accounts values (1,125.56,'06/01/2009 10:34:56');
insert into #accounts values (1,126.56,'06/01/2009 11:34:56');

insert into #accounts values (2,124.56,'06/01/2009 09:34:56');
insert into #accounts values (2,125.56,'06/01/2009 10:34:56');
insert into #accounts values (2,126.56,'06/01/2009 11:34:56');

insert into #accounts values (3,124.56,'06/01/2009 09:34:56');
insert into #accounts values (3,125.56,'06/01/2009 10:34:56');
insert into #accounts values (3,126.56,'06/01/2009 11:34:56');

insert into #accounts values (4,124.56,'06/01/2009 09:34:56');
insert into #accounts values (4,125.56,'06/01/2009 10:34:56');
insert into #accounts values (4,126.56,'06/01/2009 11:34:56');

insert into #accounts values (1,124.56,'06/02/2009 09:34:56');
insert into #accounts values (1,125.56,'06/02/2009 10:34:56');
insert into #accounts values (1,126.56,'06/02/2009 11:34:56');

insert into #accounts values (2,124.56,'06/02/2009 09:34:56');
insert into #accounts values (2,125.56,'06/02/2009 10:34:56');
insert into #accounts values (2,126.56,'06/02/2009 11:34:56');

insert into #accounts values (3,124.56,'06/02/2009 09:34:56');
insert into #accounts values (3,125.56,'06/02/2009 10:34:56');
insert into #accounts values (3,126.56,'06/02/2009 11:34:56');

insert into #accounts values (4,124.56,'06/02/2009 09:34:56');
insert into #accounts values (4,125.56,'06/02/2009 10:34:56');
insert into #accounts values (4,126.56,'06/02/2009 11:34:56');
go

select
   ranges.tran_day      transaction_day,
   ranges.account_id    account_id,
   bod.amount           bod_bal,
   eod.amount           eod_bal
from
   -- Subquery to define min/max records per account per day
   (
   select
      account_id,
      cast(convert(varchar(10),tran_date,101) as datetime) tran_day,
      max(id) max_id,
      min(id) min_id
   from
      #accounts
   group by
      account_id,
      cast(convert(varchar(10),tran_date,101) as datetime)
   ) ranges

   -- Beginning of day balance
   JOIN #accounts bod
      on (bod.id = ranges.min_id)

   -- End of day balance
   JOIN #accounts eod
      on (eod.id = ranges.max_id)
go

如果您需要更好的性能,请先将子查询存储到临时表中,然后为其添加索引以进行连接...这可能会加快它的速度。

答案 2 :(得分:0)

根据John Saunders的回答和Jeremy的评论:

SELECT account_id, date, MIN(amount), MAX(amount)
FROM <table>
GROUP BY account_id, DatePart( Year, date ),DatePart( Month, date ), DatePart( Day, date )

答案 3 :(得分:0)

基本上我需要以下查询,但with语句会导致它运行缓慢:

with x as (
 select 
  MAX(ab.id) as maxId, MIN(ab.id) as minId
 from Balance ab
 group by ab.account_id, dbo.Get_PeriodDateFromDatetime(ab.StatementDate)
)
select 
  ab.Amount as openingBalance, ab2.Amount as closingBalance
from Balance ab, Balance ab2, x
where ab.id = x.maxId and ab2.id = x.minId

答案 4 :(得分:0)

我不知道这是否有所改善,但您发布的查询看起来缺少某些部分,例如“with”查询中的account_id和主要部分中的account_id上的连接:

with x as (
 select 
  ab.account_id, MAX(ab.id) as closeId, MIN(ab.id) as openId
 from Balance ab
 group by ab.account_id, dbo.Get_PeriodDateFromDatetime(ab.StatementDate)
)
select 
  opbal.account_id, opbal.StatementDate,
  opbal.Amount as openingBalance, clsbal.Amount as closingBalance
from Balance opbal, Balance clbal, x
where clsbal.id = x.closeId 
and clsbal.ccount_id = x.account_id
and opbal.id = x.openId
and op.account_id = x.account_id

我有点担心对dbo.Get_PeriodDateFromDatetime(ab.StatementDate)的调用:如果你有一个关于account_id和StatementDate的索引(你确实有那个索引,不是吗?它看起来像是一个很好的候选人也是一个聚集索引,然后它可能不是太糟糕,除非表格很大。

顺便说一下,“慢”的速度有多慢?