11

我想从 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;
4

8 回答 8

16

With R(N)是一个公用表表达式。来自 MDSN:

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

R是您正在生成的结果集(或表)的名称。是N数字month

这个 CTE 特别是一个递归公用表表达式。来自 MSDN:

公共表表达式 (CTE) 提供了能够引用自身的显着优势,从而创建递归 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 的月份编号列表(参见演示)。

结果:

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

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

最终查询(参见演示):

;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;
于 2013-01-04T10:57:36.007 回答
8

此查询用于获取所有月份名称和月份编号

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
于 2017-04-03T08:46:30.107 回答
2

试试这个,

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
于 2019-03-21T16:35:02.680 回答
1

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

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

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

于 2013-01-04T10:43:44.667 回答
1

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

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 1SELECT 0这样您就可以生成正好 12 个数字,因此您最终不会有额外的一个月

于 2013-01-04T10:48:17.960 回答
0

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

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)
于 2015-12-02T15:41:55.020 回答
0

我修改了之前共享的代码,以按要求的顺序给出 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
于 2019-04-01T09:33:27.817 回答
-1

我想你看到这个你会期待这个,你可以理解谢谢。

with months(mnum) as (select 0 union all select mnum+1 from months where mnum <11) select left(datename(month,dateadd(month,mnum,getdate())),3) as mn from months

大卫·拉贾

于 2014-01-21T12:54:53.753 回答