【问题标题】:addition of date in sql function在sql函数中添加日期
【发布时间】:2014-10-23 17:53:49
【问题描述】:

我在 sql 中有一个我用 C# 编写的查询。查询的作用是计算类似于我输入两列日期和否的内容。球作为

Date        No. of balls
21/11/2013  2
22/11/2013  3
23/11/2013  4
24/11/2013  5
25/11/2013  2
26/11/2013  5
27/11/2013  4
28/11/2013  3
29/11/2013  9
30/11/2013  8
01/12/2013  7
02/12/2013  4
03/12/2013  5
04/12/2013  6
05/12/2013  2
06/12/2013  0
07/12/2013  1

输出应该是这样的

newdate                no. of balls
21/11/2013 -27/11/2013  25
28/11/2013-04/12/2013   42
05/12/2013-07/12/2013   3

即日期在 7 天的间隔内,例如 21/11/2013 到 27/11/2013 然后下一个 7 28/11/2013-04/12/2013 等等,但它应该将 enddate 视为仅数据库日期的结束日期(如第 3 行所示)。 我想使用创建函数函数名(例如函数名称作为间隔)在 sql 中创建一个函数,该函数应该返回输出的日期列,以便我可以在用 c# 编写的 sql 查询中使用该函数(dbo.interval) 作为

string query = @" select dbo.interval([Date]) newdate,
                  IsNull(ROUND(sum(No. of balls),2),0) [no. of balls] 
                  from stock
                   Where  date between Convert(Datetime,'" + Fromdate + "',103) and      Convert(Datetime,'" + Todate + "',103)
 Group By dbo.interval([date])";

PS:stock 是一个包含两列日期和编号的表格。球和 + Fromdate + 和 + Todate + 是下拉显示在网格中。它基本上是用户提供的日期的上限和下限,以了解这两个日期之间的信息(在这种情况下,上限和下限的日期是21/11/2013 和 07/12/2013 分别)。因此输出文件看起来像

新日期没有。球 21/11/2013 -27/11/2013 25 28/11/2013-04/12/2013 42 05/12/2013-07/12/2013 3

我曾尝试在 sql 中使用 RecursiveCTE,但它没有太大帮助,因为它只提供临时输出。

【问题讨论】:

  • 您使用的是 MS SQL 2008 或更高版本吗?您可以使用 OVER 子句(msdn.microsoft.com/en-us/library/ms189461.aspx)并尝试按 DATEPART(wk, Date)
  • 我正在使用 sql server 2008。但是如何为日期编写一个 sql 函数
  • 7 天间隔是从Stock 表中的最小日期开始,还是从一周中的某一天开始?例如:Mon-Sun.
  • 用户从下拉列表中选择的任何日期都是 startdate。从该日期开始计算 7 天。dropdown 包含股票表中的所有日期
  • 假设您将开始日期存储在变量@Fromdate 中。表中 Fromdate 到 date 之间的天数差异为 DATEDIFF(d , @ Fromdate , Date) 现在您可以按 7 进行 div - (DATEDIFF(d , @ Fromdate , Date) / 7 AS INTEGER)

标签: sql sql-server-2008 date datetime dateadd


【解决方案1】:

