MS Access在传递查询中使用表单

时间:2018-01-05 20:43:08

标签: sql sql-server ms-access

我有一个名为 FietsAantDagen 的表单,一个名为 QueryFietsAantDagen 的查询和一个名为 Txtinput 的文本框。我正在尝试对SQL Server使用传递查询,并在我的查询中使用文本格式的输入作为输入。

查询:

SELECT
   Fiets_id,
   Fiets_Type,
   SUM(DATEDIFF(DAY, Huurovereenkomst_Begin_datum, Huurovereenkomst_Eind_datum)) AS AantalDagen 
FROM
   Fiets 
   INNER JOIN
      HuurovereenkomstFiets 
      ON HuurovereenkomstFiets_Fiets_id = Fiets_id 
   INNER JOIN
      Huurovereenkomst 
      ON Huurovereenkomst_id = HuurovereenkomstFiets_Huurovereenkomst_id 
WHERE
   YEAR(Huurovereenkomst_Begin_datum) = [Forms]![FietsAantDagen]![Txtinput] 
   AND YEAR(Huurovereenkomst_Eind_datum) = [Forms]![FietsAantDagen]![Txtinput] 
GROUP BY
   Fiets_id,
   Fiets_Type

在将此查询作为传递查询运行时,我收到以下错误:

  

