使用老式的经典ADO, 而不是 ADO.NET,如何从JavaScript将日期值传递给存储过程?JS在IIS7上的经典ASP页中运行。SQL Server是2012(1)。
已解决:请参见下面的答案。长话短说,结果是通过JSON字符串查找器将其返回给我,该字符串忽略了具有可变日期值的属性。
我在SQL Server中有一个存储过程:
create procedure test(@n int, @d datetime) as begin select @n n, @d d; end;
我在经典的ASP页面中有一些JavaScript代码:
var conn = new ActiveXObject("ADODB.Connection"); var cmd = new ActiveXObject("ADODB.Command"); conn.Open(connectionString); cmd.ActiveConnection = conn; cmd.CommandType = adCmdStoredProc; cmd.CommandText = 'dbo.test'; cmd.Parameters.Append(cmd.CreateParameter('@n', adInteger, adParamInput, 4, 123)); var param = cmd.CreateParameter('@d', adDate, adParamInput); param.Value = (new Date('01/01/2000')).getVarDate(); cmd.Parameters.Append(param); var rs = cmd.Execute();
我回来从SP总是有预期值@n(123以上),并且始终null为@d。connectionString必须可以,因为它确实调用了SP,而且绝对是我想调用的SP;如果我对其进行更改,它们会反映在返回的内容中。
@n
null
@d
connectionString
我getVarDate()从下面的答案中得到了答案。我也尝试adDBDate过各种数据类型。
getVarDate()
adDBDate
(如果你走另一条路——也就是说,你有一个 JScript 对象,并且你分配了一个包含 VT_DATE 类型变体的属性——JScript 引擎应该自动将它转换为等效的 JScript 日期。) 如果您的浏览器提供商没有为您编写 getVarDate 方法,那么您自己编写代码并不难,但是为了使其适用于所有情况,您必须处理一些涉及日期之前的棘手特殊情况时代。 我所知道的使代码正确的最好方法是首先将其转换为自纪元以来的整数天和小数天的原始数,我注意到这是 12 月30日午夜,而不是1899年 31 月。一旦你有了它,你就可以特殊情况下之前的值。 非常小心四舍五入!我建议您在转换为 OA 格式之前将值舍入到最接近的秒数。因为 OA 格式的 -1.9999999 正好在 1899 年 12 月 30 日午夜之前,而 -2.0 是 12 月 28 日午夜,如果将前者四舍五入到后者,则只是将几分之一秒舍入为两天错误。
我出于测试目的编写了上述测试SP;您可能已经注意到它并没有做很多有用的工作。在生产中,我必须将日期传递给现有的SP。该SP的详细信息不会使这个问题更加清晰。如果绝对必要,我 可以 编写一个包装程序SP,该包装程序将日期作为字符串接收并进行转换。但是我想了解这里出了什么问题,而且我们已经有足够多的半冗余SP使数据库混乱。那只是做事情的可怕方式。
(1)@@ version =’Microsoft SQL Server 2012(SP1)-11.0.3381.0(X64)2013年8月23日20:08:13版权所有(c)Windows NT 6.0(Build 6002)上的Microsoft Corporation Enterprise Edition(64位) :Service Pack 2)(系统管理程序)
弄清楚了; 我错了,我什至没有提到实际上引起问题的那部分。
rs.Fields.Item("d").Value返回type的变体adDBTimeStamp。
rs.Fields.Item("d").Value
adDBTimeStamp
这是在充当Web服务并返回JSON的ASP中,而我正在使用的JSON字符串标识符只是忽略带有adDBTimeStamp值的属性。一切都从数据库恢复正常,然后又被删除。
事实证明,ADODB.Command的CreateParameter方法非常注重日期的处理。
CreateParameter
所以:
var rs = RecordSetToObjArray(cmd.Execute(); // ... // Convert variant dates into something the JSON stringifier groks. function GetADOFieldValue(field) { switch (field.Type) { case adDBTimeStamp: case adDate: case adDBDate: case adDBTime: case adFileTime: if ('undefined' === '' + field.Value) return null; return new Date('' + field.Value); default: return field.Value; } } // Given recordset from ADODBCommand.Execute(), return as array of JSON // objects. // Also convert variant dates into something the JSON stringifier groks. // If an SP returns multiple recordsets, that's on you. function RecordSetToObjArray(rs) { var rtn = []; var fieldNames = []; for (var i = 0; i < rs.Fields.Count; ++i) { fieldNames.push(rs.Fields.Item(i).Name); } rtn.FieldNames = fieldNames; while (!rs.EOF) { var rec = {}; for (var i = 0; i < fieldNames.length; ++i) { rec[fieldNames[i]] = GetADOFieldValue(rs.Fields.Item(fieldNames[i])); } rtn.push(rec); rs.MoveNext(); } return rtn; } function RecordSetToScalar(rs) { if (rs.RecordCount == 0 || rs.Fields.Count == 0) return null; return GetADOFieldValue(rs.Fields.Item(0)); }