选择每组的第一条和最后一条记录

发布于 2025-01-19 05:56:38 字数 1243 浏览 0 评论 0原文

我需要返回每组集合的第一个和最后一个记录。

数据:

Code    Close       Time
USD     146116      2022-04-03 04:00:00.00 +00:00
EUR     241789      2022-03-27 17:00:00.00 +00:00
EUR     241807      2022-03-27 08:00:00.00 +00:00
USD     141800      2022-03-27 08:00:00.00 +00:00
USD     140809      2022-03-27 07:00:00.00 +00:00

T-SQL:

SELECT 
     [Code]
    ,DATEADD(dd, 0, DATEDIFF(dd, 0, [Time]))
    ,FIRST_VALUE([Close]) OVER (ORDER BY [Time] ASC) AS [Open] -- Column 'Time' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
    ,MAX([Close]) AS [High]
    ,MIN([Close]) AS [Low]
    ,LAST_VALUE([Close]) OVER (ORDER BY [Time] ASC) AS [Close] -- Column 'Time' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
FROM [CurrencyIntradayHistories]
GROUP BY [Code],
         DATEADD(dd, 0, DATEDIFF(dd, 0, [Time]))
ORDER BY [Time] ASC

期望的结果:

Code    Open    High    Low     Close   Time
EUR     241807  241807  241789  241789  2022-03-27
USD     140809  141800  140809  141800  2022-03-27
USD     146116  146116  146116  146116  2022-04-03

I need to return the first and last record of each group of sets.

DATA:

Code    Close       Time
USD     146116      2022-04-03 04:00:00.00 +00:00
EUR     241789      2022-03-27 17:00:00.00 +00:00
EUR     241807      2022-03-27 08:00:00.00 +00:00
USD     141800      2022-03-27 08:00:00.00 +00:00
USD     140809      2022-03-27 07:00:00.00 +00:00

T-SQL:

SELECT 
     [Code]
    ,DATEADD(dd, 0, DATEDIFF(dd, 0, [Time]))
    ,FIRST_VALUE([Close]) OVER (ORDER BY [Time] ASC) AS [Open] -- Column 'Time' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
    ,MAX([Close]) AS [High]
    ,MIN([Close]) AS [Low]
    ,LAST_VALUE([Close]) OVER (ORDER BY [Time] ASC) AS [Close] -- Column 'Time' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
FROM [CurrencyIntradayHistories]
GROUP BY [Code],
         DATEADD(dd, 0, DATEDIFF(dd, 0, [Time]))
ORDER BY [Time] ASC

Desired result:

Code    Open    High    Low     Close   Time
EUR     241807  241807  241789  241789  2022-03-27
USD     140809  141800  140809  141800  2022-03-27
USD     146116  146116  146116  146116  2022-04-03

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

呢古 2025-01-26 05:56:38

您不能直接在此处使用first_value,因为它是窗口函数,而不是聚合函数。

您需要将其嵌入子查询/派生表中,并在其上使用聚合。

此外,它需要按子句进行分区,以及在未绑定的前面和无限制之间的行

SELECT 
     cih.Code
    ,cih.Date
    ,MIN(cih.OpenPerDay) AS [Open]
    ,MAX(cih.[Close]) AS High
    ,MIN(cih.[Close]) AS Low
    ,MIN(cih.ClosePerDay) AS [Close]
