【问题标题】:SQL Command Not Properly Ended - Oracle SubquerySQL 命令未正确结束 - Oracle 子查询
【发布时间】:2016-05-07 00:01:36
【问题描述】:

我正在使用 Crystal Reports 13 添加命令从通过 Oracle 11g 客户端连接的 Oracle 数据库中选择记录。我收到的错误是 ORA-00933:SQL 命令未正确结束,但我的代码找不到任何问题(不完整):

/*  Determine units with billing code effective dates in the previous month  */
SELECT "UNITS"."UnitNumber", "BILL"."EFF_DT"
FROM "MFIVE"."BILL_UNIT_ACCT" "BILL"
LEFT OUTER JOIN "MFIVE"."VIEW_ALL_UNITS" "UNITS" ON "BILL"."UNIT_ID" = "UNITS"."UNITID"
WHERE  "UNITS"."OwnerDepartment" LIKE '580' AND TO_CHAR("BILL"."EFF_DT", 'MMYYYY') = TO_CHAR(ADD_MONTHS(TRUNC(SYSDATE), -1), 'MMYYYY')

INNER JOIN

/*  Loop through previously identified units and determine last billing code change prior to preious month  */
(
SELECT "BILL2"."UNIT_ID", MAX("BILL2"."EFF_DT")
FROM "MFIVE"."BILL_UNIT_ACCT" "BILL2"
WHERE TO_CHAR("BILL2"."EFF_DT", 'MMYYYY') < TO_CHAR(ADD_MONTHS(TRUNC(SYSDATE), -1), 'MMYYYY')
GROUP BY "BILL2"."UNIT_ID"
)

ON "BILL"."UNIT_ID" = "BILL2"."UNIT_ID"
ORDER BY "UNITS"."UnitNumber", "BILL"."EFF_DT" DESC

我们是一家将车辆(单元)出租给其他机构的国家实体。每个单位都有一个带有相关生效日期的帐单代码。该应用程序是为上个月的帐单代码更改的单位制定报告。

使问题复杂化的是,对于上述每个单位,报告还必须显示上个月之前的最新帐单代码和相关生效日期。一个简单的例子:

鉴于此数据并假设现在是 2016 年 4 月(为了清楚起见,排序)...

Unit    Billing Code    Effective Date  Excluded
----    ------------    --------------  --------
1       A               04/15/2016      Present month
1       B               03/29/2016
1       A               03/15/2016
1       C               03/02/2016
1       B               01/01/2015
2       C               03/25/2016
2       A               03/04/2016
2       B               07/24/2014
2       A               01/01/2014      A later effective date prior to previous month exists
3       D               11/28/2014      No billing code change during previous month

报告应返回以下内容...

Unit    Billing Code    Effective Date
----    ------------    --------------
1       B               03/29/2016
1       A               03/15/2016
1       C               03/02/2016
1       B               01/01/2015
2       C               03/25/2016
2       A               03/04/2016
2       B               07/24/2014  

任何解决错误的帮助将不胜感激。

【问题讨论】:

  • JOIN 子句不能跟在WHERE 子句之后

标签: sql oracle oracle11g crystal-reports


【解决方案1】:

INNER JOIN 子句之前有一个 WHERE 子句。这是无效的语法 - 如果你交换它们应该可以工作:

SELECT "UNITS"."UnitNumber",
       "BILL"."EFF_DT"
FROM   "MFIVE"."BILL_UNIT_ACCT" "BILL"
       LEFT OUTER JOIN
       "MFIVE"."VIEW_ALL_UNITS" "UNITS"
       ON "BILL"."UNIT_ID" = "UNITS"."UNITID"

INNER JOIN

/*  Loop through previously identified units and determine last billing code change prior to preious month  */
    (
    SELECT "UNIT_ID",
           MAX("EFF_DT")
    FROM   "MFIVE"."BILL_UNIT_ACCT"
    WHERE  TO_CHAR("EFF_DT", 'MMYYYY') < TO_CHAR(ADD_MONTHS(TRUNC(SYSDATE), -1), 'MMYYYY')
    GROUP BY "UNIT_ID"
    ) "BILL2"

    ON "BILL"."UNIT_ID" = "BILL2"."UNIT_ID"
WHERE  "UNITS"."OwnerDepartment" LIKE '580'
AND    TO_CHAR("BILL"."EFF_DT", 'MMYYYY') = TO_CHAR(ADD_MONTHS(TRUNC(SYSDATE), -1), 'MMYYYY')
ORDER BY "UNITS"."UnitNumber", "BILL"."EFF_DT" DESC

此外,您需要将 "BILL2" 别名移到 () 括号外,因为您不需要括号内的别名,但您需要在括号外。

您确定需要双引号 "" 吗?双引号在列名中强制区分大小写 - 默认行为是 Oracle 将所有表和列名转换为大写以从用户那里抽象区分大小写 - 因为您同时使用双引号和大写名称引号似乎是多余的。

【讨论】:

  • @MTD 谢谢。我认为语法问题正困扰着我。毫无疑问,这与我构建查询的方式有关,但结果记录仅显示上个月内的更改。将 WHERE 子句移到末尾会限制输出排除上个月之前的最近生效日期。
【解决方案2】:

解决方案:

