【问题标题】:Set default table value to left pad with zeros将默认表值设置为左填充零
【发布时间】:2015-01-05 21:00:04
【问题描述】:

如果在数据输入期间未输入最大字符数,您如何创建一个表格,其中每列将用零填充。
我知道在数据输入到表格后如何填充,但我不知道在数据输入时如何填充。

例子....

为定义为 nvarchar(15) 的列导入值...

RTS092
3ISUEX
ABCDEFGHIJ
9485028

数据输入/导入后存储在表中的值......

000000000RTS092
0000000003ISUEX
00000ABCDEFGHIJ
000000009485028

【问题讨论】:

  • 各种帮助者提出了在从表中提取数据时预先添加零的方法。如果列具有唯一约束,则值 FOO0FOO 都应该被视为相等,即它们都是 000000000000FOO 的表示。这适用于您的问题吗?

标签: sql-server tsql ssis


【解决方案1】:

我如何左填充一个值?

我遵循将最大长度字符串添加到目标列然后剪掉最后 N 位的模式。在这种情况下,'000000000000000' + 'RTS092' 产生的值是 000000000000000RTS092,这显然太长了,所以我应用右子字符串操作来保留最右边的字符。

我发现这是一种“愚蠢”的方法,但效果很好。很少有逻辑会出错。您可能可以通过仅在需要时以最少的填充量来减少一些微观时间单位,但是这种方法的简单性通常比维持正确的逻辑和保持正确的维护更重要

应用垫

在我看来,这里有 3 种方法:在飞行中对其进行改造,在着陆前对其进行修复,在访问时对其进行翻译。

变换

最明智的方法是在数据出现在表中之前对其进行修复。这就是ETL 的全部T。在 SSIS 中,我将使用以下逻辑将派生列组件添加到我的数据流中

ISNULL(MyCol) ? 
    REPLICATE(@[User::PadCharacter],@PadLength) :
    RIGHT((REPLICATE(@[User::PadCharacter],@[User::PadLength]) + LTRIM(RTRIM(MyCol))),@[User::PadLength])

这是一种通用方法,假设我创建了 2 个 SSIS 级别变量:PadCharacter 和 PadLength。我指定了0 的PadCharacter 和15 的PadLength。如果您发现需要使用填充字符 X 和长度为 20,那么您更改的是值,而不是公式。

它可以正确处理 NULL 值以及两边的空白填充。

在它落地之前修复它

正如 Greg 所说,您可以使用INSTEAD OF 触发器在数据接触表格之前修复数据。我会在我无法修复应用程序以防止不良数据进入表格时提倡这种方法。我还将对增加的插入成本进行基准测试,并确保我的业务用户了解对系统的潜在影响。

在访问时翻译它

假设您无法在运行中修复它并且触发器的成本太高,您可以查看在桌子上创建一个computed column。谁在乎我们是否将其存储为“RTS092”,列应用程序访问是使用上面重复的相同公式定义的,以始终向用户显示填充值。

代码大概

ALTER TABLE
    dbo.MyTable
ADD
    MyComputedCol AS RIGHT(( REPLICATE(N'0',15) + COALESCE(NULLIF(LTRIM(RTRIM(MyCol)), ''), '') ), 15) 

比米尔

由于我喜欢展示我的作品,下面的 Biml 将创建上面的包。这确实使用 bimlscript,因为字符串操作会导致发射器难以确定长度,因此我明确地将其强制为具有指定长度的 DT_WSTR 数据类型。下载Bids Helper。添加 .biml 文件,粘贴以下代码,但粘贴时请注意 Visual Studio "helping" you

