【问题标题】:Converting a function from SQL Server to MS Access将函数从 SQL Server 转换为 MS Access
【发布时间】:2015-12-25 18:37:49
【问题描述】:

我有一些代码用于在表中插入值,用 SQL Server 编写:

创建表/构建架构:

  CREATE TABLE Inter
    ([id] int, [MarkDate] date, [MaturityDate] date, [ZeroRate] int)
;

INSERT INTO Inter
    ([id], [MarkDate], [MaturityDate], [ZeroRate])

VALUES
    (1, '2015-07-02', '2015-07-02', 1),
    (2, '2015-07-02', '2015-07-03', 5),
    (3, '2015-07-02', '2015-07-06', 15)
;


CREATE TABLE allDates
    ([id] int, [MaturityDate] date)
;

INSERT INTO allDates
    ([id], [MaturityDate])

VALUES
    (1, '2015-07-01'),
    (2, '2015-07-02'),
    (3, '2015-07-03'),
    (4, '2015-07-04'),
    (5, '2015-07-05'),
    (6, '2015-07-06'),
    (7, '2015-07-07'),
    (8, '2015-07-08'),
    (9, '2015-07-09')
;

CREATE TABLE rangesInter
    ([id] int, [MarkDate] date, [begindate] date, [enddate] date, startRate float, rateChange float);


INSERT INTO rangesInter
    SELECT 
        I1.id, 
        I1.[MarkDate], 
        I1.[MaturityDate] begindate, 
        I2.[MaturityDate] enddate, 
        I1.[ZeroRate] startRate,
        (I2.ZeroRate - I1.ZeroRate) * 1.0 / DATEDIFF ( day , I1.[MaturityDate], I2.[MaturityDate] )  rateChange        
    FROM Inter I1
    inner join Inter I2
    on I1.id = I2.id - 1;

插值:

SELECT 
    IIF(i.MarkDate IS NULL, r.MarkDate, i.MarkDate) as MarkDate,
    a.MaturityDate,
    IIF(i.ZeroRate IS NULL,
           r.startRate + DATEDIFF ( day , r.begindate, a.MaturityDate ) * rateChange,
           i.ZeroRate) as ZeroRate,
    i.*, r.*
FROM  
    allDates a
LEFT JOIN 
    Inter I ON a.MaturityDate  = I.MaturityDate
CROSS JOIN
    (SELECT 
         MIN(MaturityDate) minDate, MAX(MaturityDate) maxDate
     FROM Inter) AS t
LEFT JOIN  
    (SELECT 
         I1.id, I1.[MarkDate], 
         I1.[MaturityDate] begindate, I2.[MaturityDate] enddate, 
         I1.[ZeroRate] startRate,
         (I2.ZeroRate - I1.ZeroRate) * 1.0 / DATEDIFF ( day , I1.[MaturityDate], I2.[MaturityDate] )  rateChange        
     FROM 
         Inter I1
     INNER JOIN
         Inter I2 ON I1.id = I2.id - 1) r ON a.MaturityDate > r.[begindate]
                                          AND a.MaturityDate < r.[enddate] 
WHERE
    a.MaturityDate >= t.minDate
    AND a.MaturityDate <= t.maxDate;

如何将此代码转换为 MS Access VBA?

我不确定如何开始转换代码的“插值”部分以使用 Access VBA。

【问题讨论】:

  • 在我看来是合法的。您是否真的尝试在 Access 中运行该代码?它有没有给你任何具体的错误?如果有的话,我认为反过来也行不通。我认为您需要 CASE WHEN 语句而不是 SQL Server 中的 IIF。
  • 在 VBA 中编写代码时,您会发现此答案中概述的技术可帮助您简化在 VBA 中构建的 SQL 字符串,请参阅:stackoverflow.com/questions/31684546/…

标签: sql sql-server sql-server-2008 ms-access vba


【解决方案1】:

以下几点可以帮助您入门:

IIf 已存在于 Access 中,因此无需更改。

CROSS JOIN 关键字在 Access 中不存在;在表名/子查询之间使用逗号 (,) 以返回笛卡尔积。您可能还需要将引用笛卡尔积的 ON 语句移动到 WHERE 子句中。

当您在 Access 中的 ON 子句中有多个项目时,它们需要用括号括起来。例如:

... ON (f1.ID = f2.ID AND f1.Name = f3.Name) ...

此外,当您在 Access SQL 语句中连接多个表时,每个表都必须用括号括起来。例如:

