【问题标题】:Want to display 12 months name from sql server想从 sql server 显示 12 个月的名字
【发布时间】:2012-12-18 18:44:35
【问题描述】:

我想从 sql server 显示 12 个月的名称。我虽然完成将月份名称插入临时表,然后在该表上触发 select 语句。所以我不得不写 12 个插入表来插入 12 个月的名字。所以我搜索谷歌找到更好的解决方案,我明白了。

这里是sql语句

WITH R(N) AS
(
    SELECT 0
    UNION ALL
    SELECT N+1 
    FROM R
    WHERE N < 12
)

SELECT LEFT(DATENAME(MONTH,DATEADD(MONTH,-N,GETDATE())),3) AS [month]
FROM R

上面的脚本完美运行,但我的问题是我只是不明白它是如何工作的。我从不与 CTE 合作。

那么告诉我WITH R(N) AS是什么意思

看看这个sql

SELECT LEFT(DATENAME(MONTH,DATEADD(MONTH,-N,GETDATE())),3) AS [month] FROM R
when above sql execute how it is getting value for -N ??
because here i have not set anything for -N ??

所以请任何人帮助我了解整个事情是如何运作的。谢谢

我的第二阶段问题

看看然后告诉我

;WITH months(MonthNumber) AS
(
    SELECT 0
    UNION ALL
    SELECT MonthNumber+1 
    FROM months
    WHERE MonthNumber < 12
)

我不清楚为什么只有第一次执行以下部分

SELECT 0
UNION ALL
SELECT MonthNumber+1 
FROM months
WHERE MonthNumber < 12

从第二次开始,只执行以下部分

SELECT MonthNumber+1 
FROM months
WHERE MonthNumber < 12

每当我们使用 Union 编写两个 sql 语句并执行时,它总是从两个 sql 状态返回数据,但特别是在这种情况下,从第二次开始,为什么只有以下部分 执行

SELECT MonthNumber+1 
FROM months
WHERE MonthNumber < 12

基本上我不熟悉递归技术的 CTE,这就是为什么我不清楚事情的原因。如果可能,请讨论 CTE 递归的工作原理。

DECLARE @TotaDays SMALLINT
DECLARE @Month VARCHAR(15)
DECLARE @Year SMALLINT
DECLARE @date DATETIME 
SET @Month = 'January'
SET @Year = 2015
SET @date = '01 ' + @Month + ' ' + CONVERT(VARCHAR(4),@Year)
SET @TotaDays = 0
SELECT @TotaDays = DATEDIFF(DAY, @date, DATEADD(MONTH, 1, @date))

;WITH months(MonthNumber) AS
(
    SELECT 1
    UNION ALL
    SELECT MonthNumber+1 
    FROM months
    WHERE MonthNumber < @TotaDays
)

select * from months;