<Biml xmlns="http://schemas.varigence.com/biml.xsd">
    <# int padLength=15;#>
    <Connections>
        <OleDbConnection Name="CM_OLE" ConnectionString="Data Source=localhost\dev2014;Initial Catalog=tempdb;Provider=SQLNCLI10.1;Integrated Security=SSPI;Auto Translate=False;" />
    </Connections>
    <Packages>
        <Package ConstraintMode="Linear" Name="so_27787812">
            <Variables>
                <Variable DataType="String" Name="QuerySource">
                    <![CDATA[SELECT
    D.MyCol
FROM
(
    VALUES
    (N'RTS092')
,   (N'3ISUEX')
,   (N'ABCDEFGHIJ')
,   (N'9485028')
,   (N' UGH ')
,   (NULL)
)D(MyCol);]]>
                </Variable>
                <Variable DataType="String" Name="PadCharacter">0</Variable>
                <Variable DataType="Int32" Name="PadLength"><#=padLength#></Variable>
            </Variables>
            <Tasks>
                <Dataflow Name="DFT LeftPad">
                    <Transformations>
                        <OleDbSource ConnectionName="CM_OLE" Name="OLE_SRC Query">
                            <VariableInput VariableName="User.QuerySource"></VariableInput>
                        </OleDbSource>
                        <!--
                            Left pad our column with our specified character.
                            Assumes source column is called MyCol
                            Creates a new column callec der_MyCol
                        -->
                        <DerivedColumns Name="DFT LeftPad">
                            <Columns>
                                <Column DataType="String" Name="der_MyCol" Length="<#=padLength#>">ISNULL([MyCol]) ? REPLICATE(@[User::PadCharacter], @PadLength) : RIGHT((REPLICATE(@[User::PadCharacter], @[User::PadLength]) + LTRIM(RTRIM([MyCol]))), @[User::PadLength])</Column>
                            </Columns>
                        </DerivedColumns>
                        <DerivedColumns Name="DFT Do nothing" />

                    </Transformations>
                </Dataflow>
            </Tasks>
        </Package>
    </Packages>
</Biml>

【讨论】:

    【解决方案2】:
    right('000000000000000'+ rtrim(@str), 15)
    

    @str 是字符串。就查询而言,

    SELECT COL, right(('000000000000000'+ rtrim(COL)), 15) PaddedString FROM YourTable
    

    来源:Most efficient T-SQL way to pad a varchar on the left to a certain length?

    如果您希望在数据进入表之前实现填充,您可以有一个暂存表来存放原始数据,然后处理数据并将其移动到第二个表中。或者在源中应用上述方法,以便它被构建然后进入目标表。这里YourTable 是源表。

    【讨论】:

    • 这假设数据已经存储在表中,对吗?
    • 第二行代码适用于存储在表中的数据。任何临时字符串的第一个。
    【解决方案3】:

    您可能不应该在数据库中执行此操作,而是在提交数据的应用程序中执行此操作,但如果您必须在数据库中执行此操作,我建议您在插入时使用类似以下:

    CREATE TRIGGER myTriggerINSERT
    ON myTableName
    INSTEAD OF INSERT
    AS
    DECLARE @myField NVARCHAR(15)
    SET @myField = (SELECT myField FROM inserted)
    INSERT myTableName (myField) VALUES(right('000000000000000'+ rtrim(@myField), 15))
    

    【讨论】:

    • 您的触发器有两个主要缺陷。首先,它不支持多行操作。其次是插入现在将有两行而不是一行,因为您没有将其指定为触发器的 INSTEAD。话虽如此,我认为这里不需要触发器,因为他们表示这是用于数据导入。
    • 不错的方法,但如果大多数记录的长度已经是 15 个字符,那么它的性能就会很差。可能你应该先有一个IF 来检查长度。
    • 很好发现@SeanLange! :)
    • @SeanLange 我错过了数据导入的重点。您对触发器的 INSTEAD 是正确的-我将编辑答案。在任何情况下,我都会避免在数据库中这样做——如果是数据导入,SSIS 会是一个更好的地方。
    猜你喜欢
    • 2011-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-01
    • 1970-01-01
    相关资源
    最近更新 更多