【问题标题】:MS Access using forms in a pass-through queryMS Access 在传递查询中使用表单
【发布时间】:2018-01-05 20:43:08
【问题描述】:

我有一个名为 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 Server]关键字 'WHERE'/ (#156) 附近的语法不正确

是我在传递查询中使用 Access 文本表单值的问题吗?如果是,我该如何解决?

我阅读了另一个需要添加 () 的溢出问题,我这样做了,现在我得到了错误:

不支持 JOIN 表达式。

我要疯了……

【问题讨论】:

  • 查看选择查询的语法。 GROUP BY 出现在 WHERE 子句之后。
  • 糟糕,从其他评论中复制它时出错。现在它给出了同样的错误,但是:'!'附近的语法不正确。 (#102)
  • 在传递查询之前使用 SSMS 调试您的查询。
  • 当您尝试将 MS Access 表单添加到 SQL Server 查询中时,这很难.....

标签: sql sql-server ms-access


【解决方案1】:

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

查询 #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 server 并创建一个 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 注入有关的问题。 当然,如果你不能创建 store procs,或者没有权限,那么你必须采用上面的第一个想法。当然,您也可以在第一个建议中将原始 SQL 插入代码编辑器,但我发现使用了一个额外的查询来“仅”保存原始 SQL,然后将 SQL 修改为第二个传递查询就不需要了用于 VBA 代码编辑器中的凌乱 SQL。

【讨论】:

    【解决方案2】:

    当您运行 Pass-Through 查询时,其 SQL 文本会按原样发送到 DB 服务器,不会评估任何内容。因此,在传递查询中包含 [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
    

    【讨论】:

      【解决方案3】:

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

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

      传递 (没有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"
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-02-03
        • 1970-01-01
        • 1970-01-01
        • 2015-12-18
        • 1970-01-01
        • 2013-06-01
        • 2017-03-02
        • 2018-09-08
        相关资源
        最近更新 更多