FROM (
    SELECT
         *
        ,CAST(cih.Time AS date) AS Date
        ,FIRST_VALUE(cih.[Close]) OVER (PARTITION BY cih.Code, CAST(cih.Time AS date)
            ORDER BY cih.Time ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS OpenPerDay
        ,LAST_VALUE(cih.[Close]) OVER (PARTITION BY cih.Code, CAST(cih.Time AS date)
            ORDER BY cih.Time ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS ClosePerDay
    FROM CurrencyIntradayHistories cih
) cih
GROUP BY
  cih.Code,
  cih.Date
ORDER BY
  cih.Date;

略有效率的版本使用row_numberLEAD找到起始和结束行。

SELECT 
     cih.Code
    ,cih.Date
    ,MIN(CASE WHEN cih.rn = 1 THEN cih.[Close] END) AS [Open]
    ,MAX(cih.[Close]) AS High
    ,MIN(cih.[Close]) AS Low
    ,MIN(CASE WHEN cih.NextClose IS NULL THEN cih.[Close] END) AS [Close]
FROM (
    SELECT
         *
        ,CAST(cih.Time AS date) AS Date
        ,ROW_NUMBER() OVER (PARTITION BY cih.Code, CAST(cih.Time AS date) ORDER BY cih.Time) AS rn
        ,LEAD(cih.[Close]) OVER (PARTITION BY cih.Code, CAST(cih.Time AS date)
            ORDER BY cih.Time) AS NextClose
    FROM CurrencyIntradayHistories cih
) cih
GROUP BY
  cih.Code,
  cih.Date
ORDER BY
  cih.Date;

You cannot use FIRST_VALUE directly here because it is a window function, not an aggregate function.

You need to embed it in a subquery/derived table and use aggregation over it.

Also, it needs a PARTITION BY clause, as well as ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING

SELECT 
     cih.Code
    ,cih.Date
    ,MIN(cih.OpenPerDay) AS [Open]
    ,MAX(cih.[Close]) AS High
    ,MIN(cih.[Close]) AS Low
    ,MIN(cih.ClosePerDay) AS [Close]
FROM (
    SELECT
         *
        ,CAST(cih.Time AS date) AS Date
        ,FIRST_VALUE(cih.[Close]) OVER (PARTITION BY cih.Code, CAST(cih.Time AS date)
            ORDER BY cih.Time ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS OpenPerDay
        ,LAST_VALUE(cih.[Close]) OVER (PARTITION BY cih.Code, CAST(cih.Time AS date)
            ORDER BY cih.Time ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS ClosePerDay
    FROM CurrencyIntradayHistories cih
) cih
GROUP BY
  cih.Code,
  cih.Date
ORDER BY
  cih.Date;

A slightly more efficient version uses ROW_NUMBER and LEAD to find the starting and ending rows.

SELECT 
     cih.Code
    ,cih.Date
    ,MIN(CASE WHEN cih.rn = 1 THEN cih.[Close] END) AS [Open]
    ,MAX(cih.[Close]) AS High
    ,MIN(cih.[Close]) AS Low
    ,MIN(CASE WHEN cih.NextClose IS NULL THEN cih.[Close] END) AS [Close]
FROM (
    SELECT
         *
        ,CAST(cih.Time AS date) AS Date
        ,ROW_NUMBER() OVER (PARTITION BY cih.Code, CAST(cih.Time AS date) ORDER BY cih.Time) AS rn
        ,LEAD(cih.[Close]) OVER (PARTITION BY cih.Code, CAST(cih.Time AS date)
            ORDER BY cih.Time) AS NextClose
    FROM CurrencyIntradayHistories cih
) cih
GROUP BY
  cih.Code,
  cih.Date
ORDER BY
  cih.Date;

db<>fiddle

眼眸 2025-01-26 05:56:38

在整个数据集上使用窗口函数 MIN()、MAX() 和 FIRST_VALUE(),而不是在按代码和日期分组时得到的结果上使用:

SELECT DISTINCT
       [Code],
       FIRST_VALUE([Close]) OVER (PARTITION BY [Code], CONVERT(date, [Time]) ORDER BY [Time] ASC) AS [Open],
       MAX([Close]) OVER (PARTITION BY [Code], CONVERT(date, [Time])) AS [High],
       MIN([Close]) OVER (PARTITION BY [Code], CONVERT(date, [Time])) AS [Low],
       FIRST_VALUE([Close]) OVER (PARTITION BY [Code], CONVERT(date, [Time]) ORDER BY [Time] DESC) AS [Close],
       CONVERT(date, [Time]) [Time]
FROM [CurrencyIntradayHistories];

请参阅 演示

Use window functions MIN(), MAX() and FIRST_VALUE() on the whole dataset and not on the results that you get if you group by Code and date:

SELECT DISTINCT
       [Code],
       FIRST_VALUE([Close]) OVER (PARTITION BY [Code], CONVERT(date, [Time]) ORDER BY [Time] ASC) AS [Open],
       MAX([Close]) OVER (PARTITION BY [Code], CONVERT(date, [Time])) AS [High],
       MIN([Close]) OVER (PARTITION BY [Code], CONVERT(date, [Time])) AS [Low],
       FIRST_VALUE([Close]) OVER (PARTITION BY [Code], CONVERT(date, [Time]) ORDER BY [Time] DESC) AS [Close],
       CONVERT(date, [Time]) [Time]
FROM [CurrencyIntradayHistories];

See the demo.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文