Выбор данных из таблицы SQL Server по месяцам - PullRequest
1 голос
/ 01 апреля 2010

Мне нужно найти способ получить данные из таблицы SQL-сервера, если месяц

В таблице "events" есть поле типа smalldatetime, которое называется date, и поле из него выглядит следующим образом:

29/01/2003 17:00:00

Это должен быть один из тех, которые появляются в окне сетки, когда я выбираю jan / 03 в заданном элементе управления DropDownList в ASP.NET.

Каков наилучший способ сделать это? Если предположить, что я хочу уйти на 10 лет назад, разве не сделать словарь хорошим способом? Как изменить его так, чтобы верхний месяц всегда был текущим, а каждый месяц в выпадающем списке появлялись другие варианты?

Это должно быть общей проблемой, так что это не будет хитростью, но я хочу хороший и чистый способ сделать это, и (так как я новичок в asp.net), я сам придумал бы что-то грязное после долгих попыток.

Итак, что я хочу:
1) Выберите
2) Лучший способ заполнения DropDownList (с текущим месяцем всегда вверху)
3) Лучший способ связать удобный для написания месяцев DropDownList с выбранным удобным для запросов способом написания datetime

Информация:
ASP.NET, (C # или VB.NET), SQL Server 2005

Ответы [ 4 ]

1 голос
/ 05 апреля 2010

Спасибо, ребята, за ответы, я использовал тот, который похож на pcampbell (+1 ему):

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

(это получает каждый реестр с октября 2002)

Я не вижу никаких отступлений для этого метода, на самом деле, он работает безупречно

Еще раз спасибо!

1 голос
/ 01 апреля 2010

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
0 голосов
/ 03 апреля 2010

Шаг 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. Зайдите в Solution Explorer, добавьте класс Linq to SQL. Зайдите в Обозреватель серверов и установите соединение с вашей базой данных. Найдите хранимую процедуру и перетащите ее в область функций класса L2SQL.

Шаг 3 : вызовите функцию внутри класса .NET и поместите ее в список, который можно легко использовать и использовать в коде 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 и <с NextStartDate. </p>

Ура, надеюсь, это поможет!

0 голосов
/ 01 апреля 2010

Миллион способов сделать это, в большинстве моих систем у меня есть таблица измерения даты, используемая для отчетов и других различных вещей, которые я хочу отфильтровать по различным критериям даты. Вы можете легко построить такую ​​таблицу, используя функции DATEPART & DATENAME в MSSQL.

Пример скрипта (это из моего старого кода):

-- =============================================
-- 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 вперед), все, что вам нужно сделать, это выбрать нужные данные. Поскольку вы хотите текущий месяц назад, я бы сделал запрос для всего с ГОДОМ / МЕСЯЦОМ <= СЕГОДНЯ и> = ДОЛГОСРОЧНАЯ ДАТА РАЗРЕШЕНА.

Пример:

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

** Этот запрос к приведенной выше таблице (что, вероятно, является слишком большим для того, что вам нужно) возвращает первый день каждого месяца каждого месяца в таблице до сегодняшнего дня. Затем вы можете взять различные части даты, чтобы создать красивую метку для отображения в вашем списке (например, март 2010, февраль 2010, январь 2010 и т. Д.).

Надеюсь, это имеет смысл, единственной долгосрочной задачей "обслуживания" будет обновление таблицы с добавлением данных за годы. Поскольку это всего 365 дней в год, вы действительно можете загрузить тонну данных с минимальным влиянием на вашу систему. Если ваши страницы получают много просмотров, вы можете кэшировать результаты, чтобы данные были в памяти!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...