SQL Server:计算存储过程中的年龄返回转换失败

时间:2017-11-23 09:22:36

标签: sql-server stored-procedures

我编写了一个存储过程,用于根据表列中的值计算年龄。

这是存储过程:

WITH ages AS
(
    SELECT 
        DATEDIFF(YEAR, CONVERT(datetime, pf.Value, 104), pf.CreatedOn) END as Age
    FROM 
        Fields pf
    WHERE
        pf.Value IS NOT NULL
)
SELECT  
    (SELECT COUNT(Age) 
     FROM ages 
     WHERE ages.Age > 17 AND ages.Age < 25) AS '18-24',
    (SELECT COUNT(Age) 
     FROM ages 
     WHERE ages.Age > 24 AND ages.Age < 31) AS 25-30',
    (SELECT COUNT(Age) 
     FROM ages 
     WHERE ages.Age > 30 AND ages.Age < 36) AS '31-35',
    (SELECT COUNT(Age) 
     FROM ages 
     WHERE ages.Age > 35) AS '> 35'

在此列(值)中,生日存储为字符串值,格式如下:02.10.1987 00:00:00(DD.MM.YYY HH:mm:ss)。

在这个Fields表格中,我有3500行。

数据如下所示:

02.10.1987 00:00:00
29.07.1967 12:33:11
02.10.1987 00:00:00
15.11.1959 00:00:00
07.11.1975 00:00:00

当我运行这样的过程时,SQL服务器返回以下错误:

  

从字符串

转换日期和/或时间时转换失败

如果我将Top 100000放在存储过程中,则执行程序正常,如下所示:

WITH ages AS
(
SELECT TOP 100000 datediff(year, CONVERT(datetime, pf.Value, 104), pf.CreatedOn)
       END as Age
FROM Fields pf
where pf.Value is not null
)
SELECT  (select count(Age) FROM ages where ages.Age>17 and ages.Age<25) as '18-24',
        (select count(Age) FROM ages where ages.Age>24 and ages.Age<31)  as '25-30',
        (select count(Age) FROM ages where ages.Age>30 and ages.Age<36)  as '31-35',        
        (select count(Age) FROM ages where ages.Age>35)  as '>35'

正如我所写,我只有3500行。

我的所有数据格式都正确,存储过程的所有非空值。

有人知道为什么会这样吗?为什么它使用Top插入,但不是没有它?

具有内存分配的东西是SQL Server做的吗?

2 个答案:

答案 0 :(得分:0)

这些都是长镜头,但也许可以尝试:

  • 重建表格中的所有索引
  • 运行EXEC sp_recompile N'Fields';

完全有可能是TOP 10000&amp;直接SELECT生成不同的执行计划,但我仍然不明白为什么会影响数据。

你确定没有其他事情发生吗?查询的两个连接都使用相同的用户?两个连接的区域设置是否相同?

答案 1 :(得分:0)

尝试将CONVERT(datetime,pf.Value,104)更改为Cast(pf.Value as DateTime)或 如果你真的不关心日期的时间戳部分,请加注(pf.Value as Date)。

另外,如果pf.CreatedOn的类型是varchar,那就用它来做同样的事情。

    WITH ages AS
(
    SELECT 
        DATEDIFF(YEAR, cast(pf.Value AS DateTime), CAST(pf.CreatedOn AS DATETIME)) END as Age
    FROM 
        Fields pf
    WHERE
        pf.Value IS NOT NULL
)

对不起......我没有意识到你的约会时间已经过了#34;你不是来自这里的,是吗?&#34;格式。尝试这种不太吸引人的解决方案。

--TestData
 DECLARE @x NVARCHAR(MAX) = '29.11.1956 00:00:00'
 DECLARE @x NVARCHAR(MAX) = '2.1.1956 00:00:00'

--Solution
 select    
 -- Monthpart dd.mm.yyy
 SUBSTRING(@x, 
    CHARINDEX('.', @x) + 1 ,
        CHARINDEX('.',@x,CHARINDEX('.', @x) + 1 )-  CHARINDEX('.', @x)  -1) + '/' 
 --DayPart dd.mm.yyy
  + SUBSTRING(@x, 1, CHARINDEX('.', @X) - 1)  + '/'
 --YearPart   
  + RIGHT(LEFT (@x, CHARINDEX(' ',@x) -1),4)