查询从DataTable获取最大字段长度

时间:2018-03-06 22:58:34

标签: vb.net postgresql linq datatable

我正在处理一个使用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查询(或其他任何内容)是否有可行的方法来实现同一目标?谢谢你的帮助。

2 个答案:

答案 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之前解析为强类型。这将是确定这些精确度量的适当时机,因为它将消除对每行进行后处理及其相关成本的需要。