【问题标题】:Sorting Access Data (date times in the wrong format)对访问数据进行排序(日期时间格式错误)
【发布时间】:2012-04-23 17:50:14
【问题描述】:

问题:

我表中的某些字段的日期格式错误,它们是使用 C# 中的 .ToString() 方法进行格式化的,但我打错了,输入如下:MM/dd/yyyy hh:mm/ss tt

现在,如果您仔细观察,您会看到 MM/dd/yyyy hh:mm ----> '/'

假设是 ':'

然后我在我的 c# 代码中修复它,(意味着一些值被格式化:MM/dd/yyyy hh:mm:ss tt

问题是,我正在尝试按日期顺序从表中选择值(我不能只按“日期字段名称此处”排序),因为某些字段的格式错误,带有“/”


我尝试了什么:

现在,我想既然时间总是在同一个地方(这对我来说很重要),我可以只取时间中数字的子字符串并对其进行排序;首先是 AM,然后是 PM

我可以按 MID([ColumnName],11,2) , MID([ColumnName],14,2), MID([ColumnName],16,2) 排序,因为无论分隔符如何,每个日期始终位于格式 M/dd/yyyy hh/mm/ss tt

所以我尝试了:


(
SELECT SN, StatusCode, Time, Mid(Time,14,2) + ':'+ Mid(Time,17,2) AS TTI
FROM OrderStatus
WHERE StatusCode = 'Finished' and Left(Time,10) = '4/20/2012'
AND Time LIKE '*AM'
ORDER BY Val(Mid([Time],11,2)) DESC
)
UNION ALL (
SELECT SN, StatusCode, Time, Mid(Time,14,2) + ':'+ Mid(Time,17,2) AS TTI
FROM OrderStatus
WHERE StatusCode = 'Finished' and Left(Time,10) = '4/20/2012'
AND Time LIKE '*PM'
ORDER BY Val(Mid([Time],11,2)) DESC
);

只是想看看是否会按小时订购,但它没有给我这个:

如您所见(在小时字段中)01 然后 02 然后又回到 01...?

无论如何有一个类似的问题here我已经悬赏,如果你回答这个问题或那个问题,你将获得赏金,这对于其他情况也很有用

编辑: 我真正想回答的问题是如何按字符串的子字符串排序;对不起,我可以发誓我已经改变了这个,说我想按任何字符串/日期/任何我想知道如何做的事情的单个数字排序: 按 Val 排序(Mid(ColumnName,StartPos,EndPos))

注意: Order By 给出完全错误的结果。

【问题讨论】:

  • 是的,但不是真的...,有 21000 多条记录,我不能简单地调用 .replace,因为之前的日期中有 / 来划分年月日,我无法替换值在子字符串中的确切位置,因为某些日期在月份中有 10/11/12(一个额外的数字),我想我可以做一个 if(date.length == 22) 和 21 等来陪伴,但这确实违背了这个问题供将来使用的目的。我真正想知道的是如果可能的话,如何按列中字符串的子字符串排序..
  • 这是一个非常好的建议,虽然我会投赞成票
  • 我认为解决问题总是更好,然后找到一种复杂的方法来完成工作而不必修复它。由于这将是一次性的事情,因此您可以使用一个临时字段作为日期,使用一个临时字段来拆分有问题的字段。然后简单的替换应该很容易。 (我看到它没有回答按子字符串排序的问题......;))

标签: c# ms-access


【解决方案1】:

我的直觉是创建一个函数并在 Access UPDATE 语句中运行一次,以将存储的值转换为所需的格式。

下面的快速和肮脏的功能可以同时处理一位数和两位数的月份。它需要 Access 2000 或更高版本。

? FixTimeData("4/20/2012 01:34/09 PM")
4/20/2012 01:34:09 PM
? FixTimeData("12/20/2012 01:34/09 PM")
12/20/2012 01:34:09 PM

Public Function FixTimeData(ByVal pIn As String) As String
    Dim astrPieces() As String
    Dim strOut As String
    astrPieces = Split(pIn, " ")
    strOut = astrPieces(0) & " " & _
        Replace(astrPieces(1), "/", ":") & " " & _
        astrPieces(2)
    FixTimeData = strOut
End Function

然后是类似这样的UPDATE语句……

UPDATE OrderStatus
SET time_field = FixTimeData(time_field)
WHERE time_field Like "*/*/*/*";

如果您在 ADO 而不是 DAO 下运行语句,请在 WHERE 子句中更改为 ANSI 通配符。

WHERE time_field Like "%/%/%/%";

如果您希望相同的语句在 ADO 或 DAO 下工作,或者使用 ANSI 通配符和 Alike。

WHERE time_field ALike "%/%/%/%";

我使用time_field 作为您使用Time 的字段名称,因为Time 是保留字。如果您无法更改字段名称,请在查询中用方括号将其括起来。

编辑:我的目的是修复数据,以便您可以根据Right(time_field, 11)进行可靠排序

