从sql中输入的日期中查找最近的日期,两种方式都是

8aqjt8rx  于 2021-06-15  发布在  Mysql
关注(0)|答案(3)|浏览(988)

我有一个问题,我有一个任务,找到一个最近的日期到一个给定的日期,寻找双方的方式,老或年轻。但我不知道,我是新来的sql,试图谷歌,但没有找到任何帮助。

create proc Task
(@Date date)
as
begin

    select top(1) p.FirstName, p.LastName, e.BirthDate, e.JobTitle  from HumanResources.Employee e
    join Person.Person p
    on p.BusinessEntityID = e.BusinessEntityID
     where e.BirthDate>@Date

end

我开始做这种事,然后就失去了

nzkunb0c

nzkunb0c1#

使用 datediff() 获取两个日期之间的持续时间。因为你不在乎日期是在未来还是过去,所以使用 abs() 得到持续时间的绝对值。然后按绝对持续时间排序,取前一条记录。
我不确定你是否真的在mysql上或者sql server上。这个 TOP (1) 表示sql server,标记为mysql。
以下是mysql版本:

SELECT p.firstname,
       p.lastname,
       e.birthdate,
       e.jobtitle
       FROM humanresources.employee e
            INNER JOIN person.person p
                       ON p.businessentityid = e.businessentityid
       ORDER BY abs(datediff(e.birthdate, @date))
       LIMIT 1;

对于sql server:

SELECT TOP (1)
       p.firstname,
       p.lastname,
       e.birthdate,
       e.jobtitle
       FROM humanresources.employee e
            INNER JOIN person.person p
                       ON p.businessentityid = e.businessentityid
       ORDER BY abs(datediff(day, e.birthdate, @date));

可能需要根据实际使用的数据类型进行一些调整。
编辑:
解决fifoniks的问题的一个版本,如果相应的索引存在(在 humanresources.employee.birthdate 最佳一次上升,一次下降)。
它首先得到未来的最接近记录的并集 @date (包括 @date )以及过去的模拟记录,希望在这一过程中使用索引。从这两个记录中,绝对持续时间最短的一个 @date 被选中。那么 person 加入。

SELECT p.firstname,
       p.lastname,
       y.bithdate,
       y.jobtitle
       FROM (SELECT TOP (1)
                    x.businessentityid,
                    x.birthdate,
                    x.jobtitle
                    FROM (SELECT TOP (1)
                                 e.businessentityid,
                                 e.birthdate,
                                 e.jobtitle
                                 FROM humanresources.employee e
                                 WHERE e.birthdate >= @date
                                 ORDER BY e.birthdate ASC
                          UNION ALL
                          SELECT TOP (1)
                                 e.businessentityid,
                                 e.birthdate,
                                 e.jobtitle
                                 FROM humanresources.employee e
                                 WHERE e.birthdate <= @date
                                 ORDER BY e.birthdate DESC) x
                    ORDER BY abs(datediff(day, x.birthdate, @date)) ASC) y
            INNER JOIN person.person p
                       ON p.businessentityid = y.businessentityid;
vcudknz3

vcudknz32#

永远记住:没有订单的top没有多大意义;添加升序(您的 birthdate > @date 比较要求所有出生日期大于/之后,因此按出生日期升序排列的顶部(1)将是大于变量的最早出生日期)
然后获取整个查询,再次粘贴它,将union all放在它们之间,并在第二个查询中按降序和小于的比较顺序翻转
因此,最终的查询将选择大于的最小值和小于的最大值,即距离变量最近的值
如果某个日期符合规范,请考虑是否应该使用>=和<=

z9zf31ra

z9zf31ra3#

我不会按顺序使用函数(因为服务器将无法使用索引)。相反,我会选择两个问题的解决方案。它可以 Package 在sp中,类似这样(mysql版本):

CREATE FUNCTION `Task`(
    `aDate` DATE
)
RETURNS INT
BEGIN
    SELECT
          `BusinessEntityID`
        , `BirthDate`
    INTO
          @id_next
        , @birthdate_next
    FROM
        `Employee`
    WHERE
        `BirthDate` >= aDdate
    ORDER BY
        `BirthDate` ASC
    LIMIT
        1
    ;

    IF @birthdate_next IS NULL THEN
        SELECT
              `BusinessEntityID`
            , `BirthDate`
        INTO
            @id_prev
          , @birthdate_prev
        FROM
            `Employee`
        WHERE
            `BirthDate` < aDate
        ORDER BY
            `BirthDate` DESC
        LIMIT
            1
        ;
    ELSE
        IF DATEDIFF(@birthdate_next, aDate) > 1 THEN
            SELECT
                  `BusinessEntityID`
                , `BirthDate`
            INTO
                @id_prev
              , @birthdate_prev
            FROM
                `Employee`
            WHERE
                    `BirthDate` < aDate
                AND `BirthDate` > DATE_SUB(aDate, INTERVAL DATEDIFF(@birthdate_next, aDate) DAY)
            ORDER BY
                `BirthDate` DESC
            LIMIT
                1
            ;
        END IF;
    END IF;

    CASE
        WHEN @id_prev IS NULL AND @id_next IS NULL THEN RETURN NULL;
        WHEN @id_prev IS NULL THEN RETURN @id_next;
        WHEN @id_next IS NULL THEN RETURN @id_prev;
        WHEN DATEDIFF(@birthdate_next, aDate) < DATEDIFF(aDate, @birthdate_prev) THEN RETURN @id_next;
        ELSE RETURN @id_prev;
    END CASE;

END

所以在某些情况下,只执行一个查询(第一个)。查询将按出生日期使用索引。如果第一个查询与指定日期的差异小于2天,则第二个查询将根本不执行(它比ordered desc更复杂)。可以进一步简化sp,但是我保持它的“原样”,这样更容易理解。

相关问题