【问题标题】:Convert MSAccess Query to TSQL将 MS Access 查询转换为 SQL
【发布时间】:2014-12-16 20:53:59
【问题描述】:

您好,我正在尝试将 MSAccess 查询转换为 TSQL。

编辑更多细节;

用户通过 ODBC 使用我的数据库作为源表创建了一个 MS Access 应用程序。 根据我们的政策,MS Access 仅用于临时分析,不存储数据。 好吧,这种用法在他的应用程序中创建了一堆新表,并将其用作生产数据。我已经复制了他的逻辑并通过触发脚本将其移至 SQL Server。我现在正在尝试将他的历史数据填充到 SQL 中。

在我的数据库中 MATERIAL_NUMBER 是 varchar(30) 数据类型。 我们对收购有各种不同的约定。

我们收购的其中一家公司有 PN,例如“000000000000000001”。 Access 应用程序的创建者不喜欢前导零会在导出时提示 Excel 说“数字存储为文本”,因此在他的表格中,他将以下内容应用于材料编号以将“000000000000000001”存储为“1”

这是访问查询。

IIf(IsNumeric([MATERIAL_NUMBER])=0,[MATERIAL_NUMBER],CStr(CDbl([MATERIAL_NUMBER]))) AS PN_FORMAT

现在的问题是我无法将他的桌子加入我的桌子,因为他破坏了 MATERIAL_NUMBER。 我要做的是对他的转换进行逆向工程,以便我可以将值更新回标准约定。

这是我在 SQL 中尝试过的

CASE WHEN ISNUMERIC([MATERIAL_NUMBER])=1 
   THEN CONVERT(VARCHAR(30),CAST([MATERIAL_NUMBER] AS BIGINT))
   ELSE [MATERIAL_NUMBER] 
END AS PN_FORMAT

我收到以下错误

消息 8114,第 16 级,状态 5,第 3 行 将数据类型 varchar 转换为 bigint 时出错。

这是完整的查询

TRUNCATE TABLE PN_FORMAT;

INSERT INTO PN_FORMAT
SELECT O.BASE_PART_CODE, O.MATERIAL_NUMBER, 
  CASE WHEN ISNUMERIC([MATERIAL_NUMBER])=1 
    THEN CONVERT(VARCHAR(30),CAST([MATERIAL_NUMBER] AS BIGINT))
    ELSE [MATERIAL_NUMBER] 
  END AS PN_FORMAT
FROM [DCA-DB-326\MSBI_RS].[AGS_DATAMART].dbo.OPR_MATERIAL_DIM O

编辑更新的尝试; 根据建议,我尝试了这个...

TRUNCATE TABLE TEMP_PN_FORMAT;
INSERT INTO TEMP_PN_FORMAT
SELECT O.BASE_PART_CODE, 
O.MATERIAL_NUMBER, 
CASE WHEN ISNUMERIC([MATERIAL_NUMBER])=1 THEN CONVERT(VARCHAR(30),CAST([MATERIAL_NUMBER] AS FLOAT))
ELSE [MATERIAL_NUMBER] END AS PN_FORMAT
FROM [DCA-DB-326\MSBI_RS].[AGS_DATAMART].dbo.OPR_MATERIAL_DIM O

这次没有错误,但只有较小的数字有效。 647 按预期工作并且能够加入,4000192 没有。

【问题讨论】:

  • 您在 MATERIAL_NUMBER 字段中的数据不是数字。你检查过吗?也许有破折号(-)?
  • 或者是一种货币? technet.microsoft.com/en-us/library/…
  • 是的,材料编号中存在明显的非数字数据,但 CASE ISNUMERIC 不应该评估这些数据并且只尝试将它们转换为其余部分吗?

标签: sql-server tsql ms-access


【解决方案1】:

MATERIAL_NUMBER 列中有一些数值数据无法转换为整数

旧代码将数字数据转换为 Double

您也许可以像这样解决问题:

CASE WHEN ISNUMERIC([MATERIAL_NUMBER])=1 THEN CONVERT(VARCHAR(30),CAST([MATERIAL_NUMBER] AS FLOAT))
ELSE [MATERIAL_NUMBER] END AS PN_FORMAT

但是,我想知道您为什么需要这样做。您有一列包含文本数据。它必须是文本,否则您甚至不需要检查IsNumeric() 您最终会将其转换为...更多文本。也许您正在尝试获得特定的格式,但这似乎也很奇怪。 Double 与数字一样广泛。你不可能改变任何东西。更有可能的是,这段代码避免了 Access 中的一些问题; Sql Server 中甚至可能不存在的问题。除此之外,这首先是糟糕的数据库设计。如果您有像这样的列这样的混合类型,则架构有问题。


根据您的编辑,这对我有用:

select cast(cast('000000000004000192' as int) as varchar(10))
---------- 4000192 (1 行受影响)

你也可以考虑这个答案:

Better techniques for trimming leading zeros in SQL Server?

或者,最好将新表中的列类型更改为整数。

【讨论】:

  • 我已经更新了我原来的问题以提供更多细节。简而言之,是的,糟糕的设计决策。我现在尝试重新创建,以便恢复。我会按照回帖的建议尝试。
  • @RobertPulido 根据新信息更新了我的答案
【解决方案2】:

我能够通过使用以下方法解决此问题。 我从试图复制手段复制结果的思考过程出发。

TRUNCATE TABLE TEMP_PN_FORMAT;
INSERT INTO TEMP_PN_FORMAT
SELECT O.BASE_PART_CODE, 
O.MATERIAL_NUMBER, 
CASE WHEN ISNUMERIC(MATERIAL_NUMBER)=1 THEN SUBSTRING(MATERIAL_NUMBER, PATINDEX('%[^0 ]%', MATERIAL_NUMBER + ' '), LEN(MATERIAL_NUMBER)) 
ELSE MATERIAL_NUMBER END AS PN_FORMAT
FROM [DCA-DB-326\MSBI_RS].[AGS_DATAMART].dbo.OPR_MATERIAL_DIM O

【讨论】:

  • 虽然它有效,但 SUBSTRING 和 PATINDEX 是对数据库中每一行执行的昂贵函数。乔尔的答案可能会更好
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-20
  • 1970-01-01
  • 2019-11-17
相关资源
最近更新 更多