SQL / ACCESS函数无法按预期工作

时间:2018-11-14 18:54:10

标签: sql ms-access

Public Function GetPendingChangeOrders(strJ As String) As Double

strSQL = "SELECT DISTINCT Sum(jcdetail.cost) AS SumOfcost " & 
                    "FROM jcchangeorder INNER JOIN jcdetail ON (jcchangeorder.ordernum = jcdetail.ponum) AND (jcchangeorder.jobnum =jcdetail.jobnum) " & 
                    "GROUP BY jcdetail.jobnum, jcdetail.type, jcchangeorder.type, IIf(DLookUp(""type"",""jcchangeorderstep"",""jobnum = '"" & [jcchangeorder].[jobnum] & ""' and ordernum = '"" & [ordernum] & ""' and Type = 20"")=20,-1,0) " & _
                    "HAVING (((jcdetail.jobnum)='" & strJ & "') AND ((jcdetail.type)=19) AND ((jcchangeorder.type)<>2) AND ((IIf(DLookUp(""type"",""jcchangeorderstep"",""jobnum = '"" & [jcchangeorder].[jobnum] & ""' and ordernum = '"" & [ordernum] & ""' and Type = 20"")=20,-1,0))=0));"


Set rs = dbs.OpenRecordset(strSQL, dbOpenSnapshot, dbReadOnly, dbReadOnly)

 If Not rs.EOF Then
    dblResult = Nz(rs.Fields(0), 0)
    rs.Close
    Set rs = Nothing
    GetPendingChangeOrders = dblResult
Else
    GetPendingChangeOrders = 0
End If
End Function

因此,我迷上了一些带有VBA / SQL语句的MS-Access数据库。 我实际上是一个初学者,但是我设法弄清楚了一些事情,并使自己熟悉了我们用于打印作业报告的数据库。 某些调用函数设置有误,并且是从错误的表中提取的,基本上,我需要一些帮助,以确定应该采取哪种方法。

当前,如果我们运行报表,并调用“ GetPendingChangeOrders ”,它将执行应做的工作,但是当我们查看待处理的内容时。 即使“ JCCHANGEORDERSTEP”表中的状态为21(DENIED),它也会显示结果。我包括了它的图像。

JCCHANGEORDER与JCCHANGEORDERSTEP(JOBNUM,ORDERNUM,TYPE)的列相同,但JCCHANGEORDER中的类型只有1,我认为这很活跃。

JCCHANGEORDERSTEP包含1个已发起(待定),20个(已批准),21个(已拒绝)。它从报告的结果中筛选出20而不是21。因此,我只需要一些帮助,并解释了为什么仅将21加到混合中是行不通的。

谢谢您的时间。

EDIT-1添加了IMGS IMGUR ACCESS PICTURES

2 个答案:

答案 0 :(得分:0)

您在HAVING和GROUP BY子句中查询的这一部分是给您带来问题的原因:

