带有日期时间参数的 SQLCLR 自定义聚合
SQLCLR custom aggregate with datetime parameter
嗨,
我post几个月前就这个提出了一个关于 CLR 用户定义聚合的问题。
这对 int 非常有用。但是现在我想用日期时间参数来做同样的功能。
但是我找不到工作。
像这样,代码将无法运行...问题出在 sql 服务器上生成此错误的读取函数上:
System.ArgumentOutOfRangeException: Les graduations doivent être comprises entre DateTime.MinValue.Ticks et DateTime.MaxValue.Ticks.
Nom du paramètre : ticks
System.ArgumentOutOfRangeException:
à System.DateTime..ctor(Int64 ticks)
à sMaxDatetime.Read(BinaryReader reader)
所以我尝试用 this 将我的 sql 日期时间转换为刻度,但它不起作用。我在转换为日期时间时遇到 OverflowException。
我找到了这个 post,但我似乎无法将我的日期时间映射到 BinaryReader...
所以我 运行 没有办法做我的汇总...
你有想法吗?
这是实际代码:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Diagnostics.Eventing.Reader;
using System.Globalization;
using Microsoft.SqlServer.Server;
using System.Text;
using System.Collections;
using System.IO;
[Serializable]
[SqlUserDefinedAggregate(
Format.UserDefined,
IsInvariantToOrder = true,
IsInvariantToNulls = true,
IsInvariantToDuplicates = true,
MaxByteSize = -1)]
public struct sMaxDatetime : IBinarySerialize
{
#region Helpers
private struct MyData
{
public string Data { get; set; }
public DateTime? Group { get; set; }
public int CompareTo(MyData other)
{
if (Group == null)
return other.Group == null ? 0 : -1;
if (other.Group == null)
return 1;
return Group.Value.CompareTo(other.Group.Value);
}
public static bool operator < (MyData left, MyData right)
{
return left.CompareTo(right) == -1;
}
public static bool operator > (MyData left, MyData right)
{
return left.CompareTo(right) == 1;
}
}
#endregion
private MyData _maxItem;
public void Init()
{
_maxItem = default(MyData);
}
public void Accumulate(SqlString data, SqlDateTime group)
{
if (!data.IsNull && !group.IsNull)
{
var current = new MyData
{
Data = data.Value,
Group = group.Value,
};
if (current > _maxItem)
{
_maxItem = current;
}
}
}
public void Merge(sMaxDatetime other)
{
if (other._maxItem > _maxItem)
{
_maxItem = other._maxItem;
}
}
public SqlString Terminate()
{
return _maxItem.Data;
}
public void Read(BinaryReader reader)
{
//if (reader.ReadBoolean())
//{
_maxItem.Data = reader.ReadString();
_maxItem.Group = new DateTime(reader.ReadInt64());
//}
//else
//{
// _maxItem = default(MyData);
//}
}
public void Write(BinaryWriter writer)
{
if (_maxItem.Group.HasValue)
{
writer.Write(true);
writer.Write(_maxItem.Group.Value.ToString());
writer.Write(_maxItem.Data);
}
else
{
writer.Write(false);
}
}
}
PS : 我有这个与 sql_variant 相关的 post 未关闭谁可以做这些技巧,但我无法工作。
我认为您在使用自定义结构来保存日期时间和名称时过于努力。这是我想出的:
using System;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.IO;
[Serializable]
[SqlUserDefinedAggregate(Format.UserDefined, Name = "sMaxDatetime", MaxByteSize = -1)]
public struct SO33215409 : IBinarySerialize
{
private SqlString _data;
private SqlDateTime _latest;
public void Init()
{
_data = SqlString.Null;
_latest = SqlDateTime.MinValue;
}
public void Accumulate(SqlString data, SqlDateTime dt)
{
if (dt > _latest)
{
_data = data;
_latest = dt;
}
}
public void Merge (SO33215409 Group)
{
if (Group._latest > _latest)
{
_data = Group._data;
_latest = Group._latest;
}
}
public SqlString Terminate ()
{
return _data;
}
public void Write (BinaryWriter w)
{
w.Write(_data.IsNull);
w.Write(_latest.IsNull);
if (_data.IsNull == false)
{
w.Write(_data.Value);
}
if (_latest.IsNull == false)
{
w.Write(_latest.Value.Ticks);
}
}
public void Read(BinaryReader r)
{
bool dataIsNull = r.ReadBoolean();
bool latestIsNull = r.ReadBoolean();
if (dataIsNull)
{
_data = SqlString.Null;
}
else
{
_data = r.ReadString();
}
if (latestIsNull)
{
_latest = SqlDateTime.Null;
}
else
{
DateTime d = new DateTime(r.ReadInt64());
_latest = new SqlDateTime( d );
}
}
}
然后 SQL 去练习它:
WITH cte AS (
SELECT * FROM (VALUES
('Manager' , 'emp 1' , dateadd(year, -35, getdate())),
('Manager' , 'emp 2' , dateadd(year, -42, getdate())),
('Developer' , 'emp 3' , dateadd(year, -36, getdate())),
('Developer' , 'emp 4' , dateadd(year, -45, getdate())),
('Developer' , 'emp 5' , dateadd(year, -22, getdate()))
) AS x([Type], [Name], [DOB])
)
SELECT [Type], dbo.[sMaxDatetime]([Name], [DOB])
FROM cte
GROUP BY [Type]
嗨,
我post几个月前就这个
这对 int 非常有用。但是现在我想用日期时间参数来做同样的功能。
但是我找不到工作。 像这样,代码将无法运行...问题出在 sql 服务器上生成此错误的读取函数上:
System.ArgumentOutOfRangeException: Les graduations doivent être comprises entre DateTime.MinValue.Ticks et DateTime.MaxValue.Ticks.
Nom du paramètre : ticks
System.ArgumentOutOfRangeException:
à System.DateTime..ctor(Int64 ticks)
à sMaxDatetime.Read(BinaryReader reader)
所以我尝试用 this 将我的 sql 日期时间转换为刻度,但它不起作用。我在转换为日期时间时遇到 OverflowException。
我找到了这个 post,但我似乎无法将我的日期时间映射到 BinaryReader...
所以我 运行 没有办法做我的汇总...
你有想法吗?
这是实际代码:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Diagnostics.Eventing.Reader;
using System.Globalization;
using Microsoft.SqlServer.Server;
using System.Text;
using System.Collections;
using System.IO;
[Serializable]
[SqlUserDefinedAggregate(
Format.UserDefined,
IsInvariantToOrder = true,
IsInvariantToNulls = true,
IsInvariantToDuplicates = true,
MaxByteSize = -1)]
public struct sMaxDatetime : IBinarySerialize
{
#region Helpers
private struct MyData
{
public string Data { get; set; }
public DateTime? Group { get; set; }
public int CompareTo(MyData other)
{
if (Group == null)
return other.Group == null ? 0 : -1;
if (other.Group == null)
return 1;
return Group.Value.CompareTo(other.Group.Value);
}
public static bool operator < (MyData left, MyData right)
{
return left.CompareTo(right) == -1;
}
public static bool operator > (MyData left, MyData right)
{
return left.CompareTo(right) == 1;
}
}
#endregion
private MyData _maxItem;
public void Init()
{
_maxItem = default(MyData);
}
public void Accumulate(SqlString data, SqlDateTime group)
{
if (!data.IsNull && !group.IsNull)
{
var current = new MyData
{
Data = data.Value,
Group = group.Value,
};
if (current > _maxItem)
{
_maxItem = current;
}
}
}
public void Merge(sMaxDatetime other)
{
if (other._maxItem > _maxItem)
{
_maxItem = other._maxItem;
}
}
public SqlString Terminate()
{
return _maxItem.Data;
}
public void Read(BinaryReader reader)
{
//if (reader.ReadBoolean())
//{
_maxItem.Data = reader.ReadString();
_maxItem.Group = new DateTime(reader.ReadInt64());
//}
//else
//{
// _maxItem = default(MyData);
//}
}
public void Write(BinaryWriter writer)
{
if (_maxItem.Group.HasValue)
{
writer.Write(true);
writer.Write(_maxItem.Group.Value.ToString());
writer.Write(_maxItem.Data);
}
else
{
writer.Write(false);
}
}
}
PS : 我有这个与 sql_variant 相关的 post 未关闭谁可以做这些技巧,但我无法工作。
我认为您在使用自定义结构来保存日期时间和名称时过于努力。这是我想出的:
using System;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.IO;
[Serializable]
[SqlUserDefinedAggregate(Format.UserDefined, Name = "sMaxDatetime", MaxByteSize = -1)]
public struct SO33215409 : IBinarySerialize
{
private SqlString _data;
private SqlDateTime _latest;
public void Init()
{
_data = SqlString.Null;
_latest = SqlDateTime.MinValue;
}
public void Accumulate(SqlString data, SqlDateTime dt)
{
if (dt > _latest)
{
_data = data;
_latest = dt;
}
}
public void Merge (SO33215409 Group)
{
if (Group._latest > _latest)
{
_data = Group._data;
_latest = Group._latest;
}
}
public SqlString Terminate ()
{
return _data;
}
public void Write (BinaryWriter w)
{
w.Write(_data.IsNull);
w.Write(_latest.IsNull);
if (_data.IsNull == false)
{
w.Write(_data.Value);
}
if (_latest.IsNull == false)
{
w.Write(_latest.Value.Ticks);
}
}
public void Read(BinaryReader r)
{
bool dataIsNull = r.ReadBoolean();
bool latestIsNull = r.ReadBoolean();
if (dataIsNull)
{
_data = SqlString.Null;
}
else
{
_data = r.ReadString();
}
if (latestIsNull)
{
_latest = SqlDateTime.Null;
}
else
{
DateTime d = new DateTime(r.ReadInt64());
_latest = new SqlDateTime( d );
}
}
}
然后 SQL 去练习它:
WITH cte AS (
SELECT * FROM (VALUES
('Manager' , 'emp 1' , dateadd(year, -35, getdate())),
('Manager' , 'emp 2' , dateadd(year, -42, getdate())),
('Developer' , 'emp 3' , dateadd(year, -36, getdate())),
('Developer' , 'emp 4' , dateadd(year, -45, getdate())),
('Developer' , 'emp 5' , dateadd(year, -22, getdate()))
) AS x([Type], [Name], [DOB])
)
SELECT [Type], dbo.[sMaxDatetime]([Name], [DOB])
FROM cte
GROUP BY [Type]