SELECT DISTINCT "BILL2".*
FROM "MFIVE"."BILL_UNIT_ACCT" "BILL"
LEFT JOIN

  /*  Returns all rows for each unit with effective date >= maximum prior effective date and effective date < current month */
  (
  SELECT "UNITS"."UnitNumber" AS "UNITNO",
    UPPER("UNITS"."SpecNoDescription") AS "TS_DESCR",
    "UNITS"."UsingDepartment" AS "USING_DEPT",
    "UNITS"."OwnerDepartment" AS "OWNING_DEPT",
    "BILL"."BILLING_CODE",
    "BILL"."EFF_DT",
    "BILL"."UNIT_ID"
  FROM "MFIVE"."BILL_UNIT_ACCT" "BILL"
  LEFT OUTER JOIN "MFIVE"."VIEW_ALL_UNITS" "UNITS" ON "BILL"."UNIT_ID" =  "UNITS"."UNITID"
  WHERE TO_NUMBER(TO_CHAR(TRUNC("BILL"."EFF_DT"), 'YYYYMM'), '999999') < TO_NUMBER(TO_CHAR(TRUNC(ADD_MONTHS(SYSDATE, 0)), 'YYYYMM'), '999999') AND
"UNITS"."OwnerDepartment" = '580' AND
"BILL"."EFF_DT" >=

    /*  Returns maximum effective date prior to previous month for each unit  */
    (
    SELECT MAX("BILL3"."EFF_DT")
    FROM "MFIVE"."BILL_UNIT_ACCT" "BILL3"
    WHERE "BILL3"."UNIT_ID" = "BILL"."UNIT_ID" AND
      TO_NUMBER(TO_CHAR(TRUNC("BILL3"."EFF_DT"), 'YYYYMM'), '999999') < TO_NUMBER(TO_CHAR(TRUNC(ADD_MONTHS(SYSDATE, -1)), 'YYYYMM'), '999999')
    GROUP BY "BILL3"."UNIT_ID"
    ) 

  ) BILL2

ON "BILL"."UNIT_ID" = "BILL2"."UNIT_ID"
WHERE TO_CHAR("BILL"."EFF_DT", 'YYYYMM') = TO_CHAR(ADD_MONTHS(TRUNC(SYSDATE), -1), 'YYYYMM')
ORDER BY "BILL2"."UNITNO", "BILL2"."EFF_DT" DESC

【讨论】:

    【解决方案3】:

    如果 Join 之前的 where 对您来说真的很重要,请使用 CTE。 (对临时表使用with 子句并在其上加入。)

      With c as (SELECT "UNITS"."UnitNumber", "BILL"."EFF_DT","BILL"."UNIT_ID"  -- Correction:  Was " BILL"."UNIT_ID" (spacetanker)
        FROM "MFIVE"."BILL_UNIT_ACCT" "BILL" -- Returning unit id column too, to be used in join
    
    LEFT OUTER JOIN "MFIVE"."VIEW_ALL_UNITS" "UNITS" ON "BILL"."UNIT_ID" = "UNITS"."UNITID"
        WHERE  "UNITS"."OwnerDepartment" LIKE '580' AND TO_CHAR("BILL"."EFF_DT", 'MMYYYY') = TO_CHAR(ADD_MONTHS(TRUNC(SYSDATE), -1), 'MMYYYY'))
    
        select * from c     --Filter out your required columns from c and d alias results, e.g c.UNIT_ID
        INNER JOIN
    
        --Loop through previously identified units and determine last billing code change prior to preious month  */
        (
        SELECT "BILL2"."UNIT_ID", MAX("BILL2"."EFF_DT")
        FROM "MFIVE"."BILL_UNIT_ACCT" "BILL2"
        WHERE TO_CHAR("BILL2"."EFF_DT", 'MMYYYY') < TO_CHAR(ADD_MONTHS(TRUNC(SYSDATE), -1), 'MMYYYY')
        GROUP BY "BILL2"."UNIT_ID"
        ) d
    
        ON c."UNIT_ID" = d."UNIT_ID"
         order by c."UnitNumber", c."EFF_DT" desc  -- COrrection:  Removed semicolon that Crystal Reports didn't like (spacetanker)
    

    不过,这个查询似乎有很大的调整空间。但是,能够访问数据和需求规范的人是最好的判断者。

    编辑: 由于您在原始问题的 select 语句中使用 BILL.EFF_DT,因此您无法查看上个月之前的数据,该语句被过滤为仅提供上个月的日期(..AND TO_CHAR("BILL"."EFF_DT", 'MMYYYY') = TO_CHAR(ADD_MONTHS(TRUNC(SYSDATE), -1), 'MMYYYY'))

    如果您想要数据,我想您必须使用 BILL2 部分(我的子查询中的 d 部分),为 Max(EFF_DT) 提供别名,并在您的 select 子句中使用该别名。

    【讨论】:

    • @IaB,谢谢。您的建议似乎包含逻辑,但是当我尝试执行它时,CR 返回可怕的 SQL 命令未正确结束错误。现在仔细看看。
    • @spacetanker,我在 c 中放错了 bill.unit_id。已编辑。
    • @IaB。不幸的是,仍然收到相同的错误消息。
    • @spacetanker,您的代码中是否有您未在此处发布的内容?我上面的查询看起来不错。
    • @IaB,有两个问题。首先,SELECT 中的空格为“(space)BILL”.“UNIT_ID”。直到我删除了分号(显然 Crystal Reports 不喜欢它们),我才明白这一点。所以查询现在正在运行,但它仍然只显示上个月的值;即,它不显示最后生效日期是上个月之前的月份。
    猜你喜欢
    • 2013-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-04
    • 1970-01-01
    • 1970-01-01
    • 2014-04-15
    • 2022-01-18
    相关资源
    最近更新 更多