AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 138357
Accepted
Geoff Dawdy
Geoff Dawdy
Asked: 2016-05-13 06:36:04 +0800 CST2016-05-13 06:36:04 +0800 CST 2016-05-13 06:36:04 +0800 CST

9 位邮政编码报告 LEN 为 12

  • 772

我正在尝试解决使邮政编码正确显示的一些困难。

原始电子表格包含 5 位和 9 位混合格式的邮政编码。在导入过程之后,这些 9 位邮政编码报告的长度为 12 位。现在,当我尝试在 9 位邮政编码中添加连字符“-”时,由于长度错误和各种数据类型转换问题,我得到了异常结果和错误。

使用用于从电子表格导入数据的 openrowset 方法执行导入。

当我查询新导入的数据时,我看到邮政编码显示与电子表格中的相同,但长度错误。

SELECT ZIP,
    LEN(LTRIM(RTRIM(Zip))) AS ZIPLENGTH
  FROM XLS_IMPORT
ZIP         ZIPLENGTH
45750       5
432013256   12
441153221   12
44120       5
441351362   12

如果我选择数据的左 9 个字符,所有内容都会转换为浮点数,并且邮政编码现在不可读。

SELECT LEFT(ZIP,9) FROM XLS_IMPORT
WHERE LEN(LTRIM(RTRIM(ZIP))) = 12
ZIP
4.32013e+
4.42034e+
4.56637e+
4.41153e+
4.36045e+
4.41133e+

如何将这些邮政编码恢复为正确的 9 位数字?或者如何在报告长度为 12 的 9 位邮政编码中添加连字符?我的最终目标是简单地让 9 位邮政编码在中间有一个连字符。

该Zip列的数据类型是float.

我刚刚发现我的一些电子表格(例如 NJ 和 NY)在邮政编码的前导 0 之前有一个撇号。我将需要研究如何处理 '0xxxx 邮政编码以使其适用于我的一些电子表格导入。

sql-server sql-server-2012
  • 3 3 个回答
  • 2376 Views

3 个回答

  • Voted
  1. Best Answer
    Solomon Rutzky
    2016-05-16T11:43:36+08:002016-05-16T11:43:36+08:00

    邮政编码是字符串,而不是数字。其中一些有 1 个甚至 2 个(但不超过 2 个)前导零。导入表中的数据类型应VARCHAR(10)使其可以容纳 5 位和 9 位 + 连字符邮政编码。即使您永远不必存储其他国家/地区的邮政编码,即使这些值只有数字(即 0 - 9),该数据仍然是字符串数据,就像电话号码一样。

    根据您的其他问题中显示的导入查询(自动导入和导出进程 EXCEL -> SQL SERVER -> EXCEL without using SSIS):

    SELECT * INTO XLS_IMPORT
    FROM OPENROWSET('Microsoft.ACE.OLEDB.12.0',
    'Excel 12.0; Database=C:\RSG_ETL_Tool\Ohio\OH.xls; HDR=YES; IMEX=1',
    'SELECT * FROM [OH$]');
    

    我建议不要依赖SELECT INTO构造来创建XLS_IMPORT表,而是手动创建导入表,然后使用INSERT INTO ... SELECT FROM OPENROWSET()构造。这样做可以让您做以下事情来改善这种情况:

    1. 创建ZipCode字段为VARCHAR(10)
    2. 在使用STR函数的过程中转换值,对于 的初始FLOAT值432013256,将返回 432013256而不是4.32013e+008(这是转换为 时得到的VARCHAR)。
    3. 使用以下内容修复任何丢失的前导零:

      CASE
         WHEN LEN(LTRIM(STR(@ZipColumn))) BETWEEN 3 AND 4
                THEN RIGHT('0000' + LTRIM(STR(@ZipColumn)), 5)
         WHEN LEN(LTRIM(STR(@ZipColumn))) BETWEEN 7 AND 8
                THEN RIGHT('0000' + LTRIM(STR(@ZipColumn)), 9)
         WHEN LEN(LTRIM(STR(@ZipColumn))) IN (5, 9) THEN LTRIM(STR(@ZipColumn))
         ELSE 'BadZipCode'
      END
      

    例子:

    DECLARE @ZipColumn FLOAT = 032013256.000000;
    
    SELECT CASE
              WHEN LEN(LTRIM(STR(@ZipColumn))) BETWEEN 3 AND 4
                     THEN RIGHT('0000' + LTRIM(STR(@ZipColumn)), 5)
              WHEN LEN(LTRIM(STR(@ZipColumn))) BETWEEN 7 AND 8
                     THEN RIGHT('0000' + LTRIM(STR(@ZipColumn)), 9)
              WHEN LEN(LTRIM(STR(@ZipColumn))) IN (5, 9) THEN LTRIM(STR(@ZipColumn))
              ELSE 'BadZipCode'
           END;
    

    回报:

    032013256
    

    理想情况下,您会将电子表格中的列定义固定为字符串。但即使您这样做,保留此代码可能仍然是一个好主意。

    我的最终目标是简单地让 9 位邮政编码在中间有一个连字符。

    考虑到这一目标,以下内联 TVF 可用于将FLOAT值转换为VARCHAR,并为 ZIP + 4 值添加连字符。

    iTVF 代码:

    CREATE FUNCTION dbo.FormatZIPCode(@NumericZIPCode FLOAT)
    RETURNS TABLE
    WITH SCHEMABINDING
    AS RETURN
    
    WITH string AS
    (
        SELECT  LTRIM(STR(@NumericZIPCode)) AS [Value],
                LEN(LTRIM(STR(@NumericZIPCode))) AS [Size]
    ), converted AS
    (
    SELECT  CASE
                    WHEN st.[Value] IS NULL THEN NULL
                    WHEN st.[Size] BETWEEN 3 AND 4
                        THEN RIGHT('0000' + st.[Value], 5)
                    WHEN st.[Size] BETWEEN 7 AND 8
                        THEN RIGHT('0000' + st.[Value], 9)
                    WHEN st.[Size] IN (5, 9)
                        THEN st.[Value]
                    ELSE 'BadZipCode'
                END AS [ZIP],
                st.[Size] AS [OriginalSize]
        FROM        string st
    )
    SELECT  IIF(cnv.[OriginalSize] >= 7, STUFF(cnv.[ZIP], 6, 0, '-'), cnv.[ZIP])
                   AS [FormattedZIPCode]
    FROM        converted cnv;
    

    测试:

    SELECT  *
    FROM    (VALUES (CONVERT(FLOAT, NULL)), (1), (12), (123), (1234), (12345),
                    (123456), (1234567), (12345678), (123456789)) src(val)
    CROSS APPLY dbo.FormatZIPCode(src.[val]) frmt;
    

    回报:

    val         FormattedZIPCode
    ---------   ----------------
    NULL        NULL
    1           BadZipCode
    12          BadZipCode
    123         00123
    1234        01234
    12345       12345
    123456      BadZipCode
    1234567     00123-4567
    12345678    01234-5678
    123456789   12345-6789
    

    为了更清楚地了解建议的内容,以下显示了上面提到的所有建议:

    CREATE TABLE dbo.XLS_IMPORT
    (
      Col1     DataTypeForCol1,
      Col2     DataTypeForCol2,
      ZIPCode  VARCHAR(10),
      ...
    );
    
    INSERT INTO dbo.XLS_IMPORT (Col1, Col2, ZIPCode, ...)
      SELECT xls.Col1, xls.Col2, zip.[FormattedZIPCode], ...
      FROM   OPENROWSET('Microsoft.ACE.OLEDB.12.0',
             'Excel 12.0; Database=C:\RSG_ETL_Tool\Ohio\OH.xls; HDR=YES; IMEX=1',
             'SELECT * FROM [OH$]')
      CROSS APPLY dbo.FormatZIPCode(xls.[ZIP]) zip;
    

    一些电子表格“知道”有前导零,因此在 Excel 中的字段前加上一个撇号,以便 Excel 将值视为字符串而不是数字(例如'01234)。在这种情况下,您可以使用该REPLACE函数删除该撇号。

    -- Test incoming string data (potentially prefixed with a single apostrophe)
    SELECT  src.[val], frmt.[FormattedZIPCode],CHARINDEX(N'''', src.[val])
    FROM    (VALUES (NULL), (N'''01234'), (N'''123456789'), (N'123'), (N'12345678')) src(val)
    CROSS APPLY dbo.FormatZIPCode(REPLACE(src.[val], N'''', N'')) frmt;
    

    但是,您不能REPLACE在所有电子表格上使用,因为将ZIP列作为数字的电子表格在CONVERT_IMPLICIT将值传递给REPLACE函数时会执行 a 并且转换后的值将采用科学计数法(例如1.23457e+008)。因此,如果您不能确定 将返回哪种数据类型OPENROWSET,那么您可以使用IIF(或者CASE如果使用 2012 年之前的 SQL Server 版本)并CHARINDEX测试是否存在撇号。如果数据以 形式返回,那么在将值传递到时将发生FLOAT隐式转换,因为其中没有撇号,并且转换后的值只会到而不是到。VARCHARCHARINDEX1.23457e+008CHARINDEXdbo.FormatZIPCode

    -- Test handling incoming data as both numeric and string
    SELECT  src.[val], frmt.[FormattedZIPCode],CHARINDEX(N'''', src.[val])
    FROM    (VALUES (CONVERT(FLOAT, NULL)), (1), (12), (123), (1234), (12345),
                    (123456), (1234567), (12345678), (123456789)) src(val)
    CROSS APPLY dbo.FormatZIPCode(
           IIF(CHARINDEX(N'''', src.[val]) > 0, REPLACE(src.[val], N'''', N''), src.[val])
                                 ) frmt;
    
    SELECT  src.[val], frmt.[FormattedZIPCode]
    FROM    (VALUES (N'''01234'), (N'''123456789'), (N'123'), (N'12345678')) src(val)
    CROSS APPLY dbo.FormatZIPCode(
           IIF(CHARINDEX(N'''', src.[val]) > 0, REPLACE(src.[val], N'''', N''), src.[val])
                                 ) frmt;
    
    • 10
  2. Kenneth Fisher
    2016-05-16T13:04:19+08:002016-05-16T13:04:19+08:00

    显然,此时您已经意识到邮政编码应该存储为字符串而不是数字。如果没有其他原因,只是外国(非美国)邮政编码经常包含字母。

    也就是说,让我们回到你原来的问题。为什么当你有 5 个数字时你的长度显示为 5,而当你只存储 9 个数字时你的长度显示为 12。这与LEN 函数的工作方式有关。如果您查看此示例代码的 XML 执行计划:

    CREATE TABLE #temp (MyFloat float, MyStr varchar(50))
    INSERT INTO #temp VALUES (12345,'12345'),(123456789,'123456789')
    SELECT len(MyFloat), len(MyStr) FROM #temp
    

    你会注意到这两行:

    <ScalarOperator ScalarString="len(CONVERT_IMPLICIT(varchar(23),[tempdb].[dbo].[#temp].[MyFloat],0))">
    <ScalarOperator ScalarString="len([tempdb].[dbo].[#temp].[MyStr])">
    

    您是否看到CONVERT_IMPLICIT在varchar(23)获取LEN. (据我所知LEN,实际上只适用于字符串。)

    因此,让我们看一下CONVERT_IMPLICIT通过显式转换实际返回的内容。

    SELECT CONVERT(varchar(23), MyFloat) FROM #temp
    

    在此处输入图像描述

    现在我们看到它12345转换得很干净。 123456789但是需要科学记数法。给我们1.23457e+008。长度为 12 个字符。

    • 8
  3. Geoff Dawdy
    2016-05-13T08:46:37+08:002016-05-13T08:46:37+08:00

    邮政编码作为浮点数据类型导入。我无法将列直接从 float 转换为 varchar(10)。相反,我将数据类型从浮点数转换为十进制,然后从十进制转换为 varchar(10)。现在,该列正在报告正确的邮政编码位数 (9)。现在允许在 9 位邮政编码中插入连字符。

    • 1

相关问题

  • SQL Server - 使用聚集索引时如何存储数据页

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve