【发布时间】:2021-05-15 12:45:28
【问题描述】:
我有这个运行良好的长 SQL 查询,我想通过 Excel VBA 运行它以获取 Excel 中的数据。
为了让我的查询运行,我发现了两个需要解决的问题。
第一个是如何在 VBA Excel 中从两个 SQL 数据库中检索数据,第二个是如何在 VBA 中处理临时表。
我的工作 SQL 查询是
/* Layout: Temporary table containing all the information for Charge Events */
/* Layout: Temporary table containing all the information for Discharge Events */
/* Layout: Joining it all together */
/*Declaring the time frame for the data*/
DECLARE @StartDate nvarchar(10)
DECLARE @EndDate nvarchar(10)
SET @StartDate ='20/11/2020'
SET @EndDate ='21/11/2020'
/*Making the temporary table for the Charge data*/
drop table #chargeeventstable
SELECT
[Date1]= a.[_TimeStamp],[FCE1]='A',
[Shift]=case when DATEPART(hour, a.[_TimeStamp]) between 7 and 18 then '1' else '2' end ,
[Avg_Charg_Temp_A]=avg(CASE WHEN a.[FURNACE] ='A' then convert(real,isnull (b.[charge_temperature],'0')) else null end),
[Charge_slabs_A]=sum(case when a.[FURNACE] ='A' then 1.0 else null end),
[NGVolA]=sum(CASE WHEN a.[Furnace] ='A' then convert(real,isnull (a.[NG_AVG_MEAS_FLOW],'0.0')) else 0.0 end ) ,
[FCE2]='B' ,
[Avg_Charg_Temp_B]=avg(CASE WHEN a.[FURNACE] ='B' then convert(real,isnull (b.[charge_temperature],'0')) else null end),
[Charge_slabs_B]=sum(case when a.[FURNACE] ='B' then 1.0 else '0' end),
into #chargeeventstable
FROM (select a.*, (select min(aa.[_TimeStamp])
from ix.dbo.Fce_Data aa
where aa.[_TimeStamp] > a.[_TimeStamp])as next_time_2
from ix.dbo.Fce_Data a) a
Left JOIN ADB.dbo.Temp_Aims b on b.[charge_time] >= a.[_TimeStamp] and b.[charge_time] < a.[next_time_2] and a.[Furnace] = b.[Furnace]
WHERE CONVERT(datetime, a.[_TimeStamp], 103) BETWEEN CONVERT(datetime, @StartDate , 103) AND CONVERT(datetime, @EndDate , 103)
Group by a.[_TimeStamp]
ORDER BY a.[_TimeStamp]
/*Making the temporary table for the Discharge data*/
drop table #dischargeeventstable
SELECT
[Discharge_slabs_A]=sum(case when b.[FURNACE] ='A' then 1.0 else '0' end),
[Discharge_slabs_B]=sum(case when b.[FURNACE] ='B' then 1.0 else '0' end),
into #dischargeeventstable
FROM (select a.*, (select min(aa.[_TimeStamp])
from ix.dbo.Fce_Data aa
where aa.[_TimeStamp] > a.[_TimeStamp])as next_time_2
from ix.dbo.Fce_Data a) a
Left JOIN ADB.dbo.Temp_Aims b on b.[discharge_time] >= a.[_TimeStamp] and b.[discharge_time] < a.[next_time_2] and a.[Furnace] = b.[Furnace]
WHERE CONVERT(datetime, a.[_TimeStamp], 103) BETWEEN CONVERT(datetime, @StartDate , 103) AND CONVERT(datetime, @EndDate , 103)
Group by a.[_TimeStamp]
ORDER BY a.[_TimeStamp]
/*Joining the two temporary tables together*/
SELECT
[FCE1],
a.[Date1],
[Shift],
[Charge_slabs_A],
[Avg_Charg_Temp_A],
[NGVolA],
[FCE2],
[Charge_slabs_B],
[Avg_Charg_Temp_B],
[Discharge_slabs_A],
[Discharge_slabs_B]
FROM #chargeeventstable a
Left JOIN #dischargeeventstable b on a.[Date1] = b.[Date1]
所以我想做的就是将此查询转换为 VBA Excel。 到目前为止,我在 VBA 中所做的是:
Private Sub SetScrollBarRange()
Dim sht As Worksheet
Dim LastRow As Long
Set sht = ThisWorkbook.Worksheets("-Input Data-")
LastRow = sht.Cells(sht.Rows.Count, "C").End(xlUp).Row
ScrollBarSelDate.Max = LastRow
End Sub
Private Sub ScrollBarSelDate_Change()
SetScrollBarRange
ThisWorkbook.Worksheets("A&B").Cells(4, 15) = ScrollBarSelDate.Value
End Sub
Private Sub UpdateButton_Click()
On Error Resume Next
Sheets("Loading").Select
Sheets("-Input Data-").Range("A20:AQ1000").ClearContents
Dim cn As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim cm As New ADODB.Command
Dim SQLStr As String
Dim i As Integer
Dim StartDate As String
Dim EndDate As String
StartDate = Sheets("A&B Sankey").Cells(2, 18)
EndDate = Sheets("A&B Sankey").Cells(2, 20)
SQLStr = "drop table #chargeeventstable"
SQLStr = SQLStr & "SELECT [Date1]= a.[_TimeStamp],[FCE1]='A',[Shift]=case when DATEPART(hour, a.[_TimeStamp]) between 7 and 18 then '1' else '2' end,"
SQLStr = SQLStr & "[Avg_Charg_Temp_A]=avg(CASE WHEN a.[FURNACE] ='A' then convert(real,isnull (b.[charge_temperature],'0')) else null end),"
SQLStr = SQLStr & "[Charge_slabs_A]=sum(case when a.[FURNACE] ='A' then 1.0 else null end),"
SQLStr = SQLStr & "[NGVolA]=sum(CASE WHEN a.[Furnace] ='A' then convert(real,isnull (a.[NG_AVG_MEAS_FLOW],'0.0')) else 0.0 end ) ,"
SQLStr = SQLStr & "[Date1]= a.[_TimeStamp],[FCE2]='B',[Shift]=case when DATEPART(hour, a.[_TimeStamp]) between 7 and 18 then '1' else '2' end, "
SQLStr = SQLStr & "[Avg_Charg_Temp_B]=avg(CASE WHEN a.[FURNACE] ='B' then convert(real,isnull (b.[charge_temperature],'0')) else null end),"
SQLStr = SQLStr & "[Charge_slabs_B]=sum(case when a.[FURNACE] ='B' then 1.0 else '0' end)"
SQLStr = SQLStr & " into #chargeeventstable"
SQLStr = SQLStr & " FROM (select a.*, (select min(aa.[_TimeStamp])"
SQLStr = SQLStr & "from ix.dbo.Fce_Data aa"
SQLStr = SQLStr & "where aa.[_TimeStamp] > a.[_TimeStamp])as next_time_2"
SQLStr = SQLStr & "from ix.dbo.Fce_Data a) a"
SQLStr = SQLStr & "Left JOIN ADB.dbo.Temp_Aims b on b.[charge_time] >= a.[_TimeStamp] and b.[charge_time] < a.[next_time_2] and a.[Furnace] = b.[Furnace]"
SQLStr = SQLStr & "WHERE CONVERT(datetime, a.[_TimeStamp], 20) BETWEEN CONVERT(datetime, @StartDate , 20) AND CONVERT(datetime, @EndDate , 20)"
SQLStr = SQLStr & "Group by a.[_TimeStamp]"
SQLStr = SQLStr & "ORDER BY a.[_TimeStamp]"
SQLStr = SQLStr & "drop table #dischargeeventstable"
SQLStr = SQLStr & "SELECT"
SQLStr = SQLStr & "[Date1]= a.[_TimeStamp],"
SQLStr = SQLStr & "[Discharge_slabs_A]=sum(case when b.[FURNACE] ='A' then 1.0 else '0' end),"
SQLStr = SQLStr & "[Avg_DisCharg_Temp_A]=avg(CASE WHEN b.[FURNACE] ='A' then convert(real,isnull (b.[ave_disch_temp],'0')) else null end),"
SQLStr = SQLStr & "[Discharge_slabs_B]=sum(case when b.[FURNACE] ='B' then 1.0 else '0' end),"
SQLStr = SQLStr & "[Avg_DisCharg_Temp_B]=avg(CASE WHEN b.[FURNACE] ='B' then convert(real,isnull (b.[ave_disch_temp],'0')) else null end)"
SQLStr = SQLStr & "into #dischargeeventstable"
SQLStr = SQLStr & "FROM (select a.*, (select min(aa.[_TimeStamp])"
SQLStr = SQLStr & "from ix.dbo.Fce_Data aa"
SQLStr = SQLStr & "where aa.[_TimeStamp] > a.[_TimeStamp])as next_time_2"
SQLStr = SQLStr & "from ix.dbo.Fce_Data a) a"
SQLStr = SQLStr & "Left JOIN ADB.dbo.temp_Aims b on b.[discharge_time] >= a.[_TimeStamp] and b.[discharge_time] < a.[next_time_2] and a.[Furnace] = b.[Furnace]"
SQLStr = SQLStr & "WHERE CONVERT(datetime, a.[_TimeStamp], 20) BETWEEN CONVERT(datetime, @StartDate , 20) AND CONVERT(datetime, @EndDate , 20)"
SQLStr = SQLStr & "Group by a.[_TimeStamp]"
SQLStr = SQLStr & "ORDER BY a.[_TimeStamp]"
SQLStr = SQLStr & "SELECT"
SQLStr = SQLStr & "[FCE1],"
SQLStr = SQLStr & "a.[Date1],"
SQLStr = SQLStr & "[Shift],"
SQLStr = SQLStr & "[Charge_slabs_A],"
SQLStr = SQLStr & "[Avg_Charg_Temp_A],"
SQLStr = SQLStr & "[NGVolA], "
SQLStr = SQLStr & "[FCE2],"
SQLStr = SQLStr & "[Charge_slabs_B],"
SQLStr = SQLStr & "[Avg_Charg_Temp_B],"
SQLStr = SQLStr & "[Discharge_slabs_A],"
SQLStr = SQLStr & "[Discharge_slabs_B]"
SQLStr = SQLStr & "FROM #chargeeventstable a"
SQLStr = SQLStr & "Left JOIN #dischargeeventstable b on a.[Date1] = b.[Date1]"
SQLStr = SQLStr & "Left JOIN #slabweightcharged c on a.[Date1]=c.[Date1]"
SQLStr = SQLStr & "LEFT JOIN #slabweightdischarged d on a.[Date1]=d.[Date1]"
cn.Open "driver={SQL server}; SERVER=name; UID=user; PWD=pass; DATABASE=;"
rs.ActiveConnection = cn
rs.Open SQLStr, cn
rs.MoveFirst
i = 20
While Not rs.EOF
Sheets("-Input Data-").Cells(i, 2) = rs(0)
Sheets("-Input Data-").Cells(i, 3) = rs(1)
i = i + 1
rs.MoveNext
Wend
rs.Close
cn.Close
'Clean up
Set rs = Nothing
Set cn = Nothing
Sheets("A&B").Select
SetScrollBarRange
End Sub
Private Sub Worksheet_PivotTableUpdate(ByVal Target As PivotTable)
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
End Sub
我的第一个问题是如何在 VBA 中从两个 SQL 数据库(来自同一服务器)检索数据。正如您在 VBA 代码中看到的那样,我还没有找到一种方法来做到这一点。第二个问题是如何在 VBA 中处理临时表? QLStr = SQLStr & "into #dischargeeventstable" 是将其转换为 VBA 的正确方法吗? 我将不胜感激任何建议或 cmets。
【问题讨论】:
-
没有真正看到问题?您的代码是否有效?如果没有,那是什么不工作?
-
@DaleK SQL 代码有效,VBA 没有。我的第一个问题是如何在 VBA 中从两个 SQL 数据库(来自同一服务器)检索数据。正如您在 VBA 代码中看到的那样,我还没有找到一种方法来做到这一点。第二个问题是如何在 VBA 中处理临时表? QLStr = SQLStr & "into #dischargeeventstable" 是将其转换为 VBA 的正确方法吗?
-
edit 你的问题,所以它对人们来说很清楚。
-
VBA 根本不处理临时表,它们只存在于 SQL Server 上。我不希望您在 VBA 中的 SQL 代码能够正常工作,因为代码行之间缺少空格。此外,如果您针对较新版本的 SQL Server 运行此操作,请考虑使用
DROP TABLE IF EXISTS ...语法或一些变体,否则由于临时表尚不存在,您将收到错误。 -
你有权限在数据库上创建存储过程吗?
标签: sql-server excel vba