解决问题的最简单方法是按查询分组使用 ROLLUP (http://technet.microsoft.com/en-us/library/bb522495(v=sql.105).aspx)

这是 SQL Fiddle (http://sqlfiddle.com/#!3/3ce09/19)

日期定义:

create table test (
    Id  INT IDENTITY(1,1),
    date  DateTime,
    balls  int );
insert into test(date, balls) values('11/21/2013',  2);
insert into test(date, balls) values('11/22/2013',  3);
insert into test(date, balls) values('11/23/2013',  4);
insert into test(date, balls) values('11/24/2013',  5);
insert into test(date, balls) values('11/25/2013',  2);
insert into test(date, balls) values('11/26/2013',  5);
insert into test(date, balls) values('11/27/2013',  4);
insert into test(date, balls) values('11/28/2013',  3);
insert into test(date, balls) values('11/29/2013',  9);
insert into test(date, balls) values('11/30/2013',  8);
insert into test(date, balls) values('12/01/2013',  7);
insert into test(date, balls) values('12/02/2013',  4);
insert into test(date, balls) values('12/03/2013',  5);
insert into test(date, balls) values('12/04/2013',  6);
insert into test(date, balls) values('12/05/2013',  2);
insert into test(date, balls) values('12/06/2013',  0);
insert into test(date, balls) values('12/07/2013',  1);

实际查询:

select 
  label, 
  balls 
  from ( 
     SELECT  
       (DATEDIFF(d , '11/21/2013' , date) / 7) as week, 
       ((DATEDIFF(d , '11/21/2013' , date) / 7) + 1) as week1, 
       LEFT(CONVERT(VARCHAR, (DateAdd(d, (DATEDIFF(d , '11/21/2013' , date) / 7)*7, '11/21/2013')), 120), 10) +    ' - ' +  
       LEFT(CONVERT(VARCHAR, (DateAdd(d, ((DATEDIFF(d , '11/21/2013' , date) / 7) + 1)*7 - 1, '11/21/2013')), 120), 10) as label, 
       SUM(Balls) as balls 
      FROM test 
      GROUP BY rollup((DATEDIFF(d , '11/21/2013' , date) / 7))   
  ) as t 
  where t.label is not null

结果:

LABEL                       BALLS
2013-11-21 - 2013-11-27     25
2013-11-28 - 2013-12-04     42
2013-12-05 - 2013-12-11     3

【讨论】:

    【解决方案2】:

    我认为您实际上根本不需要使用函数。我拿了 Maksym 的测试数据,稍微整理了一下,然后编写了一个查询,它可以带回您需要的数据,而无需调用 UDF:

    DECLARE @Test TABLE (
        Id  INT IDENTITY(1,1),
        [Date] DATE,
        Balls  INT);
    INSERT INTO @Test([Date], Balls) VALUES('20131121',  2);
    INSERT INTO @Test([Date], Balls) VALUES('20131122',  3);
    INSERT INTO @Test([Date], Balls) VALUES('20131123',  4);
    INSERT INTO @Test([Date], Balls) VALUES('20131124',  5);
    INSERT INTO @Test([Date], Balls) VALUES('20131125',  2);
    INSERT INTO @Test([Date], Balls) VALUES('20131126',  5);
    INSERT INTO @Test([Date], Balls) VALUES('20131127',  4);
    INSERT INTO @Test([Date], Balls) VALUES('20131128',  3);
    INSERT INTO @Test([Date], Balls) VALUES('20131129',  9);
    INSERT INTO @Test([Date], Balls) VALUES('20131130',  8);
    INSERT INTO @Test([Date], Balls) VALUES('20131201',  7);
    INSERT INTO @Test([Date], Balls) VALUES('20131202',  4);
    INSERT INTO @Test([Date], Balls) VALUES('20131203',  5);
    INSERT INTO @Test([Date], Balls) VALUES('20131204',  6);
    INSERT INTO @Test([Date], Balls) VALUES('20131205',  2);
    INSERT INTO @Test([Date], Balls) VALUES('20131206',  0);
    INSERT INTO @Test([Date], Balls) VALUES('20131207',  1);
    DECLARE @StartDate DATE = '20131121';
    DECLARE @EndDate DATE = '20131207';
    
    WITH StartDates AS (
        SELECT 
            CASE WHEN DATEDIFF(DAY, @StartDate, [Date]) % 7 = 0 THEN [Date] END AS StartDate
        FROM
            @Test),
    EndDates AS (
        SELECT
            StartDate,
            CASE WHEN DATEADD(DAY, 6, StartDate) > @EndDate THEN @EndDate ELSE DATEADD(DAY, 6, StartDate) END AS EndDate
        FROM
            StartDates)
    SELECT 
        ed.StartDate,
        ed.EndDate,
        CONVERT(VARCHAR(12), ed.StartDate, 103) + ' - ' + CONVERT(VARCHAR(12), ed.EndDate, 103) AS NewDate,
        ISNULL(ROUND(SUM(Balls), 2), 0) [Balls] 
    FROM 
        @Test t
        INNER JOIN EndDates ed ON DATEDIFF(DAY, ed.StartDate, t.[Date]) BETWEEN 0 AND 7 AND DATEDIFF(DAY, t.[Date], ed.EndDate) BETWEEN 0 AND 7
    WHERE  
        [Date] BETWEEN @StartDate AND @EndDate
    GROUP BY 
        ed.StartDate,
        ed.EndDate,
        CONVERT(VARCHAR(12), ed.StartDate, 103) + ' - ' + CONVERT(VARCHAR(12), ed.EndDate, 103)
    ORDER BY 
        ed.StartDate;
    

    这给出了以下结果:

    StartDate   EndDate     NewDate                 Balls
    2013-11-21  2013-11-27  21/11/2013 - 27/11/2013 25
    2013-11-28  2013-12-04  28/11/2013 - 04/12/2013 42
    2013-12-05  2013-12-07  05/12/2013 - 07/12/2013 3
    

    如果您将我的查询转换为针对您的 [Stock] 表,那么您应该能够将其嵌入到您的 .NET 解决方案中,将 @StartDate 和 @EndDate 替换为用户提供的值,将 @Test 替换为 [Stock ] 并相应地修复列名?

    【讨论】:

    • 感谢一切工作正常,除了一件事我在 C# 中有一个函数名称 TRY as public DataTable TRY(string FromDate, string ToDate) { string query = " DECLARE StartDate DATE = '20110101'; DECLARE EndDate DATE = '20110119';....其余的查询由你建议。} 我需要知道我如何声明 StartDate Date = Fromdate (来自函数 TRY)同样 EndDate DATE = ToDate (来自function TRY) 意味着让它们从函数中获取值而不是赋值
    • 有两种方法可以做到这一点,“错误”的方法是在查询字符串中包含日期,例如"DECLARE StartDate = " + myStartDate.ToString("YYYYMMDD") + ", EndDate = ... 正确的方法是将其视为存储过程并将日期添加为参数。这可能非常复杂,但可以防止 SQL 注入。
    • 这就是我询问 sql func 的原因,以便在用 C# 编写的查询中我可以编写..string query = @" select dbo.interval([Date]) newdate, IsNull(ROUND(sum( No. of balls),2),0) [no. of balls] from stock where date between Convert(Datetime,'" + Fromdate + "',103) 和 Convert(Datetime,'" + Todate + "',103 ) Group By dbo.interval([date])";..在查询中 dbo.interval([Date]) newdate 是使用创建函数间隔编写的函数.....但是正如你所建议的,我已经编写了一个存储过程对于日期并将日期添加为参数。现在如何在我用 C# 编写的 sql 查询中提及它们
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-23
    • 1970-01-01
    • 2021-06-13
    • 1970-01-01
    • 1970-01-01
    • 2016-09-30
    • 2018-09-22
    相关资源
    最近更新 更多