IIf(DLookUp("type",
            "jcchangeorderstep",
            "jobnum = ' [jcchangeorder].[jobnum] ' and 
              ordernum = ' [ordernum] ' and
              Type = 20")=20,-1,0))=0);

令人费解,很难阅读。但是,这是说:“如果此工作和订单出现在 JCCHANGEORDERSTEP 中,类型为20,则将其排除。”因此,这就是您需要解决的问题。

整个查询可能应该以多种方式固定。但是我认为这可能使您到达需要的地方。

strSQL = "SELECT DISTINCT Sum(jcdetail.cost) AS SumOfcost " & _
           "FROM jcchangeorder " & _
                "INNER JOIN jcdetail " & _
                         "ON (jcchangeorder.ordernum = jcdetail.ponum) " & _
                        "AND (jcchangeorder.jobnum =jcdetail.jobnum) " & _
          "GROUP BY jcdetail.jobnum, " & _
                   "jcdetail.type, " & _
                   "jcchangeorder.type, " & _
                   "DLookUp(""type"",""jcchangeorderstep"",""jobnum = '"" & [jcchangeorder].[jobnum] & ""' and ordernum = '"" & [ordernum] & ""' and Type = 1"") " & _
         "HAVING (jcdetail.jobnum='" & strJ & "' AND " & _
                 "jcdetail.type=19 AND " & _
                 "jcchangeorder.type <> 2) AND  " & _
                 "DLookUp(""type"",""jcchangeorderstep"",""jobnum = '"" & [jcchangeorder].[jobnum] & ""' and ordernum = '"" & [ordernum] & ""' and Type = 1"")=1;"

我所做的更改为条件为“如果此工作和订单出现在 JCCHANGEORDERSTEP 中,且类型为1,则将其包括在内”。如果没有实际看到您的数据并亲自测试代码,我不能保证这会起作用。可能会有一些错别字,所以我已经解释了我要做什么,以便您可以解决它们。

另外,花一些时间来完成堆栈溢出之旅。如果您与之合作,那么这个社区将是一个很大的帮助。

尝试一下:
在与OP讨论了预期的结果之后,看来这将是一个更好的解决方案。它给出了只有 变更订单步骤为PENDING的所有变更订单的总和。

strSQL = _
"SELECT SUM(JCD.cost) AS sumofcost " & _
  "FROM jcchangeorder JCCO  " & _
       "INNER JOIN jcdetail JCD  " & _
               "ON JCCO.ordernum = jcd.ponum  " & _
              "AND JCCO.jobnum = jcd.jobnum  " & _
       "INNER JOIN (SELECT JCCOS.ponum,  " & _
                          "JCCOS.jobnum  " & _
                     "FROM jcchangeorderstep JCCOS  " & _
                    "GROUP BY JCCOS.ponum,  " & _
                             "JCCOS.jobnum  " & _
                   "HAVING Count(*) = 1  " & _
                      "AND First(JCCOS.type) = 1) JCSELECT  " & _
               "ON JCCO.ordernum = JCSELECT.ponum  " & _
                  "AND JCCO.jobnum = JCSELECT.jobnum  " & _
 "GROUP BY JCD.jobnum,  " & _
          "JCD.type,  " & _
          "JCCO.type "
"HAVING JCD.jobnum='" & strJ & "' AND " & _
       "JCD.type=19 AND " & _
       "JCCO.type <> 2;"

JCCO,JCCOS和JCD是SQL别名。 SQL理解它们。 JCSELECT是一个别名子查询。 JCSELECT创建的一组所有作业/订单只有一个待处理步骤。

答案 1 :(得分:0)

查看了图像并研究了现有的SQL代码之后,我认为以下SQL查询可能更合适并且更易读:

select sum(d.cost) as sumofcost 
from 
    (
        jcchangeorder o inner join jcdetail d
        on o.ordernum = d.ponum and o.jobnum = d.jobnum
    ) inner join
    (
        select distinct s.jobnum, s.ordernum 
        from jcchangeorderstep s 
        where s.type = 1
    ) q
    on o.jobnum = q.jobnum and o.ordernum = q.ordernum
where
    o.jobnum = ?job and d.type = 19 and o.type <> 2

在这里,包含jcdetail条记录,其中jcchangeorderstep.type = 1由表之间的inner join处理,而不是为每条记录单独的dlookup

您可以通过以下方式在您的函数中实现此目标:

Public Function GetPendingChangeOrders(strJ As String) As Double
    Dim strS As String
    strS = strS & "select sum(d.cost) "
    strS = strS & "from "
    strS = strS & "    ( "
    strS = strS & "        jcchangeorder o inner join jcdetail d "
    strS = strS & "        on o.ordernum = d.ponum and o.jobnum = d.jobnum "
    strS = strS & "    ) inner join "
    strS = strS & "    ( "
    strS = strS & "        select distinct s.jobnum, s.ordernum "
    strS = strS & "        from jcchangeorderstep s "
    strS = strS & "        where s.type = 1 "
    strS = strS & "    ) q "
    strS = strS & "    on o.jobnum = q.jobnum and o.ordernum = q.ordernum "
    strS = strS & "where "
    strS = strS & "    o.jobnum = ?job and d.type = 19 and o.type <> 2 "

    Dim rst As DAO.Recordset
    With CurrentDb.CreateQueryDef("", strS)
        .Parameters(0) = strJ
        Set rst = .OpenRecordset
        If Not rst.EOF Then
            rst.MoveFirst
            GetPendingChangeOrders = Nz(rst.Fields(0), 0)
        End If
        rst.Close
    End With
End Function

编辑:

在后续评论之后,以下内容似乎更符合您的要求:

select sum(d.cost) 
from  
    jcchangeorder o inner join jcdetail d 
    on o.ordernum = d.ponum and o.jobnum = d.jobnum
where
    o.jobnum = jobparam and
    d.type = 19 and
    o.type <> 2 and
    not exists 
    (
        select 1 from jcchangeorderstep s 
        where s.jobnum = o.jobnum and s.ordernum = o.ordernum and s.type <> 1
    )

这可以通过以下方式在您的VBA功能中实现:

Public Function GetPendingChangeOrders(strJ As String) As Double
    Dim strS As String
    strS = strS & "select sum(d.cost) "
    strS = strS & "from  "
    strS = strS & "    jcchangeorder o inner join jcdetail d "
    strS = strS & "    on o.ordernum = d.ponum and o.jobnum = d.jobnum "
    strS = strS & "where "
    strS = strS & "    o.jobnum = jobparam and "
    strS = strS & "    d.type = 19 and "
    strS = strS & "    o.type <> 2 and "
    strS = strS & "    not exists "
    strS = strS & "    ( "
    strS = strS & "        select 1 from jcchangeorderstep s "
    strS = strS & "        where s.jobnum = o.jobnum and s.ordernum = o.ordernum and s.type <> 1 "
    strS = strS & "    ) "

    Dim rst As DAO.Recordset
    With CurrentDb.CreateQueryDef("", strS)
        .Parameters("jobparam") = strJ
        Set rst = .OpenRecordset
        If Not rst.EOF Then
            rst.MoveFirst
            GetPendingChangeOrders = Nz(rst.Fields(0), 0)
        End If
        rst.Close
    End With
End Function