Как применить принцип СУХОЙ к операторам SQL, которые сводят месяцы - PullRequest
0 голосов
/ 21 января 2009

Мне интересно, как другие справляются с этой ситуацией ... и как применить принцип "Не повторяйся" (СУХОЙ) к этой ситуации.

Я постоянно нахожу или пишу операторы CASE в T-SQL, чтобы представлять месяцы в виде столбцов. У меня обычно есть некоторые поля, которые будут включать (1) поле даты и (2) поле значения. Когда я представляю это обратно пользователю через страницу ASPX или Reporting Services, у меня должны быть последние 14 правых столбцов, чтобы иметь этот шаблон:

[год], [Ян] [Февраль] [Март], [апреля], [мая], [июня], [июля], [Август] [Сентябрь] [Октябрь], [ноября] [декабря], [Всего]

Где год - это год как int а каждое другое поле является полем значения, суммированным за этот месяц (за исключением [Всего], которое является полем общего значения за год).

Я бы хотел найти один способ повторного использования. Открыто для всех предложений (T-SQL / ANSI SQL)

Ответы [ 5 ]

3 голосов
/ 21 января 2009

Это не совсем то, что вы ищете, но я сделал много повторений UNPIVOT, и, как правило, я бы написал этот код, используя какое-то стандартизированное наименование и интенсивно используя CTE: 1002 *

WITH P AS (
    SELECT Some Data
            ,[234] -- These are stats
            ,[235]
    FROM Whatever
     )
,FINAL_UNPIVOTED AS (
    SELECT Some Data
            ,[STAT]
    FROM P
    UNPIVOT (
        STAT FOR BASE IN ([234], [235]) 
    ) AS unpvt
    WHERE STAT <> 0
)
SELECT Some Data
              ,CONVERT(int, FINAL_UNPIVOTED.[BASE]) AS [BASE]
              ,FINAL_UNPIVOTED.[STAT]
FROM FINAL_UNPIVOTED

Вы можете кодировать, проверяя таблицу или представление и используя что-то вроде этого:

DECLARE @sql_unpivot AS varchar(MAX)
SELECT @sql_unpivot = COALESCE(@sql_unpivot + ',', '') + COLUMN_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = 'whatever'

И шаблонизирующий код:

SET @template = '
    WITH P AS (
        SELECT Some Data
                ,{@sql_unpivot}
                  FROM Whatever
         )
    ,FINAL_UNPIVOTED AS (
        SELECT Some Data
                ,[STAT]
        FROM P
        UNPIVOT (
            STAT FOR BASE IN ({@sql_unpivot}) 
        ) AS unpvt
        WHERE STAT <> 0
    )
    SELECT Some Data
                  ,CONVERT(int, FINAL_UNPIVOTED.[BASE]) AS [BASE]
                  ,FINAL_UNPIVOTED.[STAT]
    FROM FINAL_UNPIVOTED
'
SET @sql = REPLACE(@template, '{@sql_unpivot}', @sql_unpivot)

и т.д.

Конечно, можно запускать этот код динамически или создавать и SP, и вы можете временно поменять созданное вами представление или таблицу, просто чтобы получить метаданные для чего-то встроенного.

См. Комментарии о табличных функциях и методике OUTER APPLY.

1 голос
/ 21 января 2009
/* I leave year and month separate so you can use "real" Months or Fiscal Months */

CREATE FUNCTION [dbo].[fn_MonthValueColumns] 
(   
    @year int,
    @month int, 
    @measure int 
)
RETURNS TABLE 
AS
RETURN 
(
    SELECT @year as [Year],
        CASE WHEN @month = 1 THEN @measure ELSE 0 END AS [Jan], 
        CASE WHEN @month = 2 THEN @measure ELSE 0 END AS [Feb], 
        CASE WHEN @month = 3 THEN @measure ELSE 0 END AS [Mar], 
        CASE WHEN @month = 4 THEN @measure ELSE 0 END AS [Apr], 
        CASE WHEN @month = 5 THEN @measure ELSE 0 END AS [May], 
        CASE WHEN @month = 6 THEN @measure ELSE 0 END AS [Jun], 
        CASE WHEN @month = 7 THEN @measure ELSE 0 END AS [Jul], 
        CASE WHEN @month = 8 THEN @measure ELSE 0 END AS [Aug], 
        CASE WHEN @month = 9 THEN @measure ELSE 0 END AS [Sep], 
        CASE WHEN @month = 10 THEN @measure ELSE 0 END AS [Oct], 
        CASE WHEN @month = 11 THEN @measure ELSE 0 END AS [Nov], 
        CASE WHEN @month = 12 THEN @measure ELSE 0 END AS [Dec], 
        @measure AS [Total]
)

  /* 
   use a group by after your own CROSS APPLY to roll-up SUMs for the last 13 fields. 

   this function and a CROSS APPLY against 100000 records ran in 3 seconds.
   for what I am doing, I can live with that performance.
  */
1 голос
/ 21 января 2009

Уже поздно, и я мог бы упустить здесь что-то очевидное, но поможет ли вам в этом таблица месяцев со строкой для каждого месяца?

0 голосов
/ 07 июля 2010

Как упомянуто в комментариях @ Justice , DRY обычно относится к повторно используемому коду, что гораздо проще в языке вашего клиента SQL, чем в SQL. Если вы открыты для этой опции (и, по общему признанию, вы не можете), рассмотрите преобразователь данных, например MyBatis . Извлечение в объекты может быть излишним, что вам нужно, но возможность создавать фрагменты SQL и повторно использовать их в различных запросах звучит так, как вы.

0 голосов
/ 21 января 2009

Как насчет использования представления?

Если вы всегда выбираете одну и ту же таблицу / группу таблиц, представление может иметь смысл. ПРЕДУПРЕЖДЕНИЕ. Остерегайтесь таких представлений при использовании небольших разделов больших таблиц ... представление может помешать оптимизатору выполнять свою работу.

...