在存储过程中为[Month]参数指定值

时间:2016-01-22 16:04:06

标签: sql sql-server sql-server-2008

我有一个存储过程,其输出是一个包含[Year]和[Month]列以及许多其他列的表。我还创建了四个参数:@SYear,@ SMonth,@EYear,@ emonth。 [年份]的不同之处是2015年和2016年。在月份专栏中,我有几个月的时间,如2015年的2,3,5,7,8等,2016年的1,2。现在我想分配从年份和月份列到参数的值。如果是一年,我可以将其指定为([年] @SYear和@EYear之间)。但是当我指定月份([月] BETWEEN @SMonth和@EMonth)时,问题实际上是2015年的第5个月不到2016年的第1个月,但是因为sql以[月]为整数5是大于1.,所以它不起作用。如果我选择@SYear = 2015,@ SMonth = 5,@ yaye = 2015,@ emonth = 7就可以了。

请建议一种可能的方法,将月份列分配给开始和月末参数。

BTW @S开始@E结束了。

希望我很清楚你们能够理解这个问题,如果有人不理解,请告诉我。

谢谢。

编辑: enter image description here

在这里,当我选择开始年份,开始月份和结束年份,结束月份作为参数时,我应该从表格中获得结果。

2 个答案:

答案 0 :(得分:0)

不是答案,长评论

这是丑陋的,我知道,如果你不能使用DATEFROMPARTS()这样的东西可能会起作用(或演员字符串)

onProgressUpdate

答案 1 :(得分:0)

这取代了之前的答案,以便完全回答这个问题。事实证明这是比它应该更难的事情之一。我真的认为下面的答案#2(创建一个计算字段)将是肯定的后备答案,但事实证明你不能在PERSISTED字段中使用带有DATE类型的CAST(),这样就增加了复杂性。

这是答案1,如果......使用它

  • 您需要经常进行此查询
  • 您有大量数据并需要索引
  • 您不介意更改表格结构

'正确的方法'是通过添加具有实际MONTH / YEAR的字段和当天的虚拟“1st”来添加实际DATE的列。将其存储为DATE,然后使用它进行查询。这可以编入索引,并且会尽可能快。

这是答案2,如果......使用它

  • 您需要经常进行此查询
  • 您拥有最少的数据,因此不需要索引
  • 您不想更改表格结构

您可以使用以下任一方法在表格上创建计算字段。这样,无论何时编写查询,您都可以使用日期字段,生活很简单 - 除非您不会点击索引。

ALTER TABLE table1
ADD THE_DATE1 AS CONVERT(VARCHAR(4), THE_YEAR ) + '-' + CONVERT(VARCHAR(2), THE_MONTH) + '-01'

ALTER TABLE table1
ADD THE_DATE2 AS DATEADD(mm, THE_MONTH -1, dateadd(yy,THE_YEAR-1900,'19000101'))

ALTER TABLE table1 -- SQL212+
ADD THE_DATE3 AS DATEFROMPARTS(THE_YEAR, THE_MONTH,  1)

这是答案3,如果......使用它

  • 您需要经常进行此查询
  • 您有大量数据并且需要索引
  • 你不介意疯狂的查询

您可以使用疯狂的WHERE语句来获取数据。下面有两个版本,第二个版本包含一些AND语句,可以帮助SQL SERVER命中某些索引(因为SQL不喜欢在WHERE语句中有一堆OR运算符)。

DECLARE @table1 AS TABLE (
         ID INT ,
         THE_YEAR INT ,
         THE_MONTH INT ,
         THE_MONEY INT
        )

INSERT  INTO @table1
VALUES  ( 1, 2015, 5, 20 ),
        ( 2, 2015, 7, 50 ),
        ( 3, 2015, 9, 8 ),
        ( 4, 2015, 10, 60 ),
        ( 5, 2015, 12, 30 ),
        ( 6, 2016, 1, 90 ),
        ( 7, 2016, 2, 120 ),
        ( 8, 2017, 1, 220 ), -- Added for testing
        ( 9, 2017, 2, 320 )  -- Added for testing

DECLARE @START_YEAR INT = 2015;
DECLARE @START_MONTH INT = 7;

DECLARE @STOP_YEAR INT = 2015;
DECLARE @STOP_MONTH INT = 10;

-- QUERY THAT ANSWERS YOUR QUESTION

SELECT  *
FROM    @table1
WHERE   (
            ( @START_YEAR <> @STOP_YEAR AND THE_YEAR  = @START_YEAR AND THE_MONTH >= @START_MONTH )
            OR 
            ( @START_YEAR <> @STOP_YEAR AND THE_YEAR > @START_YEAR AND THE_YEAR < @STOP_YEAR )
            OR 
            ( @START_YEAR <> @STOP_YEAR AND THE_YEAR  = @STOP_YEAR  AND THE_MONTH <= @STOP_MONTH )
            OR 
            -- Handle when Start/Stop year are the same
            ( @START_YEAR  = @STOP_YEAR  AND THE_MONTH >= @START_MONTH AND THE_MONTH <= @STOP_MONTH )
        )
ORDER BY THE_YEAR ,
        THE_MONTH


-- QUERY THAT ANSWERS YOUR QUESTION, with INDEX optimizations
-- because once you have a bunch of data, this may help you hit on an index.
SELECT  *
FROM    @table1
WHERE   THE_YEAR >= @START_YEAR   -- Will hit an INDEX if you have one on THE_YEAR
        AND THE_YEAR <= @STOP_YEAR -- Will hit an INDEX if you have one on THE_YEAR
        AND
        (
                ( @START_YEAR <> @STOP_YEAR AND THE_YEAR  = @START_YEAR AND THE_MONTH >= @START_MONTH )
                OR 
                ( @START_YEAR <> @STOP_YEAR AND THE_YEAR > @START_YEAR AND THE_YEAR < @STOP_YEAR )
                OR 
                ( @START_YEAR <> @STOP_YEAR AND THE_YEAR  = @STOP_YEAR  AND THE_MONTH <= @STOP_MONTH )
                OR 
                -- Handle when Start/Stop year are the same
                ( @START_YEAR  = @STOP_YEAR  AND THE_MONTH >= @START_MONTH AND THE_MONTH <= @STOP_MONTH )
            )
ORDER BY THE_YEAR ,
        THE_MONTH