如何通过 select 语句直接创建复杂查询而不是创建函数

Posted

技术标签:

【中文标题】如何通过 select 语句直接创建复杂查询而不是创建函数【英文标题】:How to create complex queries directly via select statement instead of creating functions 【发布时间】:2017-07-08 14:47:44 【问题描述】:

以下是运行良好的方法,但我如何转换它并直接在 select 语句中使用它以获得所需的结果。

SET GLOBAL log_bin_trust_function_creators=1;
DROP FUNCTION IF EXISTS DayCount;
DELIMITER |

CREATE FUNCTION DayCount( d1 DATE, d2 DATE, daynum SMALLINT ) RETURNS INT
BEGIN
 DECLARE days INT DEFAULT 0;
  IF D1 IS NOT NULL AND D2 IS NOT NULL THEN
    WHILE D1 <= d2 DO
      BEGIN
        IF DAYOFWEEK(d1) = daynum THEN
          SET days=days+1;
        END IF;
        SET d1 = ADDDATE(d1, INTERVAL 1 DAY);
      END;
END WHILE;
END IF;
RETURN days;
END;
|
DELIMITER;

选择 (daycount('2017-02-05','2017-02-20',7)) + (daycount('2017-02-05','2017-02-20',1)) AS '周末';

对于上述查询,我​​需要一种动态传递 7 和 1 的方法,以便能够传递非工作日,并从主查询中删除这些日子以计算分辨率和响应时间,但根本没有任何功能,直接选择语句这样做的方法。

更新:

我在下面有一个查询,我正在计算 closeDateedate 之间的时间,我需要排除非工作日,非工作日列表是动态的,它可能是从 1 到 7(周日到周六),我的要求是排除非工作日并通过 mysql 查询本身计算平均值,而不是稍后通过 php 操作:

SELECT `complains`.`id`,
DATE (edate) AS _date,
AVG((UNIX_TIMESTAMP(closeDate) - UNIX_TIMESTAMP(edate))) AS _seconds,
COUNT(*) AS totalCases
FROM `complains`
WHERE (
    (`complains`.`govt_id` = '22')
    AND (
        `complains`.`edate` BETWEEN DATE ('2016-01-01')
            AND DATE ('2017-01-01')
        )
    )
AND (`complains`.`status` = 2)
GROUP BY `_date`
ORDER BY `_date`

因此必须在不同字段之间排除工作日,即 closeDateedate,其中 edate 是案例的入口日期。我基本上是在计算案件的平均解决时间。

SQL 小提琴 link to sql fiddle

【问题讨论】:

见meta.***.com/questions/333952/… 顺便说一句,2017-01-01 一个日期,所以不需要用函数包装它 @Strawberry 这是 SQL 小提琴:sqlfiddle.com/#!9/b223b2/1 我需要在删除非工作日后创建平均值。假设非工作日是 1 和 7(即分别为星期日和星期六)。 我看不到想要的结果。 所以对于您在小提琴中的示例架构和数据,我可以看到实际结果,但您能否给出您对相同示例架构和数据的期望结果:) 【参考方案1】:

你可以通过聚合函数实现你想要的,特别是count

SELECT count(*) AS dayscount
FROM table
WHERE (date BETWEEN d1 AND d2) AND DAYOFWEEK(date)=daynum

请注意,函数是在 select 语句中使用的东西,例如上面的 DAYOFWEEK 函数,它们并不是要替换 select 语句,反之亦然,这是因为函数不需要任何表,在上面的选择语句我不得不输入FROM table,但在你的函数中没有特定的表。

我同意,当我们想要将某些列转换为某些内容时(例如将字符串列解析为整数或获取两个日期之间的差异),最好不要使用您想要的函数并定义它们等等)。

顺便说一句,count 是一个函数,特别是一个聚合函数,就像 AVG,SUM,MAX 等,你的函数只是一个有条件的计数。

编辑

关于您的更新,简短的回答是:如果不声明函数,您将无法做到这一点。

select 替换函数意味着数据存在于某个表中,如果我想从 edate 到 closeate 排除工作日,那么必须存储这些工作日,但它们在哪里?在什么表?为此,必须有一个功能。

但你的函数不必做所有事情,查询可以这样写:

SELECT id,
DATE (edate) AS _date,
AVG((NONWORKDAYSCOUNT(edate,closedate,workdaysnum))) AS _seconds,
COUNT(*) AS totalCases
FROM complains
WHERE (
    (govt_id = '22')
    AND (
        edate BETWEEN DATE ('2016-01-01')
            AND DATE ('2017-01-01')
        )
    )
AND (status = 2)
GROUP BY _date
ORDER BY _date

我将把 NONWORKDAYSCOUNT 留给你,它与你拥有的 DayCount 几乎相同,但你需要将 daynum 传递为“类数组”类型(mysql 没有数组),你可以看到 this问题,特别是 FIND_IN_SET 是您需要的功能,DayCount 还包括 daynum 中过去的天数,不排除它们(这取决于您是否将 daynum 解释为工作日或非工作日),它还需要将其结果转换为秒。

顺便说一句,您提到要在 mysql 而不是 php 中执行此操作以提高性能,虽然您的情况是正确的,但通常我们不希望将 CPU 负载放在我们的数据库上,您确实应该在判断之前进行测量的表现。

P.S:除非您想为表指定不同的名称或加入两个(或更多)具有共享列的表,否则您无需在每次提及列时都提及表名。

您也不需要将列名包含在“``”中

【讨论】:

我有这个查询:pastebin.com/kG2uAY58 我需要从 _seconds 中减去这些工作日。你认为上面可以用我的查询来实现吗。我认为仍然需要while循环。情况很复杂。 & 日期在两个不同的字段之间,closeDate 和 edate。 @Strawberry 抱歉,打错了:) @niceman 抱歉对我的问题有任何误解,我现在已经发布了 sqlfiddle。 @niceman 我已添加我的评论,请查看。我不确定你是否收到了通知,这就是为什么在这里发帖。 @ManuSharma 我更新了我的答案,抱歉,当我应该输入 &lt;&gt; 时,我错误地输入了 DAYOFWEEK(_date)=dayname,即“不相等”(!= 也可以完成这项工作)

以上是关于如何通过 select 语句直接创建复杂查询而不是创建函数的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Java 中的 Oracle SQL 选择中获取原始脚本输出而不是查询结果

SQL 查询分析器界面上如何修改数据

MySQL的视图

第五章 复杂查询 5-2 子查询

sql常用语句

sqlserver 存储过程 保存在哪张表里如何通过select语句查询哪些存储过程是包含某个关键词