【问题标题】:Top 1 in group by clause in SQL Server?SQL Server 中 group by 子句中的前 1 名?
【发布时间】:2020-07-25 00:04:48
【问题描述】:

我正在创建一个交易平台,我需要从一个表格中带来以下数据:

date, open price, close price, highest price, lowest price, volume, value of volume.

我创建了这个查询:

Select 
    min(Price) as Low,
    max(price) as High,
    sum(Quantity) as Volume,
    sum(Price) as Value,
    dateadd(DAY, 0, datediff(day, 0, CreatedOn)) as Date,
    CompanyIdentifier 
from 
    Transactions 
group by 
    dateadd(DAY, 0, datediff(day, 0, CreatedOn)), CompanyIdentifier

这个查询是为某公司(由CompanyIdentifier标识)在某天(Date)带来最低价格,最高价格,数量和数量的价值。我不能在这个查询中添加的是该公司当天的开盘价和收盘价。基本上是数据按日期升序排列的前 1 个价格。我尝试过并且似乎可以解决问题的是以下查询:

SELECT * 
FROM (select Quantity, PRICE, CompanyIdentifier, 
             dateadd(DAY,0, datediff(day,0, CreatedOn)) AS U, 
             ROW_NUMBER() over(partition by CompanyIdentifier, dateadd(DAY,0, datediff(day,0, CreatedOn)) order by CREATEDON) AS 'COUN' 
      from Transactions
     ) AS AL 
where COUN = 1

但这是 2 个单独的查询,我只想要一个查询。我还尝试添加:

FIRST_VALUE(Price) over (order by price) as first

在第一个查询中,但我收到该函数不在 group by 子句中的错误,我将函数添加到 group by 查询中,我收到以下错误:

窗口函数只能出现在 SELECT 或 ORDER BY 子句中。

那么,如何在第一个查询中添加这两列?

【问题讨论】:

  • 添加一些示例数据以及您的预期输出。
  • 这是我现在收到的:imgur.com/a/u4VSFKZ 我想在这些列旁边再添加 2 列:起始价和收盘价。基本上为每个公司带来第一个价格和最后一个价格每个日期由 CompanyIdentifier 表示(按日期表示)
  • 您没有基于您发布的图片的开盘价或收盘价,因为时间部分始终设置为 00:00。表格中也没有“第一”或“最后”行。根据定义,表中的行没有特定的顺序,当然也不是您可以依赖的。
  • 是的,时间组件设置为 00:00 以便能够按天对数据进行分组。但是在数据库中,时间组件也有小时、分钟和秒。我知道有根据定义,表格中没有顺序,但根据数据字段,我可以按 asc order 或 desc 对它们进行排序并选择 top 1。问题是数据已分组,我无法使用 top 1 函数来获取第一个或最后一个价格一天之内。

标签: sql sql-server


【解决方案1】:

一种方法是使用窗口函数和select distinct:

select distinct t.CompanyIdentifier, v.createdDate,
       min(Price) over (partition by t.CompanyIdentifier, v.createdDate) as Low,
       max(price) over (partition by t.CompanyIdentifier, v.createdDate) as High,
       sum(Quantity) over (partition by t.CompanyIdentifier, v.createdDate) as Volume,
       sum(Price) over (partition by t.CompanyIdentifier, v.createdDate) as Value,
       first_value(Price) over (partition by t.CompanyIdentifier, v.createdDate order by CreatedOn asc) as first_price,   
       first_value(Price) over (partition by t.CompanyIdentifier, v.createdDate order by CreatedOn desc) as last_price   
from Transactions t cross apply
     (values (convert(date, CreatedOn))) v(createdDate)

这是必需的,因为 SQL Server 提供 first_value() 作为窗口函数,但没有类似于聚合函数。

更传统的方法使用条件聚合:

Select t.CompanyIdentifier, t.createdDate,
       min(Price) as Low, max(price) as High,
       sum(Quantity) as Volume, sum(Price) as Value,
       min(case when seqnum_asc = 1 then price end) as first_price,
       min(case when seqnum_desc = 1 then price end) as last_price
from (select t.*,
             createdDate,
             row_number() over (partition by CompanyIdentifier, createdDate order by CreatedOn) as seqnum_asc,
             row_number() over (partition by CompanyIdentifier, createdDate order by CreatedOn desc) as seqnum_desc
      from Transactions t cross apply
           (values (convert(date, CreatedOn))) v(createdDate)
     ) t
group by t.CompanyIdentifier, v.createdDate;

【讨论】:

  • 感谢您的回答。我尝试了这两个查询。第一个错误返回了一个组:选择列表中的“Transactions.Price”列无效,因为它不包含在聚合函数或GROUP BY 子句。第二个有效,但 first_price 和 last_price 相同。我在此处添加了数据库中的屏幕截图:imgur.com/a/xyTfZN4 我尝试调试第二个查询,但坦率地说对我来说相当先进。如果你能给我一些见解,它会很棒:)
  • @WorkoutChannel 。 . .第一个不应该有GROUP BY(这是SELECT DISTINCT 的重点)。第二个需要在排序时使用DESC
【解决方案2】:

FIRST_VALUE() OVER 是一个分析函数,根据我的经验,它们与 GROUP BY 子句不太吻合。

一个简单的解决方法应该是将使用分析函数FIRST_VALUE 的子查询加入到您的表中,收盘价LAST_VALUE 可以解决问题。

Select 
min(Price) as Low,
max(price) as High,
sum(Quantity) as Volume,
sum(Price) as Value,
dateadd(DAY, 0, datediff(day, 0, CreatedOn)) as Date,
analytic.first,
analytic.close
CompanyIdentifier 
from 
Transactions,
(SELECT CompanyIdentifier, FIRST_VALUE(price) OVER (CreatedOn) as first, LAST_VALUE(price) OVER (CreatedOn) as close) as analytic
where
Transactions.CompanyIdentifier = analytic.CompanyIdentifier 
group by 
dateadd(DAY, 0, datediff(day, 0, CreatedOn)), CompanyIdentifier,analytic.first,analytic.close

我希望它对您有用,也许需要对查询进行一些调整,因为我根据您的示例使用了假设。

【讨论】:

猜你喜欢
  • 2018-09-07
  • 1970-01-01
  • 2022-09-29
  • 1970-01-01
  • 2020-01-01
  • 1970-01-01
  • 2011-11-15
  • 2019-07-13
  • 1970-01-01
相关资源
最近更新 更多