SELECT * FROM dual WHERE CASE WHEN FALSE THEN 1>0 ELSE 0<1 END 达梦为什么报错 SQL 错误 [42000]: 第 1 行, 第 84 列[>]附近出现错误: 语法分析出错
时间: 2024-10-12 22:11:02 浏览: 24
这个SQL查询在达梦数据库中报错的原因在于它包含了一个逻辑表达式和CASE语句的组合,但在某些SQL方言中,尤其是达梦,这种结构可能解析不正确。首先,CASE语句通常用于条件选择,返回一个值而非布尔结果。在这个例子中:
```sql
CASE WHEN FALSE THEN 1 > 0 ELSE 0 < 1 END
```
`FALSE`已经是明确的布尔值,所以`WHEN`后面的比较表达式1>0实际上是多余的,因为当`FALSE`为真时,整个CASE语句的结果就是`FALSE`。而`ELSE`部分的0<1同样是恒假的,因为0永远不大于1。
其次,`SELECT * FROM dual`试图从系统表Dual中获取所有列,但当你在CASE语句中放置这样的逻辑表达式,可能使得整个WHERE子句无法被有效地解析,导致语法错误。
达梦数据库可能期望的是直接的布尔表达式作为CASE语句的结果,而不是嵌套的比较操作。正确的处理方式应该是只返回一个布尔值,例如:
```sql
CASE WHEN FALSE THEN 0 ELSE 1 END
```
如果需要在WHERE子句中使用此布尔值,可以这样做:
```sql
SELECT * FROM dual WHERE (CASE WHEN FALSE THEN 0 ELSE 1 END) = 1
```
相关问题
优化这段sql SELECT (CASE WHEN DATE_FORMAT( `start_time`, '%H:%i:%S' ) > '00:00:00' and DATE_FORMAT( `start_time`, '%H:%i:%S' ) <= '03:59:59' THEN '00:00-03:59' WHEN DATE_FORMAT( `start_time`, '%H:%i:%S' ) > '04:00:00' and DATE_FORMAT( `start_time`, '%H:%i:%S' ) <= '07:59:59' THEN '04:00-07:59' WHEN DATE_FORMAT( `start_time`, '%H:%i:%S' ) > '08:00:00' and DATE_FORMAT( `start_time`, '%H:%i:%S' ) <= '11:59:59' THEN '08:00-11:59' WHEN DATE_FORMAT( `start_time`, '%H:%i:%S' ) > '12:00:00' and DATE_FORMAT( `start_time`, '%H:%i:%S' ) <= '15:59:59' THEN '12:00-15:59' WHEN DATE_FORMAT( `start_time`, '%H:%i:%S' ) > '16:00:00' and DATE_FORMAT( `start_time`, '%H:%i:%S' ) <= '19:59:59' THEN '16:00-19:59' WHEN DATE_FORMAT( `start_time`, '%H:%i:%S' ) > '20:00:00' and DATE_FORMAT( `start_time`, '%H:%i:%S' ) <= '23:59:59' THEN '20:00-23:59' ELSE '' END) AS timeInterval, IFNULL( SUM( `dual_time` ), 0 ) AS totalTime, IFNULL( COUNT(1), 0 ) AS totalCall, IFNULL( SUM( CASE WHEN `local_action` = '主叫' THEN 1 ELSE 0 END ), 0 ) AS active, IFNULL( SUM( CASE WHEN `local_action` = '被叫' THEN 1 ELSE 0 END ), 0 ) AS passive FROM `dwd_t_call_record` WHERE `person_no` = '653129200105072624' GROUP BY HOUR ( `start_time` ) DIV 4
可以使用 MySQL 的 `CASE WHEN` 语句来简化这段 SQL 语句,同时避免重复的日期格式化操作。简化后的 SQL 语句如下:
```
SELECT
CONCAT(HOUR(`start_time`) DIV 4 * 4, ':00-', HOUR(`start_time`) DIV 4 * 4 + 3, ':59') AS timeInterval,
IFNULL(SUM(`dual_time`), 0) AS totalTime,
IFNULL(COUNT(1), 0) AS totalCall,
IFNULL(SUM(`local_action` = '主叫'), 0) AS active,
IFNULL(SUM(`local_action` = '被叫'), 0) AS passive
FROM
`dwd_t_call_record`
WHERE
`person_no` = '653129200105072624'
GROUP BY
HOUR(`start_time`) DIV 4
```
这个 SQL 语句使用了 `CONCAT` 函数来生成时间区间,使用了 `SUM` 函数的布尔表达式参数来计算主叫和被叫的数量。同时,将日期格式化操作转化为了整数运算,避免了多次重复的格式化操作。
SELECT CUST_ID agentId, AGE_NAME agentName, countReleased, dayAmountReleased, CASE o.agelimitType WHEN '1' THEN TO_CHAR(o.agelimitNum) ELSE TO_CHAR(o.issueamtlimit) END countLimit, CASE o.agelimitType WHEN '1' THEN '不限' ELSE TO_CHAR(o.daylimitamount) END dayMaxCount FROM (SELECT m.CUST_ID, m.AGE_NAME, ad.countReleased, t.dayAmountReleased, d.daylimitamount, d.issueamtlimit, (SELECT AGE_LIMIT_NUM FROM P_ACT_ALLOW_MANAGER WHERE ACTIVITY_ID = #{activityId} AND rownum = 1 ) AS agelimitNum, (SELECT AGE_LIMIT_NUM_TYPE FROM P_ACT_MANAGER_ACTIVITY WHERE ACTIVITY_ID = #{activityId} ) AS agelimitType FROM (SELECT c1.CUST_ID, c1.AGE_NAME FROM (SELECT CUST_ID, AGE_NAME FROM PM_AGET_INFO START WITH CUST_ID = #{agetId} CONNECT BY PRIOR CUST_ID = FATH_CUST_ID ) c1 INNER JOIN (SELECT DISTINCT CUST_ID, AGE_NAME FROM PM_AGET_INFO START WITH CUST_ID in (SELECT CUST_ID FROM P_ACT_ALLOW_MANAGER WHERE ACTIVITY_ID = #{activityId} ) CONNECT BY PRIOR CUST_ID = FATH_CUST_ID ) c2 ON c1.CUST_ID = c2.CUST_ID ) m LEFT JOIN (SELECT CUST_ID, count(RECORD_ID) countReleased FROM P_ACT_MANAGER_RECORD WHERE ACTIVITY_ID = #{activityId} AND RECORD_STATUS NOT IN (2, 5) AND to_date(CREATE_TIME, 'yyyy-MM-dd hh24:mi:ss') BETWEEN to_date(#{beginTime}, 'yyyyMMddhh24miss') AND to_date(#{endTime}, 'yyyyMMddhh24miss') GROUP BY CUST_ID ) ad ON m.CUST_ID = ad.CUST_ID LEFT JOIN (SELECT AGE_ID cust_id, DAY_LIMIT_AMOUNT daylimitAmount, ISSUE_AMT_LIMIT issueAmtLimit FROM P_ACT_MANAGER_LIMIT_ALLOT WHERE ACT_ID =#{activityId} ) d ON m.CUST_ID = d.CUST_ID LEFT JOIN (SELECT CUST_ID, count(RECORD_ID) dayAmountReleased FROM P_ACT_MANAGER_RECORD WHERE ACTIVITY_ID =#{activityId} AND RECORD_STATUS NOT IN (2, 5) AND to_date(CREATE_TIME, 'yyyy-MM-dd hh24:mi:ss') BETWEEN to_date(#{todayBegin}, 'yyyyMMddhh24miss') AND to_date(#{todayend}, 'yyyyMMddhh24miss') GROUP BY CUST_ID ) t ON m.CUST_ID = t.CUST_ID) o WHERE 1 = 1 AND o.CUST_ID = #{agentId} AND o.AGE_NAME = #{agentName} ORDER BY o.countReleased DESC NULLS LAST 如何优化此段sql代码,使得更加简洁?
这段 SQL 代码可以进行以下优化:
1. 使用 WITH 子句来代替嵌套查询,增加可读性。
2. 使用 LEFT JOIN 和 COALESCE 函数来代替子查询,避免多次查询。
3. 使用 CASE WHEN THEN ELSE END 语句来代替 IF 函数。
优化后的 SQL 代码如下:
WITH
cte1 AS (
SELECT
CUST_ID,
AGE_NAME
FROM
PM_AGET_INFO
START WITH
CUST_ID = #{agetId}
CONNECT BY
PRIOR CUST_ID = FATH_CUST_ID
),
cte2 AS (
SELECT
DISTINCT CUST_ID,
AGE_NAME
FROM
PM_AGET_INFO
START WITH
CUST_ID IN (
SELECT
CUST_ID
FROM
P_ACT_ALLOW_MANAGER
WHERE
ACTIVITY_ID = #{activityId}
)
CONNECT BY
PRIOR CUST_ID = FATH_CUST_ID
),
cte3 AS (
SELECT
CUST_ID,
count(RECORD_ID) countReleased
FROM
P_ACT_MANAGER_RECORD
WHERE
ACTIVITY_ID = #{activityId}
AND RECORD_STATUS NOT IN (2, 5)
AND to_date(CREATE_TIME, 'yyyy-MM-dd hh24:mi:ss') BETWEEN to_date(#{beginTime}, 'yyyyMMddhh24miss') AND to_date(#{endTime}, 'yyyyMMddhh24miss')
GROUP BY
CUST_ID
),
cte4 AS (
SELECT
CUST_ID,
count(RECORD_ID) dayAmountReleased
FROM
P_ACT_MANAGER_RECORD
WHERE
ACTIVITY_ID =#{activityId}
AND RECORD_STATUS NOT IN (2, 5)
AND to_date(CREATE_TIME, 'yyyy-MM-dd hh24:mi:ss') BETWEEN to_date(#{todayBegin}, 'yyyyMMddhh24miss') AND to_date(#{todayend}, 'yyyyMMddhh24miss')
GROUP BY
CUST_ID
),
cte5 AS (
SELECT
AGE_LIMIT_NUM
FROM
P_ACT_ALLOW_MANAGER
WHERE
ACTIVITY_ID = #{activityId}
AND rownum = 1
),
cte6 AS (
SELECT
AGE_LIMIT_NUM_TYPE
FROM
P_ACT_MANAGER_ACTIVITY
WHERE
ACTIVITY_ID = #{activityId}
),
cte7 AS (
SELECT
AGE_ID cust_id,
DAY_LIMIT_AMOUNT daylimitAmount,
ISSUE_AMT_LIMIT issueAmtLimit
FROM
P_ACT_MANAGER_LIMIT_ALLOT
WHERE
ACT_ID =#{activityId}
)
SELECT
m.CUST_ID agentId,
m.AGE_NAME agentName,
COALESCE(ad.countReleased, 0) countReleased,
COALESCE(t.dayAmountReleased, 0) dayAmountReleased,
CASE
WHEN o.agelimitType = '1' THEN TO_CHAR(o.agelimitNum)
ELSE TO_CHAR(o.issueamtlimit)
END countLimit,
CASE
WHEN o.agelimitType = '1' THEN '不限'
ELSE TO_CHAR(o.daylimitamount)
END dayMaxCount
FROM
cte1 m
INNER JOIN cte2 c ON m.CUST_ID = c.CUST_ID AND m.AGE_NAME = c.AGE_NAME
LEFT JOIN cte3 ad ON m.CUST_ID = ad.CUST_ID
LEFT JOIN cte4 t ON m.CUST_ID = t.CUST_ID
LEFT JOIN cte5 ON 1 = 1
LEFT JOIN cte6 ON 1 = 1
LEFT JOIN cte7 d ON m.CUST_ID = d.CUST_ID
LEFT JOIN (
SELECT
COALESCE(AGE_LIMIT_NUM, 0) agelimitNum,
COALESCE(AGE_LIMIT_NUM_TYPE, '1') agelimitType
FROM
dual
) o ON 1 = 1
WHERE
m.CUST_ID = #{agentId}
AND m.AGE_NAME = #{agentName}
ORDER BY
COALESCE(ad.countReleased, 0) DESC NULLS LAST
这样可以使得代码更加简洁易读,并且避免了重复查询和嵌套查询的问题。
阅读全文