SELECT ...
FROM 
    ((Table1 t1 
      INNER JOIN Table2 t2 ON t1.ID = t2.ID)
      INNER JOIN Table3 t3 ON t1.ID = t3.ID)
      INNER JOIN Table4 t4 ON t1.ID = t4.ID

在单个查询中混合连接类型(例如笛卡尔、左和内)时,您可能会遇到错误。如果是这样,我建议将查询分解为多个 Access 查询,每个查询具有相似的连接类型,然后在另一个查询中将这些部分连接在一起。分解问题还可以帮助您简化从 SQL Server 的转换。

Access 也有一个类似于 SQL Server 的DateDiff 函数。但是,第一个参数是表示间隔的字符串(例如,day = "d"、month = "m" 等)。所以你可以像这样替换你的 DATEDIFF 函数:

DateDiff("d", I1.[MaturityDate], I2.[MaturityDate])

【讨论】:

  • 感谢您的回复。您对如何重新创建我构建表的代码的第一部分有任何建议吗? “CREATE TABLE”应该在 Access 中工作,所以我认为我不必更改代码,但它似乎不起作用。
  • 您的 CREATE TABLE 语句对我有用,但请记住,在 Access 中,每个查询只能执行一个语句。尝试将CREATE TABLE ... ; 放在它自己的查询中。 INSERT 必须在单独的查询中。此外,在 Access 中,您不能一次将多个 VALUES 用于 INSERT 语句。每个语句只能插入一行。解决该限制的一种方法是创建一个 VBA 语句来执行所有插入操作。
  • 另一个建议 - 我喜欢为我的 Access 查询编号(例如“01 创建表”、“02 将数据插入表”等)然后您可以运行 VBA 方法来一次运行所有查询,例如this one
【解决方案2】:

我很想知道您为什么将其转换为访问 VBA。

我会在 VBA 中将查询 SQL 构建为字符串,然后从 SQL 字符串创建一个 QueryDef 对象。

在构建 SQL 字符串时,您会发现this 答案中概述的技术对您有帮助。

下面的SQL中显示了一些更实用的点:

在您的代码中明确删除笛卡尔连接,如下所示。

所有列别名和表别名都需要一个“AS”

你可以用 IIF 代替

nz(MyFieldWithNulls, AnotherfieldToBeUsedWhenItisNull)

替换datediff如图

SELECT Nz(i.MarkDate, r.MarkDate) as MarkDate
     , a.MaturityDate
     , Nz(i.ZeroRate 
        , r.startRate + Cint(a.MaturityDate - r.begindate) * rateChange
         ) as ZeroRate
    , i.*
    , r.*
FROM (  ( SELECT allDates.* 
            FROM allDates   
                 INNER JOIN (SELECT MIN(MaturityDate) AS minDate
                                  , MAX(MaturityDate) AS maxDate
                               FROM Inter
                            ) AS Inter
                         ON ( allDates.MaturityDate >= Inter.minDate
                              AND 
                              allDates.MaturityDate <= Inter.maxDate
                            )
        ) AS a
       LEFT JOIN Inter AS I 
              ON a.MaturityDate  = I.MaturityDate
     )
     LEFT JOIN ( SELECT , I1.id
                        , I1.[MarkDate] 
                        , I1.[MaturityDate] AS begindate
                        , I2.[MaturityDate] AS enddate, 
                        , I1.[ZeroRate]     AS startRate,
                        , (I2.ZeroRate - I1.ZeroRate) * 1.0 
                          / DATEDIFF ( day , I1.[MaturityDate], I2.[MaturityDate] )  
                          AS rateChange        
                   FROM Inter I1
                        INNER JOIN Inter I2 
                                ON I1.id = (I2.id - 1)
                ) AS r 
            ON ( a.MaturityDate > r.[begindate]
                 AND 
                 a.MaturityDate < r.[enddate] 
               )     
    ;

【讨论】:

  • 感谢您的回复。使用“nz”而不是 IIF 有什么好处,因为 IIF 已经存在于 MS 访问中?
  • 这是一种更简单的语法,涉及的输入更少。我怀疑它也可能更快。
  • 我使用您链接到的“aa”过程来构建 SQL 字符串,但是我需要做什么来创建相关的 QueryDef 对象 - 我正在尝试关注 this 但不确定如何进行。
  • 这可能更有用。 msdn.microsoft.com/en-us/library/office/ff195966.aspx一旦创建就不要删除它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-08
  • 1970-01-01
  • 2011-03-28
  • 2020-11-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多