在用户定义类型列表(SQL Server 2008中)
-
25-09-2019 - |
题
我试图定义一个新的类型,并没有太多的运气找到如何使用它们内部列出的任何信息。基本上我的新类型将包含两个列表,可以说x和类型SqlSingle(用户定义的类型是写在C#),则这甚至可能?
Y的如果没有,你应该如何去在SQL Server 2008中柱模拟的arbitary长度的两个列表?
我可能要对这个错误的方式,但它是我能在那一刻想到的最好的办法。任何帮助非常赞赏。
解决方案
您可以使用在CLR UDT一个List<T>
- 虽然CLR类型结构,这应该是不变的,所以一个ReadOnlyCollection<T>
会是一个更好的选择,如果你不具备的可变性非常令人信服的理由。你需要在这两种情况下知道的是,SQL不知道如何使用列表本身;你不能简单地暴露列表类型作为公共IList<T>
或IEnumerable<T>
并在您的快乐的方式,像你将能够在纯.NET做。
通常避开这将是暴露出Count
财产和一些方法,以获取各个独立的列表项的方式。
此外,在这种情况下,而不是维持SqlSingle
情况下,两个单独的列表,我想创建一个额外的类型来表示一个点,这样你就可以独立管理,并通过它周围的SQL如果您需要:
[Serializable]
[SqlUserDefinedType(Format.Native)]
public struct MyPoint
{
private SqlSingle x;
private SqlSingle y;
public MyPoint()
{
}
public MyPoint(SqlSingle x, SqlSingle y) : this()
{
this.x = x;
this.y = y;
}
// You need this method because SQL can't use the ctors
[SqlFunction(Name = "CreateMyPoint")]
public static MyPoint Create(SqlSingle x, SqlSingle y)
{
return new MyPoint(x, y);
}
// Snip Parse method, Null property, etc.
}
的主要类型将看起来像这样:
[Serializable]
[SqlUserDefinedType(Format.UserDefined, IsByteOrdered = true, MaxByteSize = ...)]
public struct MyUdt
{
// Make sure to initialize this in any constructors/builders
private IList<MyPoint> points;
[SqlMethod(OnNullCall = false, IsDeterministic = true, IsPrecise = true)]
public MyPoint GetPoint(int index)
{
if ((index >= 0) && (index < points.Count))
{
return points[index];
}
return MyPoint.Null;
}
public int Count
{
get { return points.Count; }
}
}
如果您需要SQL才能够获得所有点的序列,那么你可以添加一个枚举法序列类型,以及:
[SqlFunction(FillRowMethodName = "FillPointRow",
TableDefinition = "[X] real, [Y] real")]
public static IEnumerable GetPoints(MyUdt obj)
{
return obj.Points;
}
public static void FillPointRow(object obj, out SqlSingle x, out SqlSingle y)
{
MyPoint point = (MyPoint)obj;
x = point.X;
y = point.Y;
}
您可能会认为这是可能的使用IEnumerable<T>
和/或使用实例方法,而不是一个静态的,但不要甚至懒得想,这是行不通的。
所以,这样你可以在SQL Server中使用所产生的类型是:
DECLARE @UDT MyUdt
SET @UDT = <whatever>
-- Will show the number of points
SELECT @UDT.Count
-- Will show the binary representation of the second point
SELECT @UDT.GetPoint(1) AS [Point]
-- Will show the X and Y values for the second point
SELECT @UDT.GetPoint(1).X AS [X], @UDT.GetPoint(1).Y AS [Y]
-- Will show all the points
SELECT * FROM dbo.GetPoints(@UDT)
希望这有助于让你在正确的轨道上。 UDT的可以得到相当复杂的管理时,他们正在处理的列表/序列数据。
另外请注意,您会明显地需要添加序列化方法,生成器方法,聚合方法,等等。它可以是相当严峻的考验;确保这其实是你想要去的,因为一旦你开始增加UDT列它可以是非常困难的,如果你意识到你做出了错误的选择做出改变的方向。
其他提示
你描述通常归词典 - 也就是说,存储在单独的表中,每一个项目行 - 而不是试图将它们塞进一个单独的列中。如果你能分享更多的信息你正在尝试完成,也许我们可以提供更多的援助。
编辑 - 建议表的结构:
-- route table--
route_id int (PK)
route_length int (or whatever)
route_info <other fields as needed>
-- waypoint table --
route_id int (PK)
sequence tinyint (PK)
lat decimal(9,6)
lon decimal(9,6)
waypoint_info <other fields as needed>