sql server lead - 日期问题

时间:2014-05-27 11:57:34

标签: sql sql-server date lead

我在sql server 2012中使用新的主要olap函数时遇到问题。

CREATE TABLE Atext (id int, bez varchar(10), von date); 

GO

INSERT INTO Atext VALUES (1, 't1', '2001-01-01'), (1, 't2', '2012-01-01'), (2, 'a1', '2020-01-01'), (2,'a1' , '2030-01-01'), (2, 'b', '2040-05-01'), (2, 'a3', '2989-05-01'); 
GO

SELECT 
        id, 
        bez, 
        von,
        lead(von,1,0) over (partition by id ORDER BY von) -1 as bis
FROM 
        Atext
order by 
        id, 
        Von

select查询会引发错误:

Msg 206, Level 16, State 2, Line 1 
Operand type clash: int is incompatible with date

为什么数据类型日期时间有限制?

我知道一种解决方法,但它不是很好:

SELECT
    id,
    bez,
    CAST(vonChar AS DATE) AS Von,
    CASE
        WHEN bisChar <> '0'
        THEN (DATEADD(DAY,-1,(CAST((
                    CASE
                        WHEN bisChar <> '0'
                        THEN vonChar
                        ELSE NULL
                    END)AS DATE)) ))
        ELSE NULL /*'9999-12-31'*/
    END AS Bis
FROM
    (
        SELECT
            id,
            bez,
            vonChar ,
            lead(vonChar,1,0) over (partition BY id ORDER BY vonChar) AS bisChar
        FROM
            (
                SELECT
                    id,
                    bez,
                    CAST(von AS VARCHAR(10)) vonChar
                FROM
                    Atext) tab ) tab2
ORDER BY
    id,
    Von

Microsoft SQL Server 2012(SP1) - 11.0.3128.0(X64)

4 个答案:

答案 0 :(得分:3)

使用日期(或可以隐式转换为日期的东西)作为主导函数的默认值,DATEADD函数可以更简单地解决:

SELECT 
        id, 
        bez, 
        von,
        DATEADD(DAY, -1, LEAD(von, 1, '19000101') 
                        OVER (PARTITION BY id ORDER BY von)) AS bis
FROM Atext
ORDER BY id, Von;

或者只是不打扰默认。这不是必需的:

SELECT 
        id, 
        bez, 
        von,
        DATEADD(DAY, -1, LEAD(von, 1) 
                        OVER (PARTITION BY id ORDER BY von)) AS bis
FROM Atext
ORDER BY id, Von;

问题是您无法将INT投射到DATE。在SQL Server中的表达式中,表达式的所有部分必须具有相同的数据类型,因此,如果您这样做:

SELECT TOP 1 GETDATE() + number
FROM master..spt_values
WHERE type = 'p'

在幕后SQL Server需要决定是否将GETDATE()转换为整数,以便表达式的所有部分都是整数,或1到日期时间,以便 所有部分都是日期时间。 SQL Server的Data Type Precedence规定DATETIME的优先级高于INT,因此SQL Server将1转换为日期时间,这可以在执行计划中看到:

<ScalarOperator ScalarString="getdate()+[Expr1005]">
....
<ColumnReference Column="Expr1005" />
<ScalarOperator ScalarString="CONVERT_IMPLICIT(datetime,[master].[dbo].[spt_values].[number],0)">

这表明INT列master..spt_values.number在被添加到getdate()之前被隐式转换为日期时间

无论出于何种原因(我不久前看了很多并且没有找到解释原因的原因),从int到date都没有隐式或显式转换,你必须使用日期函数。

答案 1 :(得分:3)

与所有其他答案相同,但以DATEADD作为铅的参数:

SELECT
  id, 
  bez,
  von,
  lead(DATEADD(DAY,-1, von),1, null) over (partition by id order by von)
from 
  Atext
order by
    id,
    Von

SQLFiddle示例

答案 2 :(得分:2)

您可以在此查询中使用DATEADD()。此外,数据类型的LEAD默认值不能为0,因此我将其更改为NULL,或者您可以使用任何DATE常量。

SELECT 
        id, 
        bez, 
        von,
        DATEADD(DAY,-1,lead(von,1,NULL) 
                       over (partition by id ORDER BY von)) as bis
FROM 
        Atext
order by 
        id, 
        Von

SQLFiddle demo

答案 3 :(得分:0)

这会对您有所帮助吗?当给出0来代替期望日期字段时,会发生错误。

I replaced lead(von,1,0) with lead(von,1,'1900-01-01')

查看具有相同结果的其他代码。

SET DATEFORMAT ymd
DECLARE @Atext TABLE  
    (id INT, bez VARCHAR(10), von DATE); 

INSERT INTO @Atext VALUES 
    (1, 't1', '2001-01-01'),
    (1, 't2', '2012-01-01'), (2, 'a1', '2020-01-01'), 
    (2,'a1' , '2030-01-01'), (2, 'b', '2040-05-01'),
    (2, 'a3', '2099-05-01'); 

SELECT  id, 
        bez, 
        von,
        lead(von,1,'1900-01-01') OVER (PARTITION BY id ORDER BY von) AS bis
FROM    @Atext
ORDER   by 
        id, 
        Von

结果

enter image description here