【问题标题】:Selecting data from SQL Server table according to Month根据月份从 SQL Server 表中选择数据
【发布时间】:2010-03-31 20:12:27
【问题描述】:

考虑到月份,我必须想出一种从 SQL 服务器表中获取数据的方法

“事件”表中有一个名为“日期”的 smalldatetime 类型字段,其中的一个字段如下所示:

29/01/2003 17:00:00

当我在 ASP.NET 的给定 DropDownList 控件中选择 jan/03 时,它应该是出现在 gridview 中的那些之一。

最好的方法是什么? 假设我只想回到过去 10 年,那么制作字典不是一个好方法吗? 如何更改它以使上个月始终是当前月份,并且每个月都会在下拉菜单中出现另一个选项?

这应该是一个常见问题,所以这不是一个把戏,但我想要一个好的和干净的方式来做这件事,而且(因为我是 asp.net 的新手)我自己会想出一些混乱的东西经过长时间的尝试。

所以我想要的是:
1) 选择
2) 填充 DropDownList 的最佳方式(当前月份始终位于顶部)
3) 将 DropDownList 用户友好的月份书写方式绑定到 select 查询友好的日期时间书写方式的最佳方式

信息:
ASP.NET,(C# 或 VB.NET),SQL Server 2005

【问题讨论】:

    标签: c# asp.net sql select


    【解决方案1】:

    1) 用于根据下拉菜单选择事件的 SQL。将此@Selected 视为您传递给存储过程的 SQL 日期时间,从下拉列表中取值。

    @SelectedDate smalldatetime --param to stored proc
    
    SELECT @SelectedDate  = '29/01/2003'
    
    -- get the events for the desired date.
    SELECT * FROM Events 
    WHERE DATEADD(dd, DATEDIFF(dd, 0, [Date]), 0) = @SelectedDate
    

    2) 作为下拉列表的数据源,收集表格中的日期。

     SELECT   CONVERT(varchar(3), [Date], 100) + ' ' + CONVERT(VARCHAR(5), YEAR([Date])) 
              AS EventDate
     FROM     Events
     GROUP BY CONVERT(varchar(3), [Date], 100) + ' ' + CONVERT(VARCHAR(5), YEAR([Date])) ,
          YEAR([Date])                                                         ,
          MONTH([Date])
     ORDER BY YEAR([Date]) DESC,
          MONTH([Date]) DESC
    

    【讨论】:

      【解决方案2】:

      谢谢大家的回答,我用过一个看起来像 pcampbell 的(+1 给他):

      SELECT * FROM whatevertable where CONVERT(CHAR(7),DataHoraInicio,120) = '2002-10'
      

      (这将获取 2002 年 10 月以来的所有注册表)

      我没有看到这种方法有任何挫折,事实上,它完美无缺

      再次感谢!

      【讨论】:

        【解决方案3】:

        一百万种方法可以做到这一点,在我的大多数系统中,我都有一个日期维度表,用于报告和其他各种我想按各种日期标准过滤的东西。您可以使用 MSSQL 的 DATEPART 和 DATENAME 函数轻松构建这样的表。

        示例脚本(这是我的一些旧代码):

        -- =============================================
        -- Build Dimension Date Table
        -- =============================================
        DECLARE @StartDate as smalldatetime, @EndDate as smalldatetime
        
        SET @StartDate = '04/01/2010'
        SET @EndDate = '03/31/2011'
        
        BEGIN
        SELECT
        DATEPART(dy, @StartDate) as DAY_OF_YEAR,
        CASE
        WHEN DATENAME(qq,@StartDate)-1=0 THEN
        4
        ELSE
        DATENAME(qq,@StartDate)-1
        END AS FISCAL_PERIOD,
        DATENAME(m,@StartDate) AS MONTH_DESC,
        DATEPART(m,@StartDate) AS MONTH_NUM,
        DATEPART(qq,@StartDate) AS QUARTER_NUM,
        CONVERT(smalldatetime, CONVERT(CHAR(10),@StartDate,110)) AS SALES_DATE,
        REPLACE(CONVERT(CHAR(10),@StartDate,06),' ','-') AS SALES_DATE_SPL,
        DATEPART(yy,@StartDate) AS YEAR_NUM,
        DATEPART(d,@StartDate) AS DAY_OF_MONTH,
        CASE
        WHEN DATEPART(m,@StartDate)< 4 THEN
        DATENAME(yy,@StartDate)-1
        ELSE
        DATENAME(yy,@StartDate)
        END AS FISCAL_YEAR,
        CASE
        WHEN DATEPART(m,@StartDate)>3 THEN
        DATEPART(m,@StartDate)-3
        ELSE
        12-(3-DATEPART(m,@StartDate))
        END AS FISCAL_MONTH
        INTO OLAP_DATE_DIMENSION
        
        SELECT @StartDate = @StartDate + 1
        
        END
        
        WHILE (@StartDate <= @EndDate)
            BEGIN
             BEGIN
             INSERT INTO OLAP_DATE_DIMENSION SELECT
             DATEPART(dy, @StartDate) as DAY_OF_YEAR,
             CASE
             WHEN DATENAME(qq,@StartDate)-1=0 THEN
             4
             ELSE
             DATENAME(qq,@StartDate)-1
             END AS FISCAL_PERIOD,
             DATENAME(m,@StartDate) AS MONTH_DESC,
             DATEPART(m,@StartDate) AS MONTH_NUM,
             DATEPART(qq,@StartDate) AS QUARTER_NUM,
                 CONVERT(smalldatetime, CONVERT(CHAR(10),@StartDate,110)) AS SALES_DATE,
             REPLACE(CONVERT(CHAR(10),@StartDate,06),' ','-') AS SALES_DATE_SPL,
             DATEPART(yy,@StartDate) AS YEAR_NUM,
             DATEPART(d,@StartDate) AS DAY_OF_MONTH,
             CASE
             WHEN DATEPART(m,@StartDate)< 4 THEN
             DATENAME(yy,@StartDate)-1
             ELSE
             DATENAME(yy,@StartDate)
             END AS FISCAL_YEAR,
             CASE
             WHEN DATEPART(m,@StartDate)>3 THEN
             DATEPART(m,@StartDate)-3
             ELSE
             12-(3-DATEPART(m,@StartDate))
             END AS FISCAL_MONTH
             END
             SELECT @StartDate = @StartDate + 1
            END
        

        获得所需数据后(可能加载 20 年,10 年,10 年向前和 10 年),您所要做的就是选择您想要的数据。由于您想要返回当前月份,因此我会查询 YEAR/MONTH = OLDEST DATE ALLOWED 的所有内容。

        例子:

        SELECT * 
            FROM OLAP_DATE_DIMENSION 
            WHERE SALES_DATE <=  CONVERT(CHAR(10),GETDATE(),110)) 
                AND DAY_OF_MONTH = '1' 
            ORDER BY SALES_DATE DESC;
        

        ** 这个针对上表的查询(这可能超出了您的需要),将返回今天之前表中每个月的每个月的第一天。然后,您可以利用各种日期部分创建一个漂亮的显示标签以显示在您的选择中(例如 2010 年 3 月、2010 年 2 月、2010 年 1 月等)。

        希望这是有道理的,唯一的长期“维护”任务是使用额外年份的数据更新您的表格。由于每年只有 365 天,因此您可以真正加载大量数据,而对系统的影响很小。如果您的页面获得大量点击,您可以缓存结果,以便数据在内存中!

        【讨论】:

          【解决方案4】:

          第 1 步:制定程序以生成今天日期之前或之后的月份列表。使用负参数及时后退,或使用正参数向前。

          create proc Timing.spGetMonthsFromToday(@months int) 
          as
          BEGIN
          
              -- Modified Jeff Moden solution found at:
              -- http://www.sqlservercentral.com/Forums/Topic494640-149-1.aspx
              ;WITH
              cteTally AS
              (   
                  SELECT TOP (ABS(@months)) 
                      N = case when @months < 0 then -1 else 1 end 
                          * ROW_NUMBER() OVER (ORDER BY t1.Object_ID)         
                  FROM Master.sys.All_Columns t1
                      CROSS JOIN Master.sys.All_Columns t2
                  UNION
                  SELECT 0
              )
          
              SELECT 
                  YearNumber = YEAR(DATEADD(mm,DATEDIFF(mm,0,GETDATE())+t.N,0))
                  , MonthNumber = MONTH(DATEADD(mm,DATEDIFF(mm,0,GETDATE())+t.N,0))
                  , MonthDesc = DATENAME(month,DATEADD(mm,DATEDIFF(mm,0,GETDATE())+t.N,0)) 
                                  + ' ' 
                                  + DATENAME(year,DATEADD(mm,DATEDIFF(mm,0,GETDATE())+t.N,0)) 
          
                  , MonthStartDate = DATEADD(mm,DATEDIFF(mm,0,GETDATE())+t.N,0)
                  , NextMonthStartDate = DATEADD(mm,DATEDIFF(mm,0,GETDATE())+t.N+1,0)
              FROM 
                  cteTally t
              ORDER BY
                  N DESC                                      
          
          END
          GO
          exec Timing.spGetMonthsFromToday -120
          

          第 2 步:使函数可在 .NET 中调用。如果您不想,或者没有现有的 DL,您可以使用快速 Linq to SQL 类。进入解决方案资源管理器,添加一个 Linq to SQL 类。进入服务器资源管理器并连接到您的数据库。找到存储过程,将其拖入L2SQL类的函数区。

          第 3 步:在 .NET 类中调用函数并将其推送到一个 List 中,以便您的 ASP.NET 代码轻松使用和重用。

          namespace Sample
          {
              class Timing
              {
                  public struct ListMonth
                  {
                      public readonly int Year;
                      public readonly int Month;
                      public readonly string Description;
                      public readonly DateTime StartDate;
                      public readonly DateTime NextStartDate;
                      public ListMonth(int year, int month, string description, DateTime startDate, DateTime nextStartDate)
                      {
                          Year = year;
                          Month = month;
                          Description = description;
                          StartDate = startDate;
                          NextStartDate = nextStartDate;
                      }
                      public override string ToString()
                      {
                          return Description;
                      }
                  }
                  public List<ListMonth> GetMonthsFromToday(int months)
                  {
                      List<ListMonth> _return = new List<ListMonth>();
          
                      dcTimingDataContext dc = new dcTimingDataContext();
                      var data = dc.spGetMonthsFromToday(months);
                      foreach (var row in data)
                      {
                          ListMonth month = new ListMonth(row.YearNumber.Value, row.MonthNumber.Value, row.MonthDesc, row.MonthStartDate.Value, row.NextMonthStartDate.Value);
                          _return.Add(month);               
                      }
                      return _return;
                  }           
              }
          }
          

          第 4 步:将列表绑定到您的下拉列表。我为此使用了 WPF 前端,但数据绑定应该完全相同或非常接近。我使用 -120 作为参数,因为你想回到 10 年前,但它可以调整到任何值。

          private void LoadMonths()
          {
              Sample.Timing timing = new Sample.Timing();
              cboMonths.ItemsSource = timing.GetMonthsFromToday(-120).OrderByDescending(row => row.StartDate);            
          }
          
          private void cboMonths_SelectionChanged(object sender, SelectionChangedEventArgs e)
          {
              if (((ComboBox)sender).SelectedItem != null)
              {
                  Sample.Timing.ListMonth month = (Sample.Timing.ListMonth)((ComboBox)sender).SelectedItem;
                  Console.WriteLine(month.StartDate); // just showing these dates are accessible under the hood
                  Console.WriteLine(month.NextStartDate); // just showing these dates are accessible under the hood
                  /* use these dates in your query against data set where eventdate >= month.StartDate and eventdate < month.EndDate */
              }
          }
          

          第 5 步:正如您在第 4 步末尾看到的那样,当用户进行选择时,您可以获得月初和月底的实际日期时间。然后将这些传递给您对“事件”表的查询。确保将 >= 与 StartDate 和

          干杯,希望这会有所帮助!

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2020-07-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-06-07
            • 2021-03-27
            • 1970-01-01
            相关资源
            最近更新 更多