Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/excel/28.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用sql从excel工作表获取数据_Sql_Excel_Vba - Fatal编程技术网

使用sql从excel工作表获取数据

使用sql从excel工作表获取数据,sql,excel,vba,Sql,Excel,Vba,我正在使用SQL从工作表中提取数据。我有一张销售数据表。前三列是SalesDate、Customer和CBand。 首先,我得到一个不同日期的列表: wb = ThisWorkbook.Path & "\" & ThisWorkbook.name Set cn = CreateObject("ADODB.Connection") With cn .Provider = "Microsoft.ACE.OLEDB.12.0" .ConnectionString =

我正在使用SQL从工作表中提取数据。我有一张销售数据表。前三列是SalesDate、Customer和CBand。

首先,我得到一个不同日期的列表:

wb = ThisWorkbook.Path & "\" & ThisWorkbook.name
Set cn = CreateObject("ADODB.Connection")
With cn
    .Provider = "Microsoft.ACE.OLEDB.12.0"
    .ConnectionString = "Data Source=" & wb & ";" & "Extended Properties=""Excel 12.0 Xml;HDR=YES"";"
    .Open
End With

sql = "SELECT distinct SalesDate FROM [Sales$] where CBand=3 order by SalesDate desc"
Set RS = cn.Execute(sql)
ct = 0
If Not RS.EOF Then
。。。等

我将检索到的所有日期保存在另一张工作表中

然后,使用我保存的其中一个日期,我再次查询销售表: 注,“dt”作为参数提供给该子组件-例如2019年10月8日或2019年10月5日-与存储日期的格式相同

wb = ThisWorkbook.Path & "\" & ThisWorkbook.name
Set cn = CreateObject("ADODB.Connection")
With cn
    .Provider = "Microsoft.ACE.OLEDB.12.0"
    .ConnectionString = "Data Source=" & wb & ";" & "Extended Properties=""Excel 12.0 Xml;HDR=YES"";"
    .Open
End With
sql = "SELECT distinct Customer FROM [Sales$] where SalesDate = #" & dt & "# and CBand=3"
output = output & sql & vbNewLine
Set RS = cn.Execute(sql)
ct = 0
If Not RS.EOF Then...
第二个查询仅适用于某些日期。例如,使用所附工作表的示例部分,10月5日没有返回任何行RS.EOF测试失败,但10月8日可以正常工作,我可以循环浏览与该日期相关的所有行。我试过好几次约会,大多数都很成功,但也有少数没有,我不明白为什么


我被难住了

如果涉及日期,你应该处理日期,而不是日期的表示。2019年10月8日不是一个日期——它是一个可以被视为日期的字符串——但它是10月8日还是8月10日

如果工作表中有实际日期,则它们将存储为双值,并且仅以可以将其视为日期的方式显示给您。这取决于单元格的格式以及计算机的区域设置。所以10月8日存储为43746号,如果加上0.5,则为10月8日中午。您可能会将其视为2019年10月8日,或2019年10月8日或2019年10月8日。Oktober 2019-可能性是无限的,但价值本身保持不变

如果要查询日期,应向查询传递日期参数。如果传递&dt&,则传递的是字符串。如果dt是一个日期变量,VBA会将日期转换为字符串,SQL解析器会尝试将其转换回日期-不一定以相同的方式。当然,您也不希望将43746作为参数传递。您不介意日期是如何存储的,如果您查询不同的数据源,例如Oracle、SQL Server…,它们将以不同的格式存储日期

解决此问题的最佳方法是使用ADODB.Parameter。由于无法将ADODB.Parameter传递给Connection对象的Execute方法,因此需要编写更多的代码,您必须使用ADODB.Command-object,但一旦习惯了它,您将享受到好处:您不再需要考虑格式化,不需要将字符串参数放在引号中等等。此外,它还可以防止SQL注入

看看下面的代码,正如您所看到的,我更喜欢使用早期绑定,但当然,当您切换到后期绑定时,这也适用

Dim cn As ADODB.Connection, cmd As ADODB.Command, param As ADODB.Parameter
Set cn = New ADODB.Connection

With cn
    .Provider = "Microsoft.ACE.OLEDB.12.0"
    .ConnectionString = "Data Source=" & ThisWorkbook.FullName & ";" & "Extended Properties=""Excel 12.0 Xml;HDR=YES"";"
    .Open
End With

Dim sql As String
sql = "SELECT * FROM [Sheet1$] where SalesDate = ?"   ' The ? is a placeholder for a parameter
' Create command
Set cmd = New ADODB.Command
Set cmd.ActiveConnection = cn
cmd.CommandText = sql
' Create a parameter of type Date and pass the date value
Set param = cmd.CreateParameter("p1", adDate, adParamInput, , dt)
cmd.Parameters.Append param

Dim rs As ADODB.Recordset
Set rs = cmd.Execute
这样,查询将以实际日期运行。数字、字符串等还有其他参数类型

现在,当涉及日期的SQL查询时,还有另一个方面:日期可以包含时间部分,时间部分存储为双精度的小数部分。如果您正在搜索日期,并且希望包含全天的日期值,则可以将代码更改为

sql = "SELECT * FROM [Sheet1$] where SalesDate >= ? and SalesDate < ?"
' Now we have to provide two parameters:
Set param = cmd.CreateParameter("p1", adDate, adParamInput, , dt)
cmd.Parameters.Append param
' Second parameter is the next day - a little lazy, you can deal with DateAdd instead
Set param = cmd.CreateParameter("p2", adDate, adParamInput, , dt+1)
cmd.Parameters.Append param    

我不是Excel专家,但也许您可以在筛选时指定SalesDate掩码。实际存储的数据掩码可能与打印的数据掩码不同,您可以在Excel工作表中看到。请看,2019年10月5日可以写成:1 2019.10.05欧洲符号或2 2019.05.10美国符号。我不能100%确定,但它可能是日期格式的东西?i、 e.2019年10月24日是10月24日,但2019年10月5日是5月10日?2019年10月10日可能行得通,因为10月10日两种情况都是一样的。您是否尝试过在查询中将日期转换为双倍?比如…where SalesDate=&cdbldt&不感谢你的想法,但我已经想到了,事实上没有5月10日或8月10日的数据。我正在使用MsgBox在不同点输出信息,我可以看到我正在搜索正确的日期格式,它与存储在单元格中的内容相匹配,尽管它在工作表中的显示方式不同,并且我得到了10月8日的正确数据。原始帖子中有一个拼写错误-这是10月8日,而不是10月10日。我也尝试过cdbl,但没有成功!我知道我们在这里打了一匹死马,但也许不只是dt,而是尝试将它格式化为“&formatt,dd/mm/yyyy&”,看看这是否会让它开心。或者,检查您查询的单元格/列是否实际包含日期,而不仅仅是格式类似日期的字符串。ACE和JET在查询时只使用前10行左右的数据来确定数据类型,这样它们可能会变得有些愚蠢。谢谢你,FunThomas,使用你建议的代码,我现在可以工作了。