【问题标题】:Get date from substring in where clause of a sql select *EDITED*从 sql select *EDITED* 的 where 子句中的子字符串获取日期
【发布时间】:2012-01-26 08:53:43
【问题描述】:

我有一个日期与其他文本一起存储在文本字段中。他们为什么不把它放在日期字段中?我不知道,但我现在没有能力改变它。在代码的其他地方,我这样做是为了获取该日期在一定范围内的记录。它工作正常。

For Each i As InventoryItem In inventoryList
  index = i.Notes.IndexOf("on {") + 4
  scanned_dt = i.Notes.Substring(index, i.Notes.Length - index - 1)
  If Date.Parse(scanned_dt) >= startDate And Date.Parse(scanned_dt) <= endDate Then
    ...

我现在正在尝试获取某个日期范围内的项目总数。 此 sql 语句用于获取所有日期的总数。如何更新 Where 子句以仅计算 i.Notes 包含 startDateendDate 之间日期的项目

Dim sql As String = "Select COUNT(inv_PartNum) from lester.inventory i join lester.vendor v on v.vendor_ID = i.vendor_ID Where v.vendor_Name = '" + vendorName + "' AND i.inv_Desc LIKE '%" + size + "%'"

*已编辑* 我想出了这个 sql select 语句:

SELECT COUNT(i.inv_PartNum) FROM cdms.lester.inventory AS I
join CDMS.lester.vendor AS v on v.vendor_ID = i.vendor_ID Where v.vendor_Name = 'JVE-285' 
AND CONVERT(DATETIME,
SUBSTRING(i.inv_Notes, CharIndex('on {', i.inv_Notes)+4, len(i.inv_Notes)-(CharIndex('on {', i.inv_Notes) + 4)
),101) BETWEEN '01-01-2011' AND '04-04-2011'

但我收到此错误: 将 char 数据类型转换为 datetime 数据类型导致 datetime 值超出范围。

为了弄清楚我创建了以下 sql select 语句:

SELECT * FROM (
SELECT i.inv_Notes, 
CONVERT(DATETIME,SUBSTRING(i.inv_Notes, CharIndex('on {',i.inv_Notes)+4,LEN(i.inv_Notes)-(CharIndex('on {', i.inv_Notes) + 4)),101) AS d
FROM cdms.lester.inventory AS i
join CDMS.lester.vendor AS v ON v.vendor_ID = i.vendor_ID WHERE v.vendor_Name = 'JVE-285') AS s

我的 inv_Notes 列包含类似“Assigned to Tool Trailer {JVE-285} on {4/8/2011}”的字符串

当我运行如上所示的查询时,我会得到我的 inv_Notes 列和日期列。日期均以“2011-04-08 00:00:00.000”这种格式显示,并且没有抛出任何错误。

但是,一旦我添加了 WHERE 子句,我就会收到错误消息:将 char 数据类型转换为 datetime 数据类型导致 datetime 值超出范围。

我尝试过以各种方式格式化日期,但总是出错...

WHERE s.d > CONVERT(DATETIME, '2011-1-1', 101)

WHERE s.d < GetDate()

WHERE s.d > '20110101'

WHERE s.d >= '2011-01-01'

WHERE s.d >= '01-01-2011'

WHERE s.d > '01/01/2011'

编辑 我也试过 WHERE s.d IS NOT NULL 并得到同样的错误。这显然不是我认为它在 WHERE 处的 b/c 工作方式,转换应该已经成功发生。

解决方案 搞定了

SELECT * FROM (
SELECT i.inv_Notes,
SUBSTRING(i.inv_Notes, CharIndex('} on {',i.inv_Notes)+6,LEN(i.inv_Notes)-(CharIndex('} on {', i.inv_Notes) + 6))
AS d
FROM cdms.lester.inventory AS i
join CDMS.lester.vendor AS v ON v.vendor_ID = i.vendor_ID WHERE v.vendor_Name = 'JVE-285') AS s
WHERE PARSENAME(REPLACE(s.d, '/', '.'), 1)+
RIGHT('00'+PARSENAME(REPLACE(s.d, '/', '.'), 3),2)+
RIGHT('00'+PARSENAME(REPLACE(s.d, '/', '.'),2),2) BETWEEN '20110407' AND '20110409'

我尝试将其转换为 int 并进行整数比较,但随后出现错误。发现问题在于某些 inv_Notes 字段包含诸如“Item added {3/11/2011}”之类的数据,这些都不符合内部选择的条件,所以在我看来,如果它没有在内部选择中被选中,对于外部选择的条件,这应该不是问题。但是,它试图将 2011{311 转换为 int 并引发错误。我确定它试图将其转换为迄今为止,这就是我遇到以前问题的原因。

【问题讨论】:

  • 您使用的是什么数据库?我会推荐写一个存储过程

标签: sql sql-server sql-server-2008 select substring


【解决方案1】:

尝试在语句中添加类似于此 WHERE 子句的内容:

WHERE CAST(SUBSTRING(Notes, CHARINDEX(Notes, 'on {') + 4, Length?) AS Date) BETWEEN StartDate And EndDate

想法是通过组合 SubString 和 CharIndex 方法提取字符串的相关部分,然后将此表达式转换为日期格式,以便可以与 Between 运算符一起使用。

祝你好运

第 2 部分更新:

由于您已经能够选择日期但不能在 where 子句中使用它,我建议将其用作 select 语句,然后将其包装在另一个语句中,例如:

SELECT *
FROM
(SELECT CAST(SUBSTRING(Notes, CHARINDEX(Notes, 'on {') + 4, Length?) AS Date) AS dtmNotes)
WHERE dtmNotes BETWEEN Start And End

这只是为了说明,但在包装中包含整个第一个 select 语句。

【讨论】:

  • 想出了相同的解决方案,但出现错误。见上面的编辑。
  • 不。我也尝试过这种方式,但只是为了更好地衡量而再次这样做。没有运气。
  • 感谢您的帮助,但这就是我所拥有的。上面的 WHERE 语句被添加到嵌套 SELECT 的外带的最后一行。这就是我无法弄清楚的。它正在执行子字符串转换/转换(我已经尝试了两种方法)而没有错误。
  • 在您的选择语句中,日期是对齐到字段的左侧还是右侧,默认情况下,数字和日期是右对齐的,如果它仍然显示在左侧,那么我们可以假设它仍然表示为字符串,并且转换/转换尚未工作。
  • 这有点奇怪,因为我记得在所有情况下,真实的日期都是正确对齐的(可能是旧版本的)我现在能想到的就是尝试将您的日期作为 YYYYMMDD 格式的数字像 20111005 一样,然后对数值进行中间运算。
【解决方案2】:

试试这个……

假设嵌入日期的表名为InventoryList,列名为inv_Notes


SELECT *
FROM InventoryList i
WHERE

CAST(
substring(
i.inv_Notes,
patindex('%on {%',i.inv_Notes)  +4,
patindex('%[0-9][0-9][0-9][0-9]}%',i.inv_Notes)-patindex('%on {%',i.inv_Notes)
) as Datetime)

BETWEEN '12/1/2011' AND '12/23/2011

编辑:更严格地寻找“9/9999}”模式


SELECT *
FROM InventoryList i
WHERE

CAST(
substring(
i.inv_Notes,
patindex('%on {%',i.inv_Notes)  +4,
patindex('%[0-9]/[0-9][0-9][0-9][0-9]}%',i.inv_Notes)-patindex('%on {%',i.inv_Notes)
) as Datetime)

BETWEEN '12/1/2011' AND '12/23/2011

【讨论】:

  • 我得到同样的错误。如果我这样做 SELECT CAST( substring( i.inv_Notes, patindex('%on {%',i.inv_Notes) +4, patindex('%[0-9][0-9][0-9][0-9]}%',i.inv_Notes)-patindex('%on {%',i.inv_Notes) ) as Datetime) FROM lester.inventory AS i 我会在没有错误的列中获得日期时间,就像我的版本一样。
  • 模式'on {'总是一致的吗?意思是它总是存在吗?总是小写吗?
  • 当你将这个 where 子句添加到上面的选择查询时会发生什么 - WHERE (patindex('%on {%',i.inv_Notes) 0) AND (patindex('%[0- 9][0-9][0-9][0-9]}%',i.inv_Notes) 0)
  • 是的,模式总是一致的。如果我添加那个“WHERE”子句,它的运行就像它不存在一样。 CAST 似乎工作得很好,因为我得到了日期时间列。当我在选择中有演员表时,日期显示为“2011-04-08 00:00:00.000”当我在选择中只有子字符串部分没有演员表时,它返回“4/8/2011”
  • 好的,描述的“供应商”部分可以格式化为 {Vendor-9999} 意味着有四个数字后跟一个“}”。如果是这样,请尝试使用更严格的模式,例如 patindex('%[0-9]/[0-9][0-9][0-9][0-9]}%',i.inv_Notes) 这个它应该只查找并匹配此模式 '9/9999}'
猜你喜欢
  • 1970-01-01
  • 2013-09-09
  • 2013-11-19
  • 1970-01-01
  • 1970-01-01
  • 2013-08-24
  • 1970-01-01
  • 2014-09-26
  • 2015-11-18
相关资源
最近更新 更多