更新sql查询到vba的情况

时间:2018-05-10 17:54:40

标签: sql-server vba

我一直在尝试将以下代码从SQL Server转换为直接从Excel VBA运行。但无法这样做。

Update Legal 
Set Category = Case 
                  when datediff(month, GETDATE(), [End date]) > 9 
                     then 'Blue' 
                  when datediff(month, GETDATE(), [End date]) < 9 
                       and datediff(month, GETDATE(), [end date]) > 1 
                     then 'Orange'
                  when datediff(month, GETDATE(), [End date]) < 2 
                     then 'Red'
               End 
where classification = 'A'

Select 
    classification, 
    datediff(month, GETDATE(), [End date]), 
    Category 
from 
    Legal

如下所示进入VBA

Dim Cn As ADODB.Connection
Dim Server_Name As String
Dim Database_Name As String
Dim User_ID As String
Dim Password As String
Dim SQLSelect As String
Dim rs As ADODB.Recordset
Dim sqlcmd as string

cbb = Environ("computername")

With Sheet3.Range("A4:Z" & Rows.Count)
.ClearContents
'.ClearFormats
 End With


sqlcmd = "Update Legal Set Category = Case" & _
" when datediff(month,GETDATE(),[End date])>9 then 'Blue'" & _
" when datediff(month,GETDATE(),[End date])<9 and datediff(month,GETDATE(),[end date])>1 then 'Orange'" & _
" when datediff(month,GETDATE(),[End date])<2 then 'Red'" & _
" End " & _
" where classification = 'A'"

  Debug.Print sqlcmd

With Sheet3.ListObjects.Add(SourceType:=0, Source:=Array( _
    "OLEDB;Provider=SQLOLEDB.1;Persist Security Info=True;User ID=Login_ID;Password=Password;Data Source=Server_Name;Use Procedure f" _
    , _
    "or Prepare=1;Auto Translate=True;Packet Size=4096;Workstation ID=" & cbb & ";Use Encryption for Data=False;Tag with column collatio" _
    , "n when possible=False;Initial Catalog=DB_Name"), Destination:=Sheet3.Range( _
    "$A$4")).QueryTable
    .CommandType = xlCmdSql
    .CommandText = sqlcmd 
    .RowNumbers = False
    .FillAdjacentFormulas = False
    .PreserveFormatting = True
    .RefreshOnFileOpen = False
    .BackgroundQuery = True
    .RefreshStyle = xlInsertDeleteCells
    .SavePassword = False
    .SaveData = True
    .AdjustColumnWidth = True
    .RefreshPeriod = 0
    .PreserveColumnInfo = True
    .SourceConnectionFile = _
    "C:\Users\xxxxx\Documents\My Data Sources\xxxxx.odc"
    .ListObject.DisplayName = _
    "AP_123"
    .Refresh BackgroundQuery:=False
End With

此查询在SQL Server中完全有效。但是我在VBA中遇到以下错误:

  

查询未运行,或无法打开数据库表。

     

检查数据库服务器或与数据库管理员联系。确保外部数据库可用且尚未移动或重组,然后再次尝试操作。

请帮助我们!!几个星期以来一直试着这个!

P.S。不需要Power Query,因为它会向无权访问服务器的其他用户请求凭据

3 个答案:

答案 0 :(得分:1)

如上所述,只需首先实际运行action UPDATE语句,然后将QueryTable连接到SELECT语句,即可将两个查询分开。您甚至可以缩短 Source 参数中的连接字符串:

Dim Cn As ADODB.Connection, rs As ADODB.Recordset
Dim Server_Name As String, Database_Name As String
Dim User_ID As String, Password As String
Dim conn_str As String, SQLSelect As String, sqlcmd as string

cbb = Environ("computername")

With Sheet3.Range("A4:Z" & Rows.Count)
     .ClearContents
     '.ClearFormats
End With

conn_str = "Provider=SQLOLEDB.1;Persist Security Info=True;User ID=Login_ID;Password=Password;" & _
           "Data Source=Server_Name;Use Procedure for Prepare=1;Auto Translate=True;" & _
           "Packet Size=4096;Workstation ID=" & cbb & ";Use Encryption for Data=False;" & _
           "Tag with column collation when possible=False;Initial Catalog=DB_Name"

Cn.Open conn_str

