【问题标题】:MYSQL conditional update tableMYSQL条件更新表
【发布时间】:2015-04-26 19:00:56
【问题描述】:

我正在尝试根据特定条件更新数据库表。这是示例表。

  fname mname lname
 1   RONALD D VALE
 2   RONALD  VALE
 3   JACK A SMITH
 4   JACK B SMITH
 5   JACK  SMITH

如果名字和姓氏匹配,我想更新中间名列。在此示例中,我希望得到以下输出。

  fname mname lname
 1   RONALD D VALE
 2   RONALD D VALE
 3   JACK A SMITH
 4   JACK B SMITH
 5   JACK  SMITH

我不清楚如何去做。任何建议/想法...

编辑

请注意,如果有两个不同的中间首字母,我也不想更新表格。

我正在努力使数据保持一致。数据中有一些缺失值。所以主要目的是识别和合并可能相似的多个条目。同时,我们不想将错误的数据引入表中。此处显示的数据仅包含整个表格的几列。还有其他属性使元组独一无二。

【问题讨论】:

  • 鉴于元组应该是唯一的......为什么要破坏数据的完整性?重述为什么第 2 行等于第 1 行,因此,为什么同一数据有两行?我怀疑您需要解决一个设计问题。
  • @kjtl 请看我上面的编辑
  • 我会在 3 遍中完成。
  • @kjtl 你能帮忙详细说明和理解这 3 遍吗?
  • 请参阅下面的答案... 3 次传递有 3 个子查询来获取要更新的中间名。但是数据库的设计仍然存在问题,否则您将不会试图保持不同元组之间的数据完整性。

标签: mysql sql-update conditional


【解决方案1】:

使用子选择来“克隆”表并更新中间名,连接名字和姓氏。

UPDATE names JOIN 
  (SELECT fname, mname, lname FROM names WHERE mname IS NOT NULL
     GROUP BY fname,mname,lname
     HAVING COUNT(*) = 1) AS clone 
ON clone.fname = names.fname AND clone.lname=names.lname
SET names.mname = clone.mname;

【讨论】:

  • 您应该在子查询中包含“ORDER BY mname DESC”。如果不是,所有中间名都将为空。
  • 感谢您的回复,但它不处理负面情况。请看我上面的编辑。
【解决方案2】:

这是第一个可能的答案。

UPDATE table t JOIN
  ( SELECT fname, mname, lname, count(*) as qty
    FROM table
    GROUP BY fname, lname
    HAVING qty > 1
) sub
ON t.fname = sub.fname AND t.lname = sub.lname
SET t.mname = sub.mname
WHERE t.mname = '' and sub.qty = 2
;

更新

不应使用 CASE WHEN,应使用 IF 语句。 它处理 RONALD VALE 记录。

UPDATE table t JOIN
  ( SELECT fname, mname, min(mname) minname, max(mname) mxname, lname, count(*) as qty
    FROM table 
    GROUP BY fname, lname
    HAVING qty > 1
) sub
ON t.fname = sub.fname AND t.lname = sub.lname
SET t.mname = IF(sub.qty = 2, sub.mname, IF(sub.qty > 2, sub.mxname, NULL))
WHERE t.mname is NULL OR LEFT(t.mname,1) = LEFT(sub.mxname, 1)
AND t.mname <> sub.mxname
;

更新 2

# Update 1    
UPDATE table t JOIN
         ( SELECT fname, mname, min(mname) minname, max(mname) mxname, lname, count(*) as qty
           FROM table
           GROUP BY fname, lname
           HAVING qty > 1    ) sub    ON t.fname = sub.fname AND t.lname = sub.lname    SET t.mname = IF(sub.qty = 2, sub.mxname, IF(sub.qty > 2 AND minname = mxname, sub.mxname,  NULL))    WHERE t.mname is NULL #OR LEFT(t.mname,1) = LEFT(sub.mxname, 1);
# Update 2    
UPDATE table t JOIN
         ( SELECT fname, mname, min(mname) minname, max(mname) mxname, lname, count(*) as qty
           FROM table
           GROUP BY fname, lname
           HAVING qty > 1    ) sub    ON t.fname = sub.fname AND t.lname = sub.lname    SET t.mname = IF(sub.qty = 2, sub.mxname, IF(sub.qty > 2, sub.mxname,  NULL))    WHERE LEFT(t.mname,1) = LEFT(sub.mxname, 1)    AND t.mname <> sub.mxname # reduce unnecessary tasks;

