如何将记录插入 MySql table 以便一个单元格具有多个值?

How can I insert records into MySql table so that one cell has multiple values?

抱歉,如果标题令人困惑,这就是我想要做的:

INSERT INTO table (fruit, type) VALUES 
('apple', '1'), 
('apple', '2'), 
('apple', '2'), 
('banana', '3'), 
('banana', '4'), 
('banana', '5'); 

所以结果 table 在 type 列中只有两行具有 pipe-separated 值,如下所示:

('apple', '1|2') 
('banana', '3|4|5')  

现在我有:

CREATE TABLE IF NOT EXISTS table ( 
id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, 
  fruit varchar(50) NOT NULL UNIQUE KEY, 
  type varchar(100) NOT NULL 
) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=latin1;  

INSERT INTO table (fruit, type) VALUES 
('apple', '1'), 
('apple', '2'), 
('apple', '2'), 
('banana', '3'), 
('banana', '4'), 
('banana', '5') 
ON KEY DUPLICATE type = VALUES(type)|type 
//I know above line is wrong and this is where I'm stuck 

我可以在 type 列中得到一系列 pipe-separated 值吗?

非常感谢

编辑:

通过这样做,我几乎到达了我想要结束的地方:

CREATE TABLE IF NOT EXISTS table ( 
id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, 
  fruit varchar(50) NOT NULL UNIQUE KEY, 
  type varchar(100) NOT NULL 
) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=latin1;  

INSERT INTO table (fruit, type) VALUES 
('apple', '1'), 
('apple', '2'), 
('apple', '2'), 
('banana', '3'), 
('banana', '4'), 
('banana', '5') 
ON KEY DUPLICATE UPDATE type = CONCAT(type, '|', VALUES(type))

唯一的问题是生成的行是:

('apple', '1|2|2')
('banana', '3|4|5')

我正在尝试 DISTINCT 的不同方法来摆脱最后的“2”,但我不断收到 MySql 错误

MySQL的命令被称为ON DUPLICATE KEY UPDATE

如果你想按照你显示的顺序保存它(比如('banana', '3|4|5'))你应该这样使用它:

ON DUPLICATE KEY UPDATE type = CONCAT(type, '|', VALUES(type))

因为 VALUES 指的是试图插入现有记录的新值。

如果您想避免重复值,请尝试:

ON DUPLICATE KEY UPDATE type = IF(type LIKE CONCAT('%', VALUES(type), '%'), type, CONCAT(type, '|', VALUES(type)) ) 

我同意这不是处理数据库的最佳方式,但如果这是您想要的,这应该可以解决问题。

发件人:https://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html

insert插入数据用管道分隔,可以像这样正常插入数据到数据库中:

create table test(id int, fruit varchar(50), type varchar(100));
INSERT INTO test (fruit, type) VALUES 
('apple', '1'), 
('apple', '2'), 
('apple', '2'), 
('banana', '3'), 
('banana', '4'), 
('banana', '5');

然后编写这样的查询以您想要的方式提取数据:

select fruit, group_concat(distinct type separator '|') as type
from test
group by fruit

Result:
fruit   type
apple   1|2
banana  3|4|5

SQLFiddle 示例:http://sqlfiddle.com/#!9/90a9b/1

您甚至可以创建这样的视图:

create view test_pipedelimited as 
select fruit, group_concat(distinct type separator '|') as type
from test
group by fruit;

然后总是只使用管道分隔格式的结果

select * from test_pipedelimited

程序

如果您真的非常想用竖线分隔存储类型,您可以通过这样的存储过程来实现:

delimiter //
create procedure insert_data_into_test (
    p_fruit varchar(50),  -- takes fruit as first argument
    p_type varchar(100),  -- takes type as second argument
    OUT p_id int -- populates this variable with -1 if it was an update or with last inserted ID if it was an insert
)
begin

   -- find out if the fruit is already in the table
    declare fruit_count int;
    select count(*) into fruit_count from test where fruit = p_fruit;

    -- if fruit is in the table, do an update
    if fruit_count > 0 then
        update test set type = concat(type, '|', p_type) where fruit = p_fruit;
        set p_id = -1;

    -- if fruit is NOT in the table, do an insert
    else
        insert into test (fruit, type) values (p_fruit, p_type);
        select last_insert_id() into p_id;

    end if; 

end; //
delimiter ;

这个程序怎么调用?

create table test (id int primary key auto_increment, fruit varchar(50), type varchar(100));

-- create the procedure here, technically

call insert_data_into_test('apple', '1', @id);
select @id;
Result: 1

select * from test;
ID fruit  type
1  apple  1

call insert_data_into_test('apple', '2', @id);
select @id;
Result: -1

select * from test;
ID fruit  type
1  apple  1|2

call insert_data_into_test('toast', '3', @id);
select @id;
Result: 2

select * from test;
ID fruit  type
1  apple  1|2
2  toast  3

推荐

我强烈建议不要在数据库中存储这样的数据。数据库的真正力量将通过有条不紊地存储数据并遵循一些已知的规范化规则来实现。该技术违反了规范化的第一条规则 (1NF)。

当你想避免插入重复类型时,它也会限制你。假设您输入 apple1 并再次输入。您将获得 1|1 的类型。为了防止这种情况,您将不得不做更多的工作来查明 1 是否存在于类型中。你不能只做 LIKE type = '%1%',因为那会匹配 1、11、21 等。你不能理智地找出每个水果的最大类型等。

更好的程序

delimiter //
create procedure insert_data_into_test (
    p_fruit varchar(50),  -- takes fruit as first argument
    p_type varchar(100),  -- takes type as second argument
    OUT p_id int -- populates this variable with -1 if it was an update or with last inserted ID if it was an insert
)
begin

   -- find out if the fruit is already in the table
    declare fruit_count int;
    declare fruit_type_count int;
    select count(*) into fruit_count from test where fruit = p_fruit;

    -- if fruit is in the table, do an update
    if fruit_count > 0 then

        -- let's check if the the type is already there for the fruit       
        -- we don't want to put duplicates in
        select count(*) into fruit_type_count 
        from test 
        where 
            fruit = p_fruit 
            and (                                                               -- if p_type was 2
                    type regexp concat('^', p_type, '$')            -- ^2$ regex matches if type starts and ends with 2
                    or type regexp concat('^', p_type, '\|')   -- ^2| regex matches if type starts with 2| (the \ is to prevent MySQL from giving a special meaning to |)
                    or type regexp concat('\|', p_type, '\|')     -- |2| regex matches if type is in the middle somewhere
                    or type regexp concat('\|', p_type, '$')       -- |2$ regex matches if type is at the end but there's something before it
                );

        -- only update type if the type is not already present      
        if fruit_type_count = 0 then    
            update test set type = concat(type, '|', p_type);
        end if;
        set p_id = -1;

    -- if fruit is NOT in the table, do an insert
    else
        insert into test (fruit, type) values (p_fruit, p_type);
        select last_insert_id() into p_id;

    end if; 

end; //
delimiter ;

这个更好的过程可以解决重复问题并且不会插入重复项。