查询字符串或序列化数组中的数据

时间:2011-09-13 14:41:53

标签: mysql serialization

我需要从包含如下所示字符串的列进行查询: 语言1,语言2,语言3

我无法为每种语言创建新列,因为它们是未定义的数量。

所以我想知道从该字符串中查询数据的最佳性能/优雅方式是什么?

我应该使用序列化数据吗?检索匹配的所有行的查询会说“Language2”?

修改 此表包含用于从我的站点搜索用户的条件索引。语言是标准之一,因此将是城市,国家和其他一些标准。问题是每个用户都可以使用不确定数量的语言。

第二次修改 以下是我现在的表格视图:my table as it is right now

4 个答案:

答案 0 :(得分:3)

我正在为查询序列化数组中的数据寻找相同方案的解决方案,并发现使用SUBSTRING_INDEX()函数完成了这项工作。以下示例:

| language             |
------------------------
| a:1:{i:1;s:3:"183";} |

得到数字' 183' (没有引号)查询将是:

SELECT TRIM(BOTH '"' FROM SUBSTRING_INDEX(SUBSTRING_INDEX(language,';',2),':',-1)) AS language_id
FROM language_table;

它应该在没有引号的情况下给你以下结果:

| language_id          |
------------------------
| 183                  |

答案 1 :(得分:2)

不,您应该规范化表架构。是的,您甚至可以处理未定义数量的值。

创建一个单独的表来保存关系引用。

<强> table_languages

ref_id | language

示例数据将是:

user_id | language
-------------------
   1   | Language 1
   1   | Language 2
   1   | Language 3
   2   | Language 2

示例查询将是:

    SELECT *
      FROM users u
INNER JOIN languages l
        ON u.user_id = l.user_id
       AND l.language = 'language2'
     WHERE u.country = 'abc'
       AND u.city = 'def';

答案 2 :(得分:2)

虽然Shef和ajreal是正确的,但从设计的角度来看,为了规范化表格,回答实际问题,你可以使用LIKE

SELECT * FROM personnel WHERE languages LIKE '%English%';

但是,如果语言是自由文本,您可能会遇到问题,因为有人可能已输入“英语”或其他大写字母,因此您需要:

SELECT * FROM personnel WHERE UPPER(languages) LIKE '%ENGLISH%';

但作为一般规则,如果您的有效值是其他有效值的子字符串,则这些会变得混乱。要解决这个问题,您必须在每个序列化字符串的开头和结尾使用分隔符序列化值:

;value3;value4;value12;

这允许您搜索

LIKE '%;value1;%'

没有匹配value11value12

有时,您实际上想要子字符串匹配行为,例如,如果有人回答British English,您可能希望English匹配。 (但是,如果他们输入British,你就是SOL)......但如果你遇到这些问题,你可能想要定义一个层次结构或使用编码,因为你不能依赖于子串工作

答案 3 :(得分:1)

不要这样做。
标准化的一个例子

create table language
(
  id smallint(10) unsigned not null default 0,
  name varchar(255) not null,
  primary key(id),
  key (name)
);

-- assuming your table is named as data
create table data
(
  id int(10) not null default 0,
  -- plus any of your existing column definition
  key(id)
);

-- build a relation table to tied knot between language and data
create table data_language
(
  data_id int(10) not null not null default 0,
  language_id smallint(10) unsigned not null default 0,
  key (data_id, language_id)
);

-- when select
select data.id, language.id, language.name
from data
inner join (data_language, language)
on data.id=data_language.data_id and language.id=data_language.language_id
where language.name='English'