我有问题,我有一项任务是查找距给定日期最近的日期,无论年龄大小,年龄均较小。但是我不知道,我是SQL的新手,尝试使用Google搜索,但没有找到任何帮助。
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
我开始这样的事情,然后丢了
答案 0 :(得分:0)
永远记住:没有ORDER BY by的TOP没有多大意义;添加一个按升序排列的顺序(您的birthdate > @date
比较要求所有大于或大于后的生日,因此按生日升序排列的TOP(1)将是大于变量的最早生日)
然后使用整个查询,将其再次粘贴,将UNION ALL放在它们之间,然后在第二个查询中将ORDER BY降为下,而您的比较小于。
因此,您最终得到一个查询,该查询选择大于该值的最小值和小于该值的最大值,即与变量最接近的值
考虑是否应该使用> =和<=(如果符合要求的日期符合规范)
答案 1 :(得分:0)
使用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;
答案 2 :(得分:0)
我不会按顺序使用函数(因为服务器将无法使用索引)。 相反,我将寻求两个查询的解决方案。 可以将它包装在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
因此,在某些情况下,将仅执行单个查询(第一个查询)。 该查询将使用BirthDate的索引。 如果从指定日期开始的第一个查询差异小于2天,则将完全不执行第二个查询(按有序DESC比较复杂)。 可以进一步简化SP,但是我将其“按原样”保存,因此更易于理解。