【问题标题】:Database scheme for searching my age groups用于搜索我的年龄组的数据库方案
【发布时间】:2011-12-09 05:18:08
【问题描述】:

我已经为此苦苦挣扎了一段时间,现在试图弄清楚如何最有效地做到这一点。

问题如下。我在数据库中有要针对特定​​年龄组销售的商品,例如 ages 10 to 20ages 16+,我需要能够进行查询,例如 find item that is for 17 year old

这是我最好的两个想法(但我都不喜欢,因为我认为它们都效率低下)。

  1. 有一个 csv 列,其中包含 10-2016+ 之类的值,检索整个列表并对其进行解析(坏主意,我知道,不过我在这里没有想法)

  2. 有一个 csv 列,其值如 10,11,12,13...20 用于范围,所以我可以使用 WHERE ages LIKE "%17%" 查找它,对于像 16+ 这样的情况,我必须使用类似 @ 的东西来检索这些特殊情况987654329@ 并通过这些解析。

我当然倾向于第二种选择,但在最好的情况下,我会运行两个查询,一个用于常规项目,另一个用于16+

有没有更好的方法?如果没有,你认为你可以让我的任何一个模型更有效率吗?谢谢。

【问题讨论】:

  • 哪个数据库?并且请从您的词汇表中删除“csv 列”,这种事情几乎从来都不是一个好主意。
  • 我意识到这一点,但就像我说的那样,我在这里没有想法。谢谢你的帮助:D
  • 我希望您将 DOB 存储在数据库中,而不是年龄(也许年龄作为计算列)?
  • @Damien:我认为目标年龄是一个变量,该表包含固定年龄范围

标签: sql database database-design database-schema


【解决方案1】:

你可以这样做:

  1. lower_ageupper_age 列添加到您的表中,这两个整数都允许NULL。
  2. 如果lower_age 为NULL,则没有下限。
  3. 如果 upper_age 为 NULL,则没有上限。
  4. 结合 COALESCE 和 BETWEEN 进行查询。

为了澄清(4),你想说这样的话:

select *
from your_table
where $n between coalesce(lower_age, $n) and coalesce(upper_age, $n)

$n 是您要查找的年龄。 BETWEEN 使用包含边界,因此如果 lower_age 不为 NULL,coalesce(lower_age, $n) 将忽略 $n,如果 lower_age 为 NULL,则为您提供 $n >= $n(即在该边界上自动为真); upper_age 也是如此。

如果某样东西只适合 11 岁的孩子,那么你的 [lower_age,upper_age] 闭合区间将是 [11, 11],16+ 将是 [16, NULL],6 岁及以下将是 [NULL, 6],每个人都是 [NULL, NULL],并且没有人会是 [23, 11] 或任何其他带有 lower_age > upper_age 的东西(或者,更有可能是 CHECK 约束会抛出嘶嘶声的无效数据)。

【讨论】:

  • 美丽的解决方案@muistooshort ,简单明了。也感谢完整的描述,它有很大帮助:D。我太喜欢了!!
【解决方案2】:

您可以通过多种方式做到这一点。如果您将用户的年龄(无论如何)存储在行中。然后你可以查询年龄和 > 16 或

1 = 10
2 = 16+
4 = 10-20
8 = 20-30
16 = 20+
32 = 30+
.
.
.
.

然后在存储人员信息的表中,您可以将列设置为 int 或 bigint 以获取您的偏好,然后对于他们所属的任何组,您可以通过数字来确定这一点,例如:

Table of Users
ID     Name        BitWise
 1     test          2
 2     something     6 (2+4)
 3     blah          24 (8+16)

但是我认为按位计算可能有点矫枉过正,您最好将年龄存储为一个数字并针对该数字运行查询。这很可能是最有效的。

【讨论】:

  • 使用您的解决方案,如果我要搜索适合 22 岁的东西,我必须检索整个表,并解析每个选项,因为例如 22 将低于 16 +, 20-30, 20+。至少这是我得到的,我错了吗?谢谢你的帮助。
  • 如果您的 rdbms 支持位图索引,您就不必检索整个表。您将在内存中拥有位图索引并对其使用按位运算。仍然是各种全表扫描,但没有硬盘损失。
  • @vvMINOvv wellenborn 表示如果您的表已编入索引并且您的 RDBMS 支持索引,那么您实际上会缓存此内容,因此不会命中硬盘。但是,只有当您需要知道该人属于多个类别时,您才会使用它。如果它总是只有一个类别,那么我会坚持将年龄存储在行中并对其进行查询。
  • 感谢您的帮助@CBRRacer,我肯定会使用该解决方案,但用于其他目的。出于我的意图和目的,这可能有点矫枉过正。再次感谢:D
【解决方案3】:

您有多种选择(不是双关语)。对于年龄推荐,最简单的方法是存储 min_age 和 max_age 并像这样查询:

select * from item where :age between min_age and max_age

您必须决定是否允许这些列使用空值(然后您需要使用 coalesce() 或 nvl() 或数据库提供的用于处理空值比较的任何函数),或者为这些列设置边界值你可以肯定:年龄总是介于两者之间。

或者,您可以使用 m:n 表

create table item_ages (item_id int not null, age int not null, constraint item_ages_pk primary key (item_id, age)

并用显式值填充它:

item_id | age
-------------
      1 | 16
      1 | 17
      1 | 18

等等。这比使用范围更麻烦,但也更灵活,而且由于您的数据库可以索引表并可能将该索引存储在内存中,因此查询应该很快。只有在输入新项目或特定项目的年龄范围发生变化时,您才需要触摸此表。

请注意,CBRRacer 的答案具有相似的属性:两者都认为您准备了一个易于索引的数据结构,并从该索引中回答过滤问题。这是一种在电子商务应用程序中存储营销数据的流行方法。该范围的极端情况是为此目的使用专用的包来存储倒排索引。但是对于一个简单的年龄建议来说,这当然是矫枉过正了。

【讨论】:

  • 感谢@wallenborn 我也会研究您的解决方案。干杯。
  • 我似乎无法停止学习! @wallenborn 感谢您对推理的解释,这非常有帮助。我觉得我将在这个项目的另一个表中使用这个 m:n 概念。非常感谢您的所有帮助:D
  • @vvMINOvv:如果你想停止学习,你就来错地方了 :)
【解决方案4】:

有点像这样:

选择 * FROM 表名 在 start_age 和 end_age 之间的 17 处

【讨论】:

  • 您将如何处理“16 岁以上”或“5 岁以下”的情况?
猜你喜欢
  • 2015-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-16
  • 1970-01-01
  • 2012-12-05
  • 2021-12-07
相关资源
最近更新 更多