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

时间:2015-10-15 22:00:37

标签: mysql insert

对不起,如果标题令人困惑,这就是我想要做的事情:

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

因此,结果表只有两行,type列中的管道分隔值如下所示:

('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列中获得一系列以管道分隔的值吗?

非常感谢

修改

通过这样做,我几乎得到了最终的结果:

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错误

2 个答案:

答案 0 :(得分:2)

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)) ) 

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

来自:Computing Makefile variable on assignment

答案 1 :(得分:1)

插入数据与管道分离,您可以像往常一样将数据插入数据库:

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 ;

这个更好的程序会导致重复,并且不会插入副本。