检索特定年龄组

时间:2016-06-25 12:29:44

标签: mysql sql

我想问一些有关如何检索具有特定年龄组的预订的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岁。

3 个答案:

答案 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岁的客户
  • 没有超过20岁的客户
  • 至少有两位顾客。

现在......据推测,我们并不关心年龄小于20岁的多个(或单个)客户,只要他们的年龄都超过15岁,所以我们应该修改第一个条件。此外,很可能我们需要警告,如果预订中只有15岁或15岁以下的顾客 - 他们甚至没有“几乎”成年人!而且很可能我们需要警告这个人是否也将独自一人!因此条件应改为:

  • 至少一名年龄小于15岁的客户
  • 没有21岁或以上的客户

(如果重述不正确,请告诉我)

现在我们没有条件,我们可以写下我们的陈述。我们正在寻找预订:

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.