我有一个包含这些数据的MySQL表:
TempID TempName TempString
1 aaa 34:56:23:45:67:55
2 bbb 12:56:67:45:33:99
我想执行一项计算,该计算需要将TempString
拆分为单独的值,例如34,56,23 ....,
哪种方式最好:
用于存储TempID
ValID TempID Value
1 1 34
2 1 56
3 1 23
4 1 45
5 1 67
6 1 55
7 2 12
8 2 56
9 2 67
查询以获取每个TempID的值并进行计算
请建议最佳方法。
答案 0 :(得分:1)
嗯,最重要的问题是,打破这些值在语义上是否正确?
在设计数据库表时,有必要考虑每列的域定义。存储在一列内的每个数据项都应该是原子的(不可分解的)。这意味着存储在列中的项是为特定列定义的域的元素。这可以称为域完整性约束(有关详细信息,请查看data integrity上的维基百科文章)。
您可以使用简单的启发式方法作为最终决定的帮助:您是否曾经或者您是否需要使用存储的字符串的一部分进行搜索,即在where
子句内部。如果是,请将字符串分解为单独的表列,否则只需使用Python解析它。
打破域名完整性的一个简单示例是拥有一个用于存储博客帖子的表格,其中单个帖子的所有标签都连接成一个大字符串并仅存储到一行中,而不是具有连接帖子的单独表格标签
可以将相对复杂的值存储到一列中的一个明显示例是存储日期。即使它由多个值组成,如果没有关于年,月,日的所有信息,完整日期也不完整(原子)......
答案 1 :(得分:0)
让我们先评估你的两个选择。
选项1:
您应该将temp id作为字符串检索,并使用冒号作为分隔符将其拆分。分割函数的语法是
str.split(str="", num=string.count(str)).
默认分隔符是空格。这种方法的问题是你应该在你的python脚本中创建一个映射,它将每个tempid指向检索到的所有可能的值。这种方法的优点是你可以避免像temp id这样的冗余数据。尽管可以使用规范化表格并更好地组织数据。
选项2:
即使不是最佳方式,这也是实现要求的简单方法。
选项3:
使用正则表达式。检查一下。
#!/usr/bin/python
import re
txt='30:24:33:55:60'
re1='(\\d)'
re2='(\\d)'
re3='.*?'
re4='(\\d)'
re5='(\\d)'
re6='.*?'
re7='(\\d)'
re8='(\\d)'
re9='.*?'
re10='(\\d)'
re11='(\\d)'
re12='.*?'
re13='(\\d)'
re14='(\\d)'
rg = re.compile(re1+re2+re3+re4+re5+re6+re7+re8+re9+re10+re11+re12+re13+re14,re.IGNORECASE|re.DOTALL)
m = rg.search(txt)
if m:
d1=m.group(1)
d2=m.group(2)
d3=m.group(3)
d4=m.group(4)
d5=m.group(5)
d6=m.group(6)
d7=m.group(7)
d8=m.group(8)
d9=m.group(9)
d10=m.group(10)
print "("+d1+")"+"("+d2+")"+"("+d3+")"+"("+d4+")"+"("+d5+")"+"("+d6+")"+"("+d7+")"+"("+d8+")"+"("+d9+")"+"("+d10+")"+"\n"
Output: (3) (0) (2) (4) (3) (3) (5) (5) (6) (0)
你可以去掉大括号并将字符串分成两位数,并在查询中使用它。优点是你不需要改变表结构。约束很难写正则表达式。这是实现你的最佳方法目标
选项4:
在mysql查询中使用REGEXP。问题是mysql正则表达式使用POSIX标准并将我上面给出的正则表达式转换为此标准,你应该做一些替换,比如// d to digit或[0-9]和* ? to ^还有一些我不知道对我感到羞耻的事情,但这种类型的执行会提高你的查询性能,尤其是当你使用索引时。
答案 2 :(得分:0)
你的第二个解决方案是最好的。规范化数据库,使用额外的表来存储这些值。
当值的数量发生变化时,多列会变得很困难(如果需要,还会阻止您轻松使用聚合函数)。
检索脚本的所有值,他们可以将它们拆分,但是再次阻止你使用数据库的强大功能(并且可能会强制你返回比所需更多的行,因为你在执行计算之前返回它们)可能很好地定义你是否需要返回它们。)
数据库中的分隔列表很痛苦。但是,您可以将其拆分为插入到新表中,并使用以下查询: -
SELECT NULL, sometable.TempID, SUBSTRING_INDEX(SUBSTRING_INDEX(sometable.TempString, ':', aCnt), ':'. -1)
FROM sometable
CROSS JOIN
(
SELECT 1+ units.i + tens.i * 10 AS aCnt
FROM
(SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) units,
(SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) tens
) sub0
WHERE aCnt <= (LENGTH(sometable.TempString) - LENGTH(REPLACE(sometable.TempString,':', '' )))
这将处理多达100个值,但很容易扩展。