我正在处理一个使用DataTable
在PostgreSQL数据库中创建新表的函数。我试图改善"在this Gist中找到的代码并将其转换为VB.NET用于我的环境,但是当我尝试从DataTable
定义中获取一些PostgreSQL列定义时,我遇到了一些困难。
在我的代码中,我采用原始DataTable
( SourceData
),将其转换为{{1}然后调用GetSchemaTable
方法来获取字段定义
DataReader
这一般工作正常,但是如果DataTable的字段没有使用某些属性显式构建(例如,Dim TempReader As DataTableReader = SourceData.CreateDataReader
Dim SchemaTable As DataTable = TempReader.GetSchemaTable()
或NumericPrecision
用{{}},则此方法的一个限制是1}} types),架构表不能正确地将这些信息提供给我的表创建代码。 Gist显然通过简单地定义任何NumericScale
列来处理这一点,而没有明确指定Decimal
列的这些值。这对我没用。
我想要做的是查询原始Decimal
中的该列,了解该字段的最大长度 - 更具体地说,是{{1}的任何字段中小数点后面的位数我想在Integer
中为DataTable
字段执行类似操作,以确定是否需要包含在PostgreSQL中创建字段时的时间。< / p>
以下是我用于获取PostgreSQL列定义的代码示例。它现在 绝对不完整 (我需要添加默认值处理,而不是NULL等),我可能还需要更改方法定义以传递我已定义为参数的大多数变量,以便真正实现我所要求的,但这就是我要开始的。
Decimal
虽然我非常熟悉SQL,但我对Linq不太熟悉。在PostgreSQL中,我可能只是写一个类似的问题的查询(我测试了这个查询并且它显示才能正常工作):
DateTime
对于原始DataTable
,使用Linq查询(或其他任何内容)是否有可行的方法来实现同一目标?谢谢你的帮助。
答案 0 :(得分:1)
处理DateTime
部分非常简单:
Dim HasTime = dataTable.Any(Function (d) d.dateTimeColumn.TimeOfDay <> TimeSpan.Zero)
我认为您可以做的最好的事情类似于您的SQL查询,它转换为字符串并获取小数点后的长度:
Dim DecimalScale = Users.Where(Function (d) d.Userid.ToString().IndexOf(".") >= 0).Select(Function (d) d.Userid.ToString().Length-d.Userid.ToString().IndexOf(".")-1).Max()
答案 1 :(得分:1)
十进制结构在documentation of it constructor中明确定义,它采用整数数组。
您可以使用Decimal.GetBits检索现有Decimal
的此定义数组。一旦你有了这个数组,只需要一点位操作来检索一个Decimal的比例因子,它定义了Decimal
的字符串表示中小数点右边的位数。
以下内容是Decimal
类型的扩展方法。
Module DecimalExtensions
<Extension()>
Public Function Scale(d As Decimal) As Int32
' From: Decimal Constructor (Int32[]) - Remarks
' https://msdn.microsoft.com/en-us/library/t1de0ya1(v=vs.100).aspx
' The binary representation of a Decimal number consists of a 1-bit sign,
' a 96-bit integer number, and a scaling factor used to divide
' the integer number and specify what portion of it is a decimal fraction.
' The scaling factor is implicitly the number 10, raised to an exponent ranging from 0 to 28.
' bits is a four-element long array of 32-bit signed integers.
Dim bits As Int32() = Decimal.GetBits(d)
' bits [0], bits [1], and bits [2] contain the low, middle, and high 32 bits of the 96-bit integer number.
' bits [3] contains the scale factor and sign, and consists of following parts:
' Bits 0 to 15, the lower word, are unused and must be zero.
' Bits 16 to 23 must contain an exponent between 0 and 28,
' which indicates the power of 10 to divide the integer number.
' i.e.: the number digits to the right of the decimal mark
' so, mask off bits 0 to 15 --> lower 2 bytes, and the upper byte
' mask = &H00FF0000
Dim mask As Int32 = &HFF0000
Dim masked As Int32 = bits(3) And mask
' shift masked value 16 bits to the left to obtain the scaleFactor
Dim scaleFactor As Int32 = masked >> 16
Return scaleFactor
End Function
End Module
使用示例:
Dim d1 As Decimal = 1.0123456789012345678901234567D
Debug.Print(d1.Scale.ToString()) ' prints 28
d1 = 1D
Debug.Print(d1.Scale.ToString()) ' prints 0
d1 = 1.1D
Debug.Print(d1.Scale.ToString()) ' prints 1
d1 = 12345678901234567890.012345679D
Debug.Print(d1.Scale.ToString()) ' prints 10
您在评论中提到DataTable是从CSV填充的。希望您在将值添加到DataTable之前解析为强类型。这将是确定这些精确度量的适当时机,因为它将消除对每行进行后处理及其相关成本的需要。