我想问一些有关如何检索具有特定年龄组的预订的SQL Query的帮助。基本上,我想检索有成人和儿童顾客的预订,这些只有出生日期才能确定。儿童被视为15岁以下,成年人超过15岁。我想检索有孩子和成人不超过20岁的预订。如果预订中有一位年龄超过20岁的客户,则不应检索预订。预订应该有超过1个客户。这是一个供您参考的样本表 -
Booking No 123
Customer 1 - March 1, 2008
Customer 2 - Aug 3, 1998
Booking No 456
Customer 1 - March 2, 1986
Customer 2 - Feb 9, 2007
Customer 3 - Apr 10, 1999
Booking No 789
Customer 1 - Jun 7, 1999
需要检索的预订仅为预订号123.表中未提供年龄,仅使用出生日期计算 - DateDiff。
BookingID CustomerID LName FName DOB
ReservationID BookingID CompanyID ArrivalDate CompanyName
这是我放置的where语句
(SELECT DATEDIFF(YEAR,bp.DOB,GETDATE()))< = 20 AND(SELECT DATEDIFF(YEAR,bp.DOB,GETDATE()))< 15
但仍然拉着包含顾客的预订> 20岁。
答案 0 :(得分:0)
好的,现在我们可以看到发生了什么(以及出了什么问题)。
您当前的查询包含:
WHERE (SELECT DATEDIFF(YEAR ,bp.DOB,GETDATE()) <= 20
AND (SELECT DATEDIFF(YEAR ,bp.DOB,GETDATE())) < 15
......这可以翻译为:
WHERE (the number of times January 1st is passed) <= 20
AND AT THE SAME TIME (the number of times January 1st is passed) < 15
除了AND
s是独占的这一事实 - 行必须匹配两个条件 - 正在发生的事情是DATEDIFF
计算跨越的“边界”数量给定的措施:
返回指定的startdate和enddate之间交叉的指定日期部分边界的计数(有符号整数)。
......当然,一年的边界是1月1日。
<小时/> 首先,对数据库范围搜索的偏离。你这样做,
WHERE DATEDIFF(YEAR ,bp.DOB,GETDATE() <= 20
,你通常会使数据库忽略索引,这是加速查询的方法;这是因为它必须计算表中每个行的值(这里是年份的差异)(因为否则它不知道计算的值是否匹配)。
WHERE DOB <= DATEADD(year, -21, GETDATE())
(这相当于那些“如果你出生在XXXX年的这个日期或之前,你是21岁”,你在杂货店看到的标志)
不,那不在意,我们需要弄清楚我们真正需要什么。重述上述条件,我们正在寻找(全部)预订:
现在......据推测,我们并不关心年龄小于20岁的多个(或单个)客户,只要他们的年龄都超过15岁,所以我们应该修改第一个条件。此外,很可能我们需要警告,如果预订中只有15岁或15岁以下的顾客 - 他们甚至没有“几乎”成年人!而且很可能我们需要警告这个人是否也将独自一人!因此条件应改为:
(如果重述不正确,请告诉我)
现在我们没有条件,我们可以写下我们的陈述。我们正在寻找预订:
SELECT ReservationID, BookingID, CompanyID, ArrivalDate, CompanyName
FROM Booking
如果至少有一位年龄小于15岁的客户:
WHERE EXISTS (SELECT 1
FROM BookingCustomer
WHERE BookingCustomer.bookingId = Booking.BookingId
-- birthday after 15 years ago today
AND BookingCustomer.dob > DATEADD(year, -15, GETDATE()))
并且没有21岁或以上的客户:
AND NOT EXISTS (SELECT 1
FROM BookingCustomer
WHERE BookingCustomer.bookingId = Booking.BookingId
-- birthday before or on 21 years ago today
AND BookingCustomer.dob <= DATEADD(year, -21, GETDATE()))
旁注:大部分时间用于预订旅游和其他东西,他们只关心旅行时,不预订时间的年龄 “今天”碰巧就是你跑步的时候。您可能不希望GETDATE()
,而是其他内容,可能是ArrivalDate
。由于你要在一个专栏上进行数学运算,它会再次强制进行一次表格扫描,但保持年龄检查 - 并稍微修改一下以考虑预订可以提前多久 - 会“更早”淘汰预订,因为有人肯定够老了(或者没有人足够年轻)。
答案 1 :(得分:0)
感谢您的详细回复。我尝试了建议的查询,并且没有退回任何预订
在哪里存在(选择1 来自BookingCustomer 在哪里BookingCustomer.bookingId = Booking.BookingId - 15年前的生日今天 或BookingCustomer.dob&gt; DATEADD(年,-15,BOOKING.ARRIVALDATE))
AND NOT EXISTS(选择1 来自BookingCustomer 在哪里BookingCustomer.bookingId = Booking.BookingId - 21年前或之前的生日今天 AND BookingCustomer.dob&lt; = DATEADD(年,-21,BOOKING.ARRIVALDATE))
答案 2 :(得分:0)
这应该可以帮您预订。日期计算应基于预订到达日期,如果考虑较旧或未来的预订,getdate()将改变到达时的计算年龄。
我正在通过预订分组的预订和预订表之间直接加入,并确定每位乘客的年龄。
SELECT
R.BookingID
FROM
BookingCustomer BC
JOIN Reservation R
ON BC.BookingID = R.BookingID
group by
R.BookingID
having
SUM( case when DATEDIFF(YEAR , BC.DOB, R.ArrivalDate ) < 16 then 1 else 0 end ) > 0
AND SUM( case when DATEDIFF(YEAR , BC.DOB, R.ArrivalDate ) >= 16
and DATEDIFF(YEAR , BC.DOB, R.ArrivalDate ) < 21 then 1 else 0 end ) > 0
AND SUM( case when DATEDIFF(YEAR , BC.DOB, R.ArrivalDate ) > 20 then 1 else 0 end ) = 0
现在,既然预订都指向相同的预订,您可以同时抓住所有其他字段
SELECT
R.BookingID,
R.ReservationID,
R.CompanyID,
R.ArrivalDate,
R.CompanyName ... rest of query.
如果查询唠叨非聚合字段,您可以将其他字段作为MAX()包装不属于该组,因为预订始终指向相同的预订,并且父预订详细信息无论如何都不会改变
SELECT
R.BookingID,
MAX( R.ReservationID ) ReservationID,
MAX( R.CompanyID ) CompanyID,
MAX( R.ArrivalDate ) ArrivalDate,
MAX( R.CompanyName ) CompanyName ... rest of query.