' EXECUTE ACTION QUERY
sqlcmd = "UPDATE Legal SET Category = Case" & _
         " when datediff(month,GETDATE(),[End date])>9 then 'Blue'" & _
         " when datediff(month,GETDATE(),[End date])<9 and " & _
         "      datediff(month,GETDATE(),[end date])>1 then 'Orange'" & _
         " when datediff(month,GETDATE(),[End date])<2 then 'Red'" & _
         " End " & _
         " where classification = 'A'"

Cn.Execute sqlcmd

' CONNECT TO SELECT QUERY
sqlcmd = "SELECT classification, datediff(month, GETDATE(), [End date]), Category " & _
         " FROM Legal;"

With Sheet3.ListObjects.Add(SourceType:=0, Source:=Array( _
    "OLEDB;" & conn_str), Destination:=Sheet3.Range( _
    "$A$4")).QueryTable
    .CommandType = xlCmdSql
    .CommandText = sqlcmd 
    .RowNumbers = False
    .FillAdjacentFormulas = False
    .PreserveFormatting = True
    .RefreshOnFileOpen = False
    .BackgroundQuery = True
    .RefreshStyle = xlInsertDeleteCells
    .SavePassword = False
    .SaveData = True
    .AdjustColumnWidth = True
    .RefreshPeriod = 0
    .PreserveColumnInfo = True
    .SourceConnectionFile = _
    "C:\Users\xxxxx\Documents\My Data Sources\xxxxx.odc"
    .ListObject.DisplayName = _
    "AP_123"
    .Refresh BackgroundQuery:=False
End With

Cn.Close
Set Cn = Nothing

答案 1 :(得分:1)

这是存储过程方法。在SSMS中,运行一次

CREATE PROCEDURE dbo.UpdateAndGetLegal
AS
    UPDATE Legal
    SET    Category = CASE WHEN DATEDIFF(MONTH, GETDATE(), [End date]) > 9 THEN 'Blue'
                           WHEN DATEDIFF(MONTH, GETDATE(), [End date]) < 9
                                AND DATEDIFF(MONTH, GETDATE(), [end date]) > 1 THEN 'Orange'
                           WHEN DATEDIFF(MONTH, GETDATE(), [End date]) < 2 THEN 'Red'
                      END
    WHERE  classification = 'A'

    SELECT classification
         , DATEDIFF(MONTH, GETDATE(), [End date])
         , Category
    FROM   Legal

这将创建一个运行更新并返回SELECT结果的存储过程。

在Excel中,我几乎不需要.Add一个ListObject。有时我必须更改现有ListObject的SQL语句,但是一旦创建了表,就不需要再次创建它。所以我不完全确定你在做什么,但这是我的一个项目的样子。

我创建了一个Excel文件(或模板,如果它是我正在生成的东西)。在该文件中,我创建了一个外部数据ListObject,其命令文本为

EXEC UpdateAndGetLegal

然后,如果用户只是刷新表,我就完成了。如果我需要我的代码刷新表,那就是

Sheet3.ListObjects(1).QueryTable.Refresh

如果您将Windows凭据传递给SQL Server,则所有用户都需要存储过程的EXECUTE权限。

答案 2 :(得分:0)

我在这里做了一些猜测,但这是基于感觉不适的东西。

每次运行SELECT以获取一些数据

Select 
    classification, 
    datediff(month, GETDATE(), [End date]), 
    Category 
from 
    Legal

您首先运行UPDATE ...

Update Legal 
Set Category = Case 
                  when datediff(month, GETDATE(), [End date]) > 9 
                     then 'Blue' 
                  when datediff(month, GETDATE(), [End date]) < 9 
                       and datediff(month, GETDATE(), [end date]) > 1 
                     then 'Orange'
                  when datediff(month, GETDATE(), [End date]) < 2 
                     then 'Red'
               End 
where classification = 'A'

这很奇怪,我想不出任何适用于任何数据库的用例。相反,你可以自己选择SELECT:

Select 
    classification, 
    datediff(month, GETDATE(), [End date]), 
    Case WHEN classification = 'A' 
        THEN
            CASE
                  when datediff(month, GETDATE(), [End date]) > 9 
                     then 'Blue' 
                  when datediff(month, GETDATE(), [End date]) < 9 
                       and datediff(month, GETDATE(), [end date]) > 1 
                     then 'Orange'
                  when datediff(month, GETDATE(), [End date]) < 2 
                     then 'Red'
               End 
        ELSE Category
        END
from 
    Legal

这是做同样的事情,但没有触及Legal中的基础数据。这个SELECT是您想要偷偷摸摸进入VBA / QueryTable的那个。