我想要做的是一个跟踪个人记录的数据库。 模型差不多完成了,但是我面临着存储不同类型记录的困难。
有时间,重量,重复/圈数,距离的记录......所以,有不同类型的数据:时间,小数,整数......
首先,我为每种类型的数据创建了一个表(或django中的类)。一张时间表,另一张是重量(十进制)等等。
但我很想知道是否有更好的解决方案只能为所有记录保留一个表。
我的分离表/模型的代码(所以,我有一个类,每个类型,总共5个模型):(这很好用,但我必须预先选择适当的模型来插入数据。)
class PRWeight(model.Models): # there are PRDistance, PRLaps, PRHeight, PRTime
user = FK(User)
exercise = FK(Exercise)
date = datefield()
weight = decimalfield() # integer, integer, decimal, time
class Meta:
unique_together = [user, exercise, date,]
或者我可以做这样的事情,如果它是好的或有更好的解决方案:
class PR(models.Model):
user = FK(User)
exercise = FK(Exercise)
date = datefield()
metric = FK(Metric) # choose between time, weight, height...
# the aspect beeing mesured
record = # how can I call the right field type?
或者我可以使用blank = True
重新显示其他五个字段的字段“record”class PR(models.Model):
user = FK(User)
exercise = FK(Exercise)
date = datefield()
metric = FK(Metric) # choose between time, weight, height, distance...
# the aspect beeing mesured
# not necessary in this approach
wheight = decimalfield(blank=True)
height = decimalfield(blank=True)
time = timefield(blank=True)
distance = integerfield(blank=True)
laps = integerfield(blank=True)
我正在寻找一个简单的解决方案。到目前为止,我很容易选择最后一个例子,因为它是直截了当的,但填写表格的用户可能会犯错...
答案 0 :(得分:1)
表包含使某些语句(由列名参数化)为true的行。只要您可以使用它们创建单个语句,表应该只有列。
将许多但相关的列放在一起
如果(用户,锻炼,日期)总是有体重和日期,则只需一张桌子。
-- user [user] in exercise [exercise] on [date] weighed [weight] kg and was [height] m tall
PRstuff(user,exercise,date,weight,height)
但是如果(用户,练习,日期)可能有权重而不是日期,则有单独的表格。
-- user [user] in exercise [exercise] on [date] lifted [weight] kg
PRlift(user,exercise,date,weight)
-- User [user] in exercise [exercise] on [date] jumped [height] m
PRjump(user,exercise,date,height)
条件列很复杂
可以像第三个例子一样使用语句/表格:
-- user [user] did [exercise] on [date]
-- AND ( lifted != blank and they lifted [weight] kg OR lifted = blank and they didn't lift )
-- AND ( jumped != blank and they jumped [height] m OR jumped = blank and they didn't jump )
PR(user,exercise,date,weight,height)
但是正如您所看到的,查询语句(表语句的组合)和SQL表达式(表的组合)变得复杂。基本上,在查询时,您必须不断将此表格切换为单独的非条件表格版本。
请勿使用记录类型列
有时候我们可以有一个类型由固定部分组成的列。但是,如果您想使用SQL中的逻辑条件查询部件,那么您应该将部件分成表格的列。
-- user [user] in exercise [exercise] on [date] weighed [record.weight] kg and was [record.height] m tall
PRrecord(user,exercise,date,record)
SELECT * FROM PRrecord
WHERE PRrecord.record.weight = 100 -- really, record_dot(PRrecord.record,'weight')=100
这里第一个点是数据库表操作,但第二个点是编程语言记录操作。 DBMS无法优化您的查询,因为它优化了表操作,而不是数据类型操作。基本上它必须得到一大堆不看记录值的行然后调用记录操作符点然后调用字段相等然后扔掉很多行。
SELECT * FROM PR
WHERE PR.weight = 100
现在,DBMS可以将字段相等性组合到优化获取行的方式,因为您只使用了dot的表格版本。
请勿使用容器类型列
有时我们可能会有一个类型由类似部分集合组成的列。但是如果你想使用SQL中的逻辑条件来查询部件,那么你应该创建一个新表。新表有一个特定集合的PK列,旧表有一个与新PK相对应的列。
-- user [user] in exercise [exercise] on [date] and their set of lifted weights in kg is [weights]
PRlifts(user,exercise,date,weights)
SELECT user FROM PRlifts l
WHERE l.name = 'Fred' AND set_has_member(l.weights,200)
AND ??? no two lifts were the same weight ???
坏。注意声明是如何复杂的。此外,DBMS无法优化查询,因为set_has_member不是表操作。更糟糕的是,你甚至无法查询某些条件,你必须编写非查询循环代码。
SELECT user FROM PRlift l
WHERE l.user = 'Fred' AND l.weight = 200
AND NOT EXISTS(
SELECT weight
FROM Prlift l1, PRlift l2
WHERE l1.user = l.user AND l2.user = l.user AND l1.weight = l2.weight
)
现在,DBMS可以优化并避免循环。
(请注意,如果这是
WHERE string_length(l1.name) = string_length(l2.name)
然后DBMS可以通过使用名称长度列进一步优化。但通常DBMS具有字符串和某些其他类型的特殊知识,并且或多或少地优化,就好像存在与某些运算符的值相对应的某些列。事实上,DBMS可以了解记录和集合类型,但您仍然无法循环使用简单的语句和查询。)