之前

         DANIEL J   ABADI
         DANIEL     ABADI
         DANIEL     ABADI
         DANIEL     ABADI
         ROBERT     ABADI
         ROBERT K   ABADI
         AMEY   S   BAILEY
         AMEY   SCHENCK BAILEY
         KARL   K   KWON
         KARL       KWON
         DINESH     MAJETI
         ADAM   M   SMITH
         ADAM   B   SMITH
         ADAM   C   SMITH
         ADAM       SMITH
         ADAM       SMITH
         JACK   A   SMITH
         JACK   B   SMITH
         JACK       SMITH
         RONALD A   VALE
         RONALD D   VALE
         RONALD DAVID   VALE
         RONALD     VALE

之后

         DANIEL J   ABADI
         DANIEL J   ABADI
         DANIEL J   ABADI
         DANIEL J   ABADI
         DANIEL J   ABADI
         ROBERT K   ABADI
         ROBERT K   ABADI
         AMEY   SCHENCK BAILEY
         AMEY   SCHENCK BAILEY
         KARL   K   KWON
         KARL   K   KWON
         DINESH     MAJETI
         ADAM   M   SMITH
         ADAM   B   SMITH
         ADAM   C   SMITH
         ADAM       SMITH
         ADAM       SMITH
         JACK   A   SMITH
         JACK   B   SMITH
         JACK       SMITH
         RONALD A   VALE
         RONALD DAVID   VALE
         RONALD DAVID   VALE
         RONALD     VALE

【讨论】:

  • AMEY S BAILEY AMEY SCHENCK BAILEY to AMEY SCHENCK BAILEY AMEY SCHENCK BAILEY 违反规范。
  • 数据库的设计也有问题...请参阅en.wikipedia.org/wiki/Fourth_normal_form ...名称不应在表中重复 - 无论其他列如何。
【解决方案3】:
/* create the table */
CREATE TABLE if not exists  `duplicated_names` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `first_name` varchar(50) DEFAULT NULL,
  `middle_name` varchar(50) DEFAULT NULL,
  `last_name` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `first_name` (`first_name`),
  KEY `middle_name` (`middle_name`),
  KEY `last_name` (`last_name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

/* drop old values if any */
truncate duplicated_names ;

/* set up up data for example */
insert into duplicated_names ( first_name, middle_name, last_name ) values ( 'Ronald', 'D', 'Vale') ;
insert into duplicated_names ( first_name, middle_name, last_name ) values ( 'Ronald', 'D', 'Vale') ;
insert into duplicated_names ( first_name, middle_name, last_name ) values ( 'Ronald', '', 'Vale') ;
insert into duplicated_names ( first_name, middle_name, last_name ) values ( 'Jack', 'A', 'Smith') ;
insert into duplicated_names ( first_name, middle_name, last_name ) values ( 'Jack', 'B', 'Smith') ;
insert into duplicated_names ( first_name, middle_name, last_name ) values ( 'Jack', '', 'Smith') ;

update duplicated_names
join (
    /* find the middle names */
    select duplicated_names.id
    , duplicated_names.first_name
    , duplicated_names.middle_name
    , duplicated_names.last_name 
    from duplicated_names
    inner join (
        /* find first_name and last_name that have only one middle name */
        select count(*) sum, first_name, last_name from (
            /* find candidate middle name donors who have middle names */
            select count(*) sum, first_name, middle_name, last_name
            from duplicated_names
            where middle_name <> ''
            group by first_name, middle_name, last_name
        ) candidate_middle_name_donors
        group by first_name, last_name
        having count(*) = 1
    ) names_with_one_middle_name
    on names_with_one_middle_name.first_name = duplicated_names.first_name
    and names_with_one_middle_name.last_name = duplicated_names.last_name
    and duplicated_names.middle_name <> ''
) middle_names
on duplicated_names.first_name = middle_names.first_name
and duplicated_names.last_name = middle_names.last_name
set duplicated_names.middle_name = middle_names.middle_name ;

select * from duplicated_names ;

/* 

results 

id  first_name  middle_name last_name
1   Ronald  D   Vale
2   Ronald  D   Vale
3   Ronald  D   Vale
4   Jack    A   Smith
5   Jack    B   Smith
6   Jack        Smith

*/

【讨论】:

  • 如果“Ronald David Vale”存在怎么办?它不起作用。如果有,记录应该更新为“Ronald David Vale”。 @kjtl
  • 规范是有一个一致中间名和一个空白中间名,使空白中间名与一致中间名相同。如果同一个名字和姓氏有两个不同的中间名 - 没有更新。
猜你喜欢
  • 2020-06-27
  • 2018-07-30
  • 1970-01-01
  • 2016-12-06
  • 2013-06-20
  • 1970-01-01
  • 1970-01-01
  • 2011-07-12
  • 2016-08-14
相关资源
最近更新 更多