2015-09-28 48 views
1

我有一些代码设计在表中插入值,写在SQL Server:转换从SQL Server的功能到MS Access

创建表/建模式:

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工作。

+0

看起来合法的给我。你真的尝试在Access中运行该代码吗?它给了你什么具体的错误?如果有的话,我会认为它不会反过来工作;我以为你需要在SQL Server中使用CASE WHEN语句而不是IIF。 –

+0

在VBA中编写代码时,您会发现此答案中概述的技术可帮助您简化和在VBA中构建的SQL字符串请参阅:http://stackoverflow.com/questions/31684546/how-to-format-a-sql-string这是一个可读的代码块,它的格式很好 – HarveyFrench

回答

1

我很想知道为什么要转换这是在访问VBA。

我将建立查询SQL作为VBA字符串,然后创建一个从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] 
       )  
    ; 
+0

感谢您的回复。因为IIF已经存在于MS访问中,所以使用“nz”而不是IIF的优点是什么? – beeba

+0

这是一个更简单的语法,它可以减少输入。我怀疑它也可能更快。 – HarveyFrench

+0

我使用了链接到的“aa”过程来构建SQL字符串,但是我需要做什么来创建相关的QueryDef对象 - 我正在试图遵循[this](https://msdn.microsoft.com /en-us/library/bb177500(v=office.12).aspx)但不知道如何继续。 – beeba

2

有几点让你开始:

IIf存在于访问了,所以没有必要改变这种状况。

CROSS JOIN关键字访问不存在;在表名/子查询之间使用逗号(,)来返回笛卡尔积。您可能还需要您ON声明指的是笛卡尔乘积移动到WHERE条款。

当你在访问一个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查询,每个Access查询都有相似的连接类型,然后在另一个查询中将这些部分连接在一起。分解这个问题也可以帮助您简化从SQL Server的转换。

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

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

感谢您的回复。你有什么建议如何重新创建表的代码的第一部分? “CREATE TABLE”应该在Access中工作,所以我原以为我不需要更改代码,但它似乎不工作。 – beeba

+0

您的CREATE TABLE语句适用于我,但请记住,在Access中,每个查询只能执行一条语句。尝试将'CREATE TABLE ...;'放在它自己的查询中。 INSERT必须在单独的查询中。另外,在Access中,您不能一次使用多个'VALUES'作为'INSERT'语句。每条语句只能插入一行。处理这种限制的一种方法是创建一个VBA语句来执行所有的插入操作。 – transistor1

+0

另一个建议 - 我想要做的是编号我的访问查询(例如“01创建表”,“02插入数据到表”,等等......)然后你可以运行一个VBA方法来运行所有的查询一次,例如[this one](http://fieldeffect.info/wp/frontpage/vba_library/#Run_Numbered_Queries_in_an_Access_Database)。 – transistor1