【问题讨论】:

    标签: sql sql-server tsql


    【解决方案1】:

    With R(N)Common Table Expression。来自 MDSN:

    公用表表达式 (CTE) 可以被认为是临时的 在单个的执行范围内定义的结果集 SELECT、INSERT、UPDATE、DELETE 或 CREATE VIEW 语句。 CTE 是 类似于派生表,因为它不存储为对象,并且 仅在查询期间持续。与派生表不同,一个 CTE 可以是自引用的,并且可以在 相同的查询。

    R 是您正在生成的结果集(或表)的名称。而Nmonth 号码。

    这个 CTE 特别是 Recursive Common Table Expression。来自 MSDN:

    公用表表达式 (CTE) 具有以下显着优势: 能够引用自身,从而创建递归 CTE。一种 递归 CTE 是一种重复执行初始 CTE 以 返回数据的子集,直到获得完整的结果集。

    在使用 CTE 时,我的建议是名称更具描述性。因此,对于您的示例,您可以使用以下内容:

    ;WITH months(MonthNumber) AS
    (
        SELECT 0
        UNION ALL
        SELECT MonthNumber+1 
        FROM months
        WHERE MonthNumber < 12
    )
    select *
    from months;
    

    在我的版本中,months 是您正在生成的结果集的名称,monthnumber 是值。这会生成一个从 0 到 12 的月份编号列表(请参阅 Demo)。

    结果:

    | MONTHNUMBER |
    ---------------
    |           0 |
    |           1 |
    |           2 |
    |           3 |
    |           4 |
    |           5 |
    |           6 |
    |           7 |
    |           8 |
    |           9 |
    |          10 |
    |          11 |
    |          12 |
    

    然后,紧随其后的 SELECT 语句使用 CTE 结果集的值来获取月份名称。

    最终查询(见Demo):

    ;WITH months(MonthNumber) AS
    (
        SELECT 0
        UNION ALL
        SELECT MonthNumber+1 
        FROM months
        WHERE MonthNumber < 12
    )
    SELECT LEFT(DATENAME(MONTH,DATEADD(MONTH,-MonthNumber,GETDATE())),3) AS [month]
    FROM months;
    

    【讨论】:

    • 第一次告诉我 MonthNumber 的值是多少。在这里你写 SELECT MonthNumber+1 FROM months 如何第一次将值分配给 MonthNumber。
    • 第一个 MonthNumber 为 0。然后基本上循环遍历每个值,直到 MonthNumber 等于 12。
    • 我已经更新了我的问题。所以请看看我的第二阶段问题。谢谢
    • @Thomas 如果您还有其他问题,那么您应该发布一个新问题。通常,您不会编辑原始帖子以继续询问更新。网上有很多教程解释递归 CTE 是如何工作的,包括 thisthis
    【解决方案2】:

    这个查询是获取所有月份的名字和月份的编号

    SELECT DATENAME(MONTH, DATEADD(MM, s.number, CONVERT(DATETIME, 0))) AS [MonthName], 
    MONTH(DATEADD(MM, s.number, CONVERT(DATETIME, 0))) AS [MonthNumber] 
    FROM master.dbo.spt_values s 
    WHERE [type] = 'P' AND s.number BETWEEN 0 AND 11
    ORDER BY 2
    

    【讨论】:

      【解决方案3】:

      试试这个,

      with Months as 
      ( 
          select month(GETDATE()) as Monthnumber, datename(month, GETDATE()) as name, 1 as number
          union all
          select month(dateadd(month,number,(GETDATE()))) Monthnumber ,datename(month, dateadd(month,number,(GETDATE()))) as name, number+1 
          from Months 
          where number<12
      )   
      select Monthnumber, name 
      from Months 
      order by Monthnumber
      

      【讨论】:

        【解决方案4】:

        R 定义 CTE 的名称,(N) 定义 CTE 中列的名称 - 在这种情况下只有一列。

        您可以在语句的第二部分看到您正在从 R 中进行选择。

        当您select 0 时,您确实在设置(N) 的值,即CTE 定义的锚部分中的第一列也是唯一的列,稍后在CTE 定义的递归部分中指定select N+1 时。

        【讨论】:

        • 只运行这个语句。它应该只打印从 0 到 11,但它打印 0 到 12 ....怎么可能。 WITH R(N) AS ( SELECT 0 UNION ALL SELECT N+1 FROM R WHERE N
        • 只需使用 N
        • 第一次告诉我 (N) 的值是多少。在这里你写 SELECT N+1 FROM 第一次如何将值分配给(N)。
        【解决方案5】:

        尝试更改代码的第二部分,这样您将看到递归部分生成的内容:

        WITH R(N) AS
        (
            SELECT 0
            UNION ALL
            SELECT N+1 
            FROM R
            WHERE N < 12
        )
        
        SELECT *
        FROM R
        

        你会得到这个结果:

        Row# | N
             |
         1   | 0
         2   | 1
         3   | 2
         4   | 3
         5   | 4
         6   | 5
         7   | 6
         8   | 7
         9   | 8
         10  | 9
         11  | 10
         12  | 10
         13  | 12
        

        顺便说一句,我认为使用SELECT 1 而不是SELECT 0 会更好,这样您就可以生成正好12 个数字,因此您最终不会有额外的一个月

        【讨论】:

        • 第一次告诉我 (N) 的值是多少。在这里你写 SELECT N+1 FROM 第一次如何将值分配给(N)。
        • SELECT 0 UNION ALL ... 是语句的初始条件,是代码运行的必要条件。如果您想要一个不同的初始值,只需将其放入而不是 0。
        • 我已经更新了我的问题。所以请看看我的第二阶段问题。谢谢
        【解决方案6】:

        此查询获取每个时间段的信息并获取列表:

        set language  'SPANISH'
        DECLARE @table table(fechaDesde datetime , fechaHasta datetime ) 
        INSERT @table VALUES('20151231' , '20161231');
        WITH x AS 
            (
                SELECT   DATEADD( m , 1 ,fechaDesde ) as fecha  FROM @table
                UNION ALL
                SELECT  DATEADD( m , 1 ,fecha )
                FROM @table t INNER JOIN x ON  DATEADD( m , 1 ,x.fecha ) <= t.fechaHasta
            )
        SELECT LEFT( CONVERT( VARCHAR, fecha , 112 ) , 6 ) as Periodo_Id 
        ,DATEPART ( dd, DATEADD(dd,-(DAY(fecha)-1),fecha)) Num_Dia_Inicio
        ,DATEADD(dd,-(DAY(fecha)-1),fecha) Fecha_Inicio
        ,DATEPART ( mm , fecha ) Mes_Id
        ,DATEPART ( yy , fecha ) Anio
        ,DATEPART ( dd, DATEADD(dd,-(DAY(DATEADD(mm,1,fecha))),DATEADD(mm,1,fecha))) Num_Dia_Fin
        ,DATEADD(dd,-(DAY(DATEADD(mm,1,fecha))),DATEADD(mm,1,fecha)) ultimoDia
        ,datename(MONTH, fecha) mes
        ,'Q' + convert(varchar(10),  DATEPART(QUARTER, fecha)) Trimestre_Name
        FROM x 
        OPTION(MAXRECURSION 0)
        

        【讨论】:

          【解决方案7】:

          我修改了之前共享的代码,以按要求的顺序给出 12 个月的名称以及它们各自的月份编号。此外,通过添加 1900 年 1 月 1 日作为固定日期来消除对当前日期的依赖。

          WITH R (N)
          AS
          (SELECT
                  0
              UNION ALL
              SELECT
                  N + 1
              FROM R
              WHERE N < 12)
          
          SELECT
              N
             ,DATENAME(MONTH, DATEADD(MONTH, N - 1, '1 Jan 1900')) AS [month]
          FROM R
          WHERE N > 0
          

          【讨论】:

          • 虽然此命令可能会回答问题,但提供有关此代码为何和/或如何回答问题的额外上下文可提高其长期价值。 How to Answer
          【解决方案8】:

          我想你看到这个你就可以期待这个了,谢谢。

          以月(mnum)为 (选择 0 联合所有 从 mnum

          大卫·拉贾

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-02-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多