ODBC:运行时错误[Microsoft] [SQL Server Native Client 11.0] [SQL   服务器]关键字' WHERE' /(#156)

附近的语法不正确

问题是我在传递查询中使用Access文本表单值,如果是,我该怎么做才能解决它?

我在读取你需要添加()的另一个Overflow问题,我做了,现在我得到了错误:

  

不支持JOIN表达式。

我疯了......

3 个答案:

答案 0 :(得分:1)

如果您没有直接使用SQL服务器,那么最好通过查询创建两个pass。

查询#1 - 这是您的原始SQL 例如:

SELECT
    Fiets_id,
    Fiets_Type,
    SUM(DATEDIFF(DAY, Huurovereenkomst_Begin_datum,
    Huurovereenkomst_Eind_datum)) AS AantalDagen 
FROM
   Fiets 
INNER JOIN
  HuurovereenkomstFiets 
  ON HuurovereenkomstFiets_Fiets_id = Fiets_id 
INNER JOIN
  Huurovereenkomst 
  ON Huurovereenkomst_id = HuurovereenkomstFiets_Huurovereenkomst_id 
WHERE
  YEAR(Huurovereenkomst_Begin_datum) = [StartYear]
  AND YEAR(Huurovereenkomst_Eind_datum) = [EndYear]
GROUP BY
  Fiets_id,
   Fiets_Type

查询#2 - 这是一个应用程序范围的查询,您可以反复使用任何原始t-SQL(SQL服务器通过)。然后你在代码中这样:

Dim rst     As DAO.Recordset
Dim strSQL  As String

strSQL = CurrentDb.QueryDefs("MyQ1").SQL
srtSQL = Replace(strSQL, "[YearStart]", [Forms]![FietsAantDagen]![Txtinput])
strSQL = Replace(strSQL, "[YearEnd]", [Forms]![FietsAantDagen]![Txtinput])
With CurrentDb.QueryDefs("qryPassR")
   .SQL = strSQL
  .ReturnsRecords = True
  Set rst = .OpenRecordset
End With

但是,如果你有能力使用SQL服务器,并创建一个proc,那么我建议你创建这样的存储过程:

CREATE PROCEDURE SelectDates
@StartYear int,
@EndYear int
AS
BEGIN
SET NOCOUNT ON;
 SELECT
   Fiets_id,
   Fiets_Type,
   SUM(DATEDIFF(DAY, Huurovereenkomst_Begin_datum, Huurovereenkomst_Eind_datum)) AS AantalDagen 
FROM
Fiets 
   INNER JOIN
    HuurovereenkomstFiets 
  ON HuurovereenkomstFiets_Fiets_id = Fiets_id 
INNER JOIN
   Huurovereenkomst 
   ON Huurovereenkomst_id = HuurovereenkomstFiets_Huurovereenkomst_id 
WHERE
YEAR(Huurovereenkomst_Begin_datum) = @StartYear
AND YEAR(Huurovereenkomst_Eind_datum) = @EndYear
GROUP BY
   Fiets_id,
   Fiets_Type

END

然后在访问中,您使用此:

Dim rst     As DAO.Recordset

With CurrentDb.QueryDefs("qryPassR")
   .SQL = "exec SelectDates " & [Forms]![FietsAantDagen]![Txtinput] & "," & _
          [Forms]![FietsAantDagen]![Txtinput]
  .ReturnsRecords = True
  Set rst = .OpenRecordset
End With

因此,通过传递参数可以减少与SQL注入有关的大多数问题。 当然,如果你不能创建存储过程,或者没有权限,那么你必须采用上面的第一个想法。您当然也可以在第一个建议中将原始SQL插入到代码编辑器中,但我发现使用额外的查询来“只”保存原始SQL,然后将SQL修改为第二个直通查询消除了需要对于VBA代码编辑器中的混乱SQL。

答案 1 :(得分:0)

当您运行Pass-Through查询时,其SQL文本将按原样发送到数据库服务器,不会对任何内容进行评估。因此,在Pass-Through查询中包含[Forms]![FietsAantDagen]![Txtinput]将永远不会有效。

您正在使用

走上正轨
SELECT * FROM fnFietsAantDagenPerJaar([Forms]![FietsAantDagen]![Txtinput])‌​

但你需要自己提供参数,因为(见上文)。

所以你需要构建Pass-Through SQL,例如使用此VBA程序:

Private Sub txtInput_AfterUpdate()

    Dim QD As DAO.QueryDef
    Dim lYear As Long

    ' Make sure we pass a number to the SQL Server function
    lYear = Val(Me!txtInput)
    If lYear > 0 Then
        Set QD = CurrentDb.QueryDefs("QueryFietsAantDagen")
        QD.SQL = "SELECT * FROM fnFietsAantDagenPerJaar(" & lYear & ")"
        Set QD = Nothing

        ' After changing the query SQL, requery the form
        ' This assumes that your form is bound to Pass-Through query QueryFietsAantDagen
        Me.Requery
    End If

End Sub

答案 2 :(得分:0)

传递查询仅在连接的外部数据库引擎(此处为SQL Server)上运行,并且在MS Access中看不到任何内容,只显示该外部环境中的所有内容。

考虑调整传递查询以避免任何MS Access评估,并添加分组以聚合查询。然后使用表单值在本地Access查询过滤中查询此结果集以查找所需的条件。下面为了清晰起见添加了表别名(如果不正确则调整)。

传递 (无WHERE子句,但已展开SELECTGROUP BY

SELECT
   f.Fiets_id,
   f.Fiets_Type,
   YEAR(h.Huurovereenkomst_Begin_datum) As BeginYear,
   YEAR(h.Huurovereenkomst_Eind_datum) As EndYear,
   SUM(DATEDIFF('d', h.Huurovereenkomst_Begin_datum, 
                     h.Huurovereenkomst_Eind_datum)) AS AantalDagen 
FROM
    HuurovereenkomstFiets_LinkTable hf
    INNER JOIN
      Fiets_LinkTable f
      ON hf.HuurovereenkomstFiets_Fiets_id = f.Fiets_id 
    INNER JOIN
      Huurovereenkomst_LinkTable h
      ON h.Huurovereenkomst_id = hf.HuurovereenkomstFiets_Huurovereenkomst_id 
GROUP BY
   f.Fiets_id,
   f.Fiets_Type,
   YEAR(h.Huurovereenkomst_Begin_datum),
   YEAR(h.Huurovereenkomst_Eind_datum)

本地查询

SELECT
   t.Fiets_id,
   t.Fiets_Type,
   t.AantalDagen 
FROM
   myPassThroughQuery t
WHERE t.BeginYear = [Forms]![FietsAantDagen]![Txtinput]
  AND t.EndYear = [Forms]![FietsAantDagen]![Txtinput]

或者,考虑使用SQL Server中的链接表(具有与传递相同的ODBC连接),其中Access可将它们视为本地表。因此,您可以使用表单日期值运行查询。请注意,您必须将语法转换为遵守Access' SQL方言,如DATEDIFFJOIN括号。性能可能因引擎改变而有所不同,但是测试。

链接表本地查询

SELECT
   f.Fiets_id,
   f.Fiets_Type,
   SUM(DATEDIFF('d', h.Huurovereenkomst_Begin_datum, 
                     h.Huurovereenkomst_Eind_datum)) AS AantalDagen 
FROM
   (HuurovereenkomstFiets_LinkTable hf
    INNER JOIN
      Fiets_LinkTable f
      ON hf.HuurovereenkomstFiets_Fiets_id = f.Fiets_id) 
    INNER JOIN
      Huurovereenkomst_LinkTable h
      ON h.Huurovereenkomst_id = hf.HuurovereenkomstFiets_Huurovereenkomst_id 
WHERE YEAR(h.Huurovereenkomst_Begin_datum) = [Forms]![FietsAantDagen]![Txtinput] 
  AND YEAR(h.Huurovereenkomst_Eind_datum) = [Forms]![FietsAantDagen]![Txtinput] 
GROUP BY
   f.Fiets_id,
   f.Fiets_Type

要自动创建链接表,请使用DoCmd.TransferDatabase。否则,请使用功能区上的External Data / ODBC Database图标并完成设置向导。

DoCmd.TransferDatabase acLink, "ODBC Database", _
    "ODBC;DRIVER={SQL Server};Server=<ServerAddress>;Database=<DBname>;Trusted_Connection=Yes;", _
    acTable, "HuurovereenkomstFiets", "HuurovereenkomstFiets_LinkedTable"