如何通过 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 的方法,以便能够传递非工作日,并从主查询中删除这些日子以计算分辨率和响应时间,但根本没有任何功能,直接选择语句这样做的方法。
更新:
我在下面有一个查询,我正在计算 closeDate 和 edate 之间的时间,我需要排除非工作日,非工作日列表是动态的,它可能是从 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`
因此必须在不同字段之间排除工作日,即 closeDate 和 edate,其中 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 我更新了我的答案,抱歉,当我应该输入<>
时,我错误地输入了 DAYOFWEEK(_date)=dayname
,即“不相等”(!=
也可以完成这项工作)以上是关于如何通过 select 语句直接创建复杂查询而不是创建函数的主要内容,如果未能解决你的问题,请参考以下文章