Edit2:要根据“高位”分钟数字进行排序,看看您是否可以在此方法的基础上进行构建,假设您已修复存储的日期/时间字符串:

? Left(Format(Minute("4/23/2012 04:02:40 PM"), "00"), 1)
0
? Left(Format(Minute("4/23/2012 04:12:40 PM"), "00"), 1)
1
? Left(Format(Minute("4/23/2012 04:22:40 PM"), "00"), 1)
2

虽然Minute() 函数接受字符串,但我可能会使用CDate() 将字符串显式转换为日期/时间,然后再将其提供给Minute()

所以......如果我没有完全误入歧途......在这样的查询中尝试这种方法:

SELECT
    Left(Format(Minute(CDate(time_field)), "00"), 1) AS upper_minute,
    OrderStatus. *
FROM OrderStatus
ORDER BY 1;

【讨论】:

  • 这很好地解决了我的问题(我可以使用 c# 非常相似地解决它),但它忽略了问题的要点;我如何按列的子字符串对表格进行排序:我所有的谷歌结果都表明我可以按左/右/中(列名,长度)或在中的情况下(列名,开始,长度)排序,但事实并非如此似乎在工作
  • 你修复数据后,Right(time_field, 11)不给你正确的排序吗?
  • 是的,确实如此!但​​是如果我尝试或发现需要按上分钟列排序,hh:-->m
  • 我投了你的票,你的关注是/非常感谢 (>^_^)>
【解决方案2】:

将日期归档为真实日期字段而不是字符串。使用 2 次更新将所有值迁移到新字段 - 一个选择具有旧格式的所有行,另一个选择新格式。删除日期字符串列并享受正确键入的数据。

如果您真的想将其保留为字符串,至少请确保使用对排序/本地化安全的标准 ISO8601 格式(大约 YYYY-MM-DDTHH:MM.ssss)。

【讨论】:

  • 有 8000 多行代码不是我编写的,我在 c# 中以字符串的形式访问这些数据,我不能简单地将其更改为日期时间,否则我已经这样做了。
  • 我对你的回答投了赞成票,因为我感谢你的关注,你说得非常正确(应该是真实的日期,而不是字符串),但它没有回答我的问题
  • 谢谢。如果您最终接触到此代码,我仍然建议您切换到可排序的字符串格式。 HansUp 的转换看起来正是您所需要的。
【解决方案3】:

我没有要测试的表,但我想给出我的想法。
我将把 Left、Mid 和 Right 函数与 CDate 和 CInt 函数一起使用。
我将得到时间字段的最左边部分(16 个字节),为秒和 PM/AM 指示符添加一个“:00”。可以使用 CDate 将此字符串转换为日期。
然后我将获取秒部分并将它们转换为整数。
现在可以在不使用 UNION 的情况下对第一部分 (TTI) 和第二部分 (TTS) 进行排序。
但是有一个问题,有些日期包含只有 1 个字符的月份,(es:4 月 4 日 vs 12 月 12 日)幸运的是,我们可以使用 IIF 运算符为中、右和左选择正确的数字。

编辑:

SELECT 
SN, StatusCode, Time, 
IIF(Len(Time) = 22, Left(Time,16) + ':00' + Right(Time,2), Left(Time,15) + ':00' + Right(Time,2)) AS TTI, 
IIF(Len(Time) = 22, Mid(Time, 18,2), Mid(Time, 17,2)) as TTS
FROM OrderStatus 
WHERE StatusCode = 'Finished' and Left(Time,10) = '4/20/2012' 
ORDER BY CDate(IIf(Len([Time])=22,Left([Time],16)+ ':00 ' + Right([Time],2),Left([Time],15)+ ':00 ' + Right([Time],2))) DESC , 
         CInt(IIf(Len([Time])=22,CInt(Mid([Time],18,2)),CInt(Mid([Time],17,2)))) DESC;

【讨论】:

  • 这是左右的错误用法吧? Left 有 2 个参数而不是 3 个
  • 'Length' 是否可以与'Val' 互换?它不认识它
  • @JustinKirk,哦,另一个错误。函数是 Len。抱歉,我正在开发一个 C# 项目,有时我倾向于将两者混合使用 :)
  • 另外你有 2 个 if 语句,在它们中你都放了一个 'as' 子句,然后最后你对它们进行排序,......但其中只有 1 个可能存在
  • hmm... 它的工作方式,它按外部秒列排序,TTI 列都是'#Error's' 我假设这是因为 if 语句看到它是 22 位数字,我对IIF一无所知,无论如何你不能按'as'语句中生成的列名排序,你必须将查询表达式作为排序子句: ORDER BY CInt(Mid(Time, 18,2) ), CInt(Mid(Time, 17,2)), CDate(Left(Time,15) + ':00' + Right(Time,2)) DESC
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-05-29
  • 1970-01-01
  • 1970-01-01
  • 2021-12-22
  • 1970-01-01
  • 2016-02-01
  • 2021-04-05
相关资源
最近更新 更多