在MySQL中使用间隔在数据库日期中添加月份

问题描述

我想通过连接计划表和交易表使用MysqL interval函数在交易日期中添加月份,但是此方法不起作用,但是如果我以静态方式在交易日期中添加月份,则该方法有效。

const deferredRec = step => { while (step && step.tag === "Call") step = step.f(...step.args); return step; }; const Call = f => (...args) => ({tag: "Call",f,args}); const record = (type,o) => (o[type.name || type] = type.name || type,o); const thisify = f => f({}); const arrFold = f => init => xs => { let acc = init; for (let i = 0; i < xs.length; i++) acc = f(acc) (xs[i],i); return acc; }; const Task = task => record( Task,thisify(o => { o.task = (res,rej) => task(x => { o.task = k => k(x); return res(x); },rej); return o; })); const taskMap = f => tx => Task((res,rej) => Call(f => tx.task(f)) (x => Call(res) (f(x)),rej)); const taskOf = x => Task((res,rej) => res(x)); const taskAnd = tx => ty => Task((res,rej) => tx.task(x => ty.task(y => res([x,y]),rej),rej)); const taskAll = arrFold(tx => ty => taskMap(([xs,x]) => xs.concat([x])) (taskAnd(tx) (ty))) (taskOf([])); const inc = x => Task((res,rej) => setTimeout(x => deferredRec(res(x + 1)),x)); // A const xs = Array(1e4).fill(inc(0)); const main = taskAll(xs); deferredRec(main.task(console.log,console.error));表:

plan

plan_id plan 1 6 month 2 12 month 3 3 month 表:

transaction

MySQL查询(不起作用):

id  user_id  subscribed_on   plan_id    
1     2       2020-04-04     1    
2     4       2019-02-22     2 

如果我以静态方式添加月份,则工作正常:

SELECT t.* FROM transaction t inner join plan p on p.plan_id=t.plan_id 
where t.user_id=2 and DATE_ADD(date(t.subscribed_on),INTERVAL p.plan) >= CURDATE() 
order by t.id desc

解决方法

不幸的是,数据中的字符串不等于间隔。一种方法是:

date(t.subscribed_on) + interval substring_index(plan,' ') + 0 month

请注意,month是关键字,而不是字符串。

,

MySQL不支持那样使用间隔。与其他数据库(例如Postgres)不同,unit参数是关键字,而不是文字字符串。

我怀疑您的表可能会存储其他间隔,而不仅仅是几个月(例如,几年,几天等等)。如果是这样,您可以使用字符串函数和case表达式来容纳不同的可能值,例如:

select t.* 
from transaction t 
inner join plan p on p.plan_id = t.plan_id 
where 
    t.user_id = 2 
    and date(t.subscribed_on) + case substring_index(p.plan,' ',-1)
        when 'year'  then interval substring_index(p.plan,1) year
        when 'month' then interval substring_index(p.plan,1) month
        when 'day'   then interval substring_index(p.plan,1) day
    end
    >= current_date
order by t.id desc

这里的逻辑是将存储的间隔字符串分为两部分:数字和单位; case表达式处理单位并相应地生成正确的文字间隔。

,

尝试将plan表中的plan列强制为整数。似乎无法将字符串强制转换为间隔。

我尝试过这样:

WITH
plan( plan_id,plan) AS (
          SELECT 1,'6 month'
UNION ALL SELECT 2,'12 month'    
UNION ALL SELECT 3,'3 month'
),transaction(id,user_id,subscribed_on,plan_id) AS (
          SELECT 1,2,DATE '2020-09-04',1    
UNION ALL SELECT 2,4,DATE '2019-02-22',2 
)
SELECT t.*
FROM transaction t
INNER JOIN plan p ON p.plan_id = t.plan_id
WHERE t.user_id = 2
  AND DATE_ADD(
        DATE(t.subscribed_on),INTERVAL CAST(REPLACE(plan,' month','') AS SIGNED) MONTH
    ) >= CURDATE()
ORDER BY t.id DESC

(不返回任何结果,因为您的示例数据中没有足够高的日期...)