【问题标题】:Concatenating Time and DateTime in where clause在 where 子句中连接时间和日期时间
【发布时间】:2016-09-14 15:18:35
【问题描述】:

我正在尝试将SmallDateTime 字段和Time 值(标量值函数的结果)组合成DateTime,但我不断收到以下错误:

从字符转换日期和/或时间时转换失败 字符串。


以下是贯穿始终的变量:

DECLARE @STARTDATETIME AS DATETIME
DECLARE @ENDDATETIME AS DATETIME
SELECT @STARTDATETIME = '8/29/2016 12:00:00'
SELECT @ENDDATETIME = '8/30/2016 12:00:00'

列定义:

FT_START_DATE   SmallDateTime
FT_END_DATE     SmallDateTime
FT_START_TIME   Int
FT_END_TIME     Int

日期字段不包含时间戳。时间字段基本上是 24 小时时间,没有冒号分隔符。 (例如:142350 = 14:23:50)

这是我的查询中调用的函数:

USE [PWIN171]
GO
/****** Object:  UserDefinedFunction [dbo].[dbo.IPC_Convert_Time]    Script Date: 9/13/2016 4:50:49 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[dbo.IPC_Convert_Time] 
(
    @time int
)
RETURNS time
AS
BEGIN
    DECLARE @Result time
    SELECT @Result = CONVERT(time
                            , STUFF(
                                STUFF(
                                    RIGHT('000000' + CONVERT(varchar(6), @time), 6) 
                                , 5, 0, ':')
                            , 3, 0, ':')
                        )
    RETURN @Result
END

示例 1 - 失败:

这就是我所追求的。

SELECT * FROM FT WITH (NOLOCK)
WHERE
CAST(FT_END_DATE AS DATETIME) + DBO.[dbo.IPC_Convert_Time](FT_END_TIME) BETWEEN @STARTDATETIME AND @ENDDATETIME;

示例 2 - 作品:

这个运行,但它不会从 8/29 获取记录,因为结束日期将在 8/29 的 12:00:00 之前。

SELECT * FROM FT WITH (NOLOCK)
WHERE
FT_END_DATE BETWEEN @STARTDATETIME AND @ENDDATETIME
AND CAST(FT_END_DATE AS DATETIME) + DBO.[dbo.IPC_Convert_Time](FT_END_TIME) BETWEEN @STARTDATETIME AND @ENDDATETIME;

我想我可以做一个拆分参数并检查结束时间是否也在参数的时间部分之间的方法,但这似乎是朝着错误方向迈出的一步。该错误似乎仅在 where 子句中没有 FT_START_DATEFT_END_DATE 的其他用法时出现。

时间转换功能在我创建的每个场景中都能正常工作。我什至尝试了示例 2,其参数可以使其与示例 1 涵盖的数据 100% 重叠,以防有错误数据导致错误,但它运行良好。

我也不知道错误发生的确切位置,因为它只引用 select 语句开始的行,而不是代码中的实际位置。

为什么会这样?

更新:

TIMEFROMPARTS 不可用,因为它在 SQL Server 2008 上

【问题讨论】:

  • 没有第 29 个月。如果您必须使用日期文字,请使用未分隔的日期格式 20160829 或完整的 ISO 8601 格式。此外,无论IPC_Convert_Time 做什么,您都不需要字符串操作来创建time 值。可能还有许多其他错误,例如,如果 FT_END_DATE 已经是日期类型,为什么还要转换它?为什么使用smalldatetime 而不是datedatetime
  • @PanagiotisKanavos - 字段由供应商设置,无法更改。我转换为datetime,因为如果我不这样做,+ 操作的最终结果也将是smalldatetime,因此将四舍五入。为什么我不需要字符串操作来从 int 列创建时间值?
  • 重点是您使用美国特定的日期字符串,这保证在美国以外的任何地方都失败。由于您没有提及 where 发生错误,因此这是可能失败的第一件事。字符串操作使您面临更多此类问题。使用 TIMEFROMPARTS 创建一个 time 值,因为您已经拥有每个部分
  • 这个问题的范围是在一个数据库内,在一家美国公司内,在一个时区内。虽然系统设计得不好,但它的一致性是无可挑剔的。
  • 然而,它失败了。在不知道 where 的情况下,它要么是文字,要么是函数。为什么不把函数换成TIMEFROMPARTS,去掉字符串呢?

标签: sql-server sql-server-2008


【解决方案1】:

如果我理解正确,这可以更简单:

试试这个:

DECLARE @d DATE=GETDATE();
DECLARE @t TIME=GETDATE();
SELECT @d;
SELECT @t;
SELECT CAST(@d AS datetime)+CAST(@t AS datetime);

pure 日期和 pure 时间可以简单地添加以组合它们...

更新再次阅读您的问题...

试试这个

SELECT FT_END_DATE
      ,FT_END_TIME 
      ,CAST(FT_END_DATE AS DATETIME) + DBO.[dbo.IPC_Convert_Time](FT_END_TIME) AS CombinedTime
      ,* 
FROM FT

看看你的尝试是否做对了。

如果是,创建 CTE 并对命名列进行过滤可能会有所帮助。

有时引擎不会按照您期望的顺序工作

由于 CTE 是完全内联的,这很有可能无济于事......

SQL Server 以引发此类错误而闻名,因为类型检查发生在转换发生之前...

使用给定的 SELECT 和 INTO #tbl 将结果集推送到新表中并从那里执行您的逻辑可能是一个想法......

【讨论】:

  • 还有SELECT @STARTDATETIME = '8/29/2016 12:00:00' 行,这可能只是可能引发转换错误的行之一
  • @PanagiotisKanavos,真的...永远不应该使用文化特定的日期文字...
  • IPC_Convert_Time 函数可能也应该替换为内置的 TIMEFROMPARTS 函数。
  • @PanagiotisKanavos,好吧,AFAIU OP 有一个像“174112”这样的时间,必须转换为“17:41:12”。使用STUFF...在字符串基础上执行此操作似乎是有效的...
  • 感谢您的更新。查询运行良好。我做了一个彻底的测试,我抓取了这个查询应该找到的数据,把它放到一个类型匹配的表中,然后在所有记录上运行这个函数。它通过了。这告诉我问题不在于函数,而与 where 子句的解释方式有关。
猜你喜欢
  • 1970-01-01
  • 2023-03-21
  • 2010-12-29
  • 1970-01-01
  • 2016-10-28
  • 1970-01-01
  • 2013-11-24
  • 1970-01-01
  • 2018-11-03
相关资源
最近更新 更多