【问题标题】:Converting Access calculated field to T-SQL将 Access 计算字段转换为 T-SQL
【发布时间】:2019-02-04 08:08:51
【问题描述】:

我正在尝试手动迁移实际上是一个表达式的访问查询(访问中的计算字段。

有问题的访问表达式是:

Balance2: (IIf(([OutstandingBalance]-nz([PartsStockForJobTotals]! 
[Expr1]))>0,([OutstandingBalance]-nz([PartsStockForJobTotals]![Expr1])),0))* 
[Part Assembly Link Table]![Qty]

到目前为止,我已经成功编写了 SQL 代码:

SELECT
IIF([Order Transactions Table].[OutstandingBalance] - 
ISNULL([PartsStockForJobTotals].[EXPR1], 0) >0,
[Order Transactions Table].[OutstandingBalance] - 
ISNULL([PartsStockForJobTotals].[EXPR1], 0), 0 *
[Part Assembly Link Table].[QTY]) AS Balance2,

FROM ((([PART LIBARY HEADER] 
INNER JOIN [Part Assembly Link Table] 
ON [PART LIBARY HEADER].PartID = [Part Assembly Link Table].PartIDParent) 
INNER JOIN [PART LIBARY HEADER] AS [PART LIBARY HEADER_1] 
ON [Part Assembly Link Table].PartIDChild = [PART LIBARY HEADER].PartID) 
INNER JOIN [Order Transactions Table] 
ON [PART LIBARY HEADER].[Part Number] = [Order Transactions Table].[Part 
Number]) 
LEFT JOIN PartsStockForJobTotals 
ON [Order Transactions Table].[Item Referance] = PartsStockForJobTotals. 
[Item Referance]

现在到此为止的所有内容都会返回记录。但是我试图只过滤 'Balance2' 大于 0 的记录。

这是我使用的 WHERE 子句,但它不检索任何行:

WHERE 
IIF([Order Transactions Table].[OutstandingBalance] - 
ISNULL([PartsStockForJobTotals].[EXPR1], 0) >0,
[Order Transactions Table].[OutstandingBalance] - 
ISNULL([PartsStockForJobTotals].[EXPR1], 0), 0 *
[Part Assembly Link Table].[QTY]) > 0;

显然别名不允许在 WHERE 子句中使用,所以我只是将 'Balance2' 复制并粘贴到 where 语句中,并附加一个 > 0

【问题讨论】:

  • @OwlsSleeping IIF() is available in tsql 尽管我认为Case 在大多数情况下更好,仅仅是因为它是可移植的。 Iif() 在可能倾向于使用三元运算符的情况下似乎是合理的,例如 CASE 过于冗长。
  • 我相信也可以在 T-SQL 中执行 IIF。在这种情况下使用 Case 是否更有利?编辑:@JNevill 说了什么

标签: sql sql-server tsql ms-access migrate


【解决方案1】:

我已经设法解决了这个问题!感谢 @Jnevill@Gordon Linoff 简化了代码,但我的 WHERE 子句不起作用,因为表之间的链接不正确。将多个实例添加到查询托盘时,Access 会创建临时表。它用 _1 附加第二个实例,在我的例子中是 PART LIBARY HEADER_1

最初我的加入没有指定这个连接:

PART LIBARY HEADER ----> PART ASSEMBLY LINK TABLE ----> PART LIBARY HEADER_1

但在重新执行连接后,@Gordon Linoff 提供的 where 子句似乎可以解决问题。准确的结果会在 Access 中返回。

感谢您的帮助!

【讨论】:

    【解决方案2】:

    我会这样写:

         (CASE WHEN ott.[OutstandingBalance] < COALESCE(psfjt.[EXPR1], 0)
               THEN ott.[OutstandingBalance] - COALESCE(psfjt.[EXPR1], 0)
               ELSE 0 
          END) * palt.[Qty] AS Balance2
      . . .
    FROM . . .
         [Order Transactions Table] ott . . .
         [PartsStockForJobTotals] psfjt . . .
         [Part Assembly Link Table] palt
    

    表别名使查询更易于编写和阅读。

    那么WHERE 将是:

    WHERE (ott.OutstandingBalance - COALESCE(psfjt.EXPR1, 0)) * palt.qty > 0
    

    我认为WHERE 中不需要条件逻辑。

    【讨论】:

    • 这是对代码的更好重写,但在添加 where 子句时我仍然检索 0 行。似乎只有值为 0 的“Balance2”与 where 子句一起返回。
    【解决方案3】:

    快速重写您的重写以提高性能和便携性:

    CASE 
      WHEN [Order Transactions Table].[OutstandingBalance] < [PartsStockForJobTotals].[EXPR1] 
        THEN [Order Transactions Table].[OutstandingBalance] - ISNULL([PartsStockForJobTotals].[EXPR1], 0)
      ELSE 0 
      END AS Balance2
    

    在此处切换以使用与IIF() 类似但更便携的 CASE 语句(可在除 Access 之外的任何 RDBMS 中使用),其中 IIF() 仅适用于较新版本的 SQL Server 和 Access(不适用于 Oracle 、Postgres、DB2、MySQL、MariaDB 等)。

    此外,减去这两个值并测试&gt;0 的数学运算也很昂贵。只需测试一个是否大于另一个。

    最后,您的ELSE 条件可以写成0 而不是0 * [Part Assembly Link Table].[QTY],因为任何时候0 都是0。

    这在您的 WHERE 子句中也应该可以正常工作(尽管我不知道为什么您的 WHERE 首先会失败,所以可能还有更多问题)。

    【讨论】:

    • 您是否打算: End AND Balance2 ?不是 AS?
    • 我有一个流浪者AND。绝对是胖手指那个。现已修复。
    • WHERE 在某处失败,我不知道为什么。该逻辑似乎万无一失,并且在 Access 中执行时也在检索记录。它们是指向同一个地方的链接表。
    • @JNevill 您说“减去两个值并测试&gt;0 的数学很昂贵”。您能否引用所涉及的大量开销的来源?典型的处理器架构通过从另一个值中减去一个值并设置随后检查的条件代码来执行比较。 A - B &gt; 0A &gt; B 的优化代码很可能是相同的。
    • 我没有源,但我担心CPU和SQL之间有很多。 RDBMS 是否会根据减法输出的类型对整数文字进行类型检查,以确保在用完条件之前需要潜在的隐式转换(例如)。最终我发现&lt; 更容易理解。话虽如此,我更喜欢 Gordon 的回答,因为我认为它解决了 OP 在他们的逻辑中尚未发现的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-29
    • 1970-01-01
    • 2013-10-24
    • 2021-04-07
    相关资源
    最近更新 更多