板凳-------Mysql cookbook学习 (十一--------11)
14.4 从表中消除重复项 7/14/2025 9:19:12 PM
mysql> select * from catalog_list order by last_name, first_name;
+-----------+-------------+--------------------------+
| last_name | first_name | street |
+-----------+-------------+--------------------------+
| Baxter | Wallace | 57 3rd Ave. |
| BAXTER | WALLACE | 57 3rd Ave. |
| Baxter | Wallace | 57 3rd Ave., Apt 102 |
| Baxter | Wallace | 57 3rd Ave. |
| BAXTER | WALLACE | 57 3rd Ave. |
| Baxter | Wallace | 57 3rd Ave., Apt 102 |
| Brown | Bartholomew | 432 River Run |
| Brown | Bartholomew | 432 River Run |
| Isaacson | Jim | 515 Fordam St., Apt. 917 |
| Isaacson | Jim | 515 Fordam St., Apt. 917 |
| McTavish | Taylor | 432 River Run |
| McTavish | Taylor | 432 River Run |
| Pinter | Marlene | 9 Sunset Trail |
| Pinter | Marlene | 9 Sunset Trail |
| Pinter | Marlene | 9 Sunset Trail |
| Pinter | Marlene | 9 Sunset Trail |
+-----------+-------------+--------------------------+
16 rows in set (0.00 sec)mysql> create table tmpp7 like catalog_list;
Query OK, 0 rows affected (0.08 sec)mysql> insert into tmpp7 select distinct * from catalog_list;
Query OK, 6 rows affected (0.01 sec)
Records: 6 Duplicates: 0 Warnings: 0mysql> select * from tmpp7 order by last_name, first_name;
+-----------+-------------+--------------------------+
| last_name | first_name | street |
+-----------+-------------+--------------------------+
| Baxter | Wallace | 57 3rd Ave. |
| Baxter | Wallace | 57 3rd Ave., Apt 102 |
| Brown | Bartholomew | 432 River Run |
| Isaacson | Jim | 515 Fordam St., Apt. 917 |
| McTavish | Taylor | 432 River Run |
| Pinter | Marlene | 9 Sunset Trail |
+-----------+-------------+--------------------------+
6 rows in set (0.00 sec)mysql> drop table catalog_list;
Query OK, 0 rows affected (0.04 sec)mysql> rename table tmpp7 to catalog_list;
Query OK, 0 rows affected (0.04 sec)mysql> create table tmpp7 like catalog_list;
Query OK, 0 rows affected (0.06 sec)mysql> alter table tmpp7 add primary key (last_name, first_name);
Query OK, 0 rows affected (0.12 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> insert ignore into tmpp7 select * from catalog_list;
Query OK, 5 rows affected, 1 warning (0.01 sec)
Records: 6 Duplicates: 1 Warnings: 1mysql> select * from tmpp7 order by last_name, first_name;
+-----------+-------------+--------------------------+
| last_name | first_name | street |
+-----------+-------------+--------------------------+
| Baxter | Wallace | 57 3rd Ave. |
| Brown | Bartholomew | 432 River Run |
| Isaacson | Jim | 515 Fordam St., Apt. 917 |
| McTavish | Taylor | 432 River Run |
| Pinter | Marlene | 9 Sunset Trail |
+-----------+-------------+--------------------------+
5 rows in set (0.00 sec)mysql> drop table catalog_list;
Query OK, 0 rows affected (0.03 sec)mysql> rename table tmpp7 to catalog_list;
Query OK, 0 rows affected (0.03 sec)
14.5 从自连接的结果中消除重复
mysql> select year(s1.statehood) as year,-> s1.name as name1, s1.statehood as statehood1,-> s2.name as name2, s2.statehood as statehood2-> from states as s1 inner join states as s2-> on year(s1.statehood) = year(s2.statehood) and s1.name = s2.name-> order by year, s1.name, s2.name;
+------+----------------+------------+----------------+------------+
| year | name1 | statehood1 | name2 | statehood2 |
+------+----------------+------------+----------------+------------+
| 1787 | Delaware | 1787-12-07 | Delaware | 1787-12-07 |
| 1787 | New Jersey | 1787-12-18 | New Jersey | 1787-12-18 |
| 1787 | Pennsylvania | 1787-12-12 | Pennsylvania | 1787-12-12 |
| 1788 | Connecticut | 1788-01-09 | Connecticut | 1788-01-09 |
| 1788 | Georgia | 1788-01-02 | Georgia | 1788-01-02 |
| 1788 | Maryland | 1788-04-28 | Maryland | 1788-04-28 |
| 1788 | Massachusetts | 1788-02-06 | Massachusetts | 1788-02-06 |
| 1788 | New Hampshire | 1788-06-21 | New Hampshire | 1788-06-21 |
| 1788 | New York | 1788-07-26 | New York | 1788-07-26 |
| 1788 | South Carolina | 1788-05-23 | South Carolina | 1788-05-23 |
| 1788 | Virginia | 1788-06-25 | Virginia | 1788-06-25 |
| 1789 | North Carolina | 1789-11-21 | North Carolina | 1789-11-21 |
| 1790 | Rhode Island | 1790-05-29 | Rhode Island | 1790-05-29 |
| 1791 | Vermont | 1791-03-04 | Vermont | 1791-03-04 |
| 1792 | Kentucky | 1792-06-01 | Kentucky | 1792-06-01 |
| 1796 | Tennessee | 1796-06-01 | Tennessee | 1796-06-01 |
| 1803 | Ohio | 1803-03-01 | Ohio | 1803-03-01 |
| 1812 | Louisiana | 1812-04-30 | Louisiana | 1812-04-30 |
| 1816 | Indiana | 1816-12-11 | Indiana | 1816-12-11 |
| 1817 | Mississippi | 1817-12-10 | Mississippi | 1817-12-10 |
| 1818 | Illinois | 1818-12-03 | Illinois | 1818-12-03 |
| 1819 | Alabama | 1819-12-14 | Alabama | 1819-12-14 |
| 1820 | Maine | 1820-03-15 | Maine | 1820-03-15 |
| 1821 | Missouri | 1821-08-10 | Missouri | 1821-08-10 |
| 1836 | Arkansas | 1836-06-15 | Arkansas | 1836-06-15 |
| 1837 | Michigan | 1837-01-26 | Michigan | 1837-01-26 |
| 1845 | Florida | 1845-03-03 | Florida | 1845-03-03 |
| 1845 | Texas | 1845-12-29 | Texas | 1845-12-29 |
| 1846 | Iowa | 1846-12-28 | Iowa | 1846-12-28 |
| 1848 | Wisconsin | 1848-05-29 | Wisconsin | 1848-05-29 |
| 1850 | California | 1850-09-09 | California | 1850-09-09 |
| 1858 | Minnesota | 1858-05-11 | Minnesota | 1858-05-11 |
| 1859 | Oregon | 1859-02-14 | Oregon | 1859-02-14 |
| 1861 | Kansas | 1861-01-29 | Kansas | 1861-01-29 |
| 1863 | West Virginia | 1863-06-20 | West Virginia | 1863-06-20 |
| 1864 | Nevada | 1864-10-31 | Nevada | 1864-10-31 |
| 1867 | Nebraska | 1867-03-01 | Nebraska | 1867-03-01 |
| 1876 | Colorado | 1876-08-01 | Colorado | 1876-08-01 |
| 1889 | Montana | 1889-11-08 | Montana | 1889-11-08 |
| 1889 | North Dakota | 1889-11-02 | North Dakota | 1889-11-02 |
| 1889 | South Dakota | 1889-11-02 | South Dakota | 1889-11-02 |
| 1889 | Washington | 1889-11-11 | Washington | 1889-11-11 |
| 1890 | Idaho | 1890-07-03 | Idaho | 1890-07-03 |
| 1890 | Wyoming | 1890-07-10 | Wyoming | 1890-07-10 |
| 1896 | Utah | 1896-01-04 | Utah | 1896-01-04 |
| 1907 | Oklahoma | 1907-11-16 | Oklahoma | 1907-11-16 |
| 1912 | Arizona | 1912-02-14 | Arizona | 1912-02-14 |
| 1912 | New Mexico | 1912-01-06 | New Mexico | 1912-01-06 |
| 1959 | Alaska | 1959-01-03 | Alaska | 1959-01-03 |
| 1959 | Hawaii | 1959-08-21 | Hawaii | 1959-08-21 |
+------+----------------+------------+----------------+------------+
50 rows in set (0.01 sec)这个查询会:
1. 找出同一年加入联邦的州对
2. 按字母顺序排列每对州的名称(name1是字母顺序靠前的,name2是字母顺序靠后的)
3. 按照年份、name1和name2排序结果mysql> SELECT YEAR(s1.statehood) AS year,-> IF(s1.name < s2.name, s1.name, s2.name) AS name1,-> IF(s1.name < s2.name, s1.statehood, s2.statehood) AS statehood1,-> IF(s1.name < s2.name, s2.name, s1.name) AS name2,-> IF(s1.name < s2.name, s2.statehood, s1.statehood) AS statehood2-> FROM states AS s1-> INNER JOIN states AS s2-> ON YEAR(s1.statehood) = YEAR(s2.statehood) AND s1.name != s2.name-> ORDER BY year, name1, name2;
+------+----------------+------------+----------------+------------+
| year | name1 | statehood1 | name2 | statehood2 |
+------+----------------+------------+----------------+------------+
| 1787 | Delaware | 1787-12-07 | New Jersey | 1787-12-18 |
| 1787 | Delaware | 1787-12-07 | New Jersey | 1787-12-18 |
| 1787 | Delaware | 1787-12-07 | Pennsylvania | 1787-12-12 |
| 1787 | Delaware | 1787-12-07 | Pennsylvania | 1787-12-12 |
| 1787 | New Jersey | 1787-12-18 | Pennsylvania | 1787-12-12 |
| 1787 | New Jersey | 1787-12-18 | Pennsylvania | 1787-12-12 |
| 1788 | Connecticut | 1788-01-09 | Georgia | 1788-01-02 |
| 1788 | Connecticut | 1788-01-09 | Georgia | 1788-01-02 |
| 1788 | Connecticut | 1788-01-09 | Maryland | 1788-04-28 |
| 1788 | Connecticut | 1788-01-09 | Maryland | 1788-04-28 |
| 1788 | Connecticut | 1788-01-09 | Massachusetts | 1788-02-06 |
| 1788 | Connecticut | 1788-01-09 | Massachusetts | 1788-02-06 |
| 1788 | Connecticut | 1788-01-09 | New Hampshire | 1788-06-21 |
| 1788 | Connecticut | 1788-01-09 | New Hampshire | 1788-06-21 |
| 1788 | Connecticut | 1788-01-09 | New York | 1788-07-26 |
| 1788 | Connecticut | 1788-01-09 | New York | 1788-07-26 |
| 1788 | Connecticut | 1788-01-09 | South Carolina | 1788-05-23 |
| 1788 | Connecticut | 1788-01-09 | South Carolina | 1788-05-23 |
| 1788 | Connecticut | 1788-01-09 | Virginia | 1788-06-25 |
| 1788 | Connecticut | 1788-01-09 | Virginia | 1788-06-25 |
| 1788 | Georgia | 1788-01-02 | Maryland | 1788-04-28 |
| 1788 | Georgia | 1788-01-02 | Maryland | 1788-04-28 |
| 1788 | Georgia | 1788-01-02 | Massachusetts | 1788-02-06 |
| 1788 | Georgia | 1788-01-02 | Massachusetts | 1788-02-06 |
| 1788 | Georgia | 1788-01-02 | New Hampshire | 1788-06-21 |
| 1788 | Georgia | 1788-01-02 | New Hampshire | 1788-06-21 |
| 1788 | Georgia | 1788-01-02 | New York | 1788-07-26 |
| 1788 | Georgia | 1788-01-02 | New York | 1788-07-26 |
| 1788 | Georgia | 1788-01-02 | South Carolina | 1788-05-23 |
| 1788 | Georgia | 1788-01-02 | South Carolina | 1788-05-23 |
| 1788 | Georgia | 1788-01-02 | Virginia | 1788-06-25 |
| 1788 | Georgia | 1788-01-02 | Virginia | 1788-06-25 |
| 1788 | Maryland | 1788-04-28 | Massachusetts | 1788-02-06 |
| 1788 | Maryland | 1788-04-28 | Massachusetts | 1788-02-06 |
| 1788 | Maryland | 1788-04-28 | New Hampshire | 1788-06-21 |
| 1788 | Maryland | 1788-04-28 | New Hampshire | 1788-06-21 |
| 1788 | Maryland | 1788-04-28 | New York | 1788-07-26 |
| 1788 | Maryland | 1788-04-28 | New York | 1788-07-26 |
| 1788 | Maryland | 1788-04-28 | South Carolina | 1788-05-23 |
| 1788 | Maryland | 1788-04-28 | South Carolina | 1788-05-23 |
| 1788 | Maryland | 1788-04-28 | Virginia | 1788-06-25 |
| 1788 | Maryland | 1788-04-28 | Virginia | 1788-06-25 |
| 1788 | Massachusetts | 1788-02-06 | New Hampshire | 1788-06-21 |
| 1788 | Massachusetts | 1788-02-06 | New Hampshire | 1788-06-21 |
| 1788 | Massachusetts | 1788-02-06 | New York | 1788-07-26 |
| 1788 | Massachusetts | 1788-02-06 | New York | 1788-07-26 |
| 1788 | Massachusetts | 1788-02-06 | South Carolina | 1788-05-23 |
| 1788 | Massachusetts | 1788-02-06 | South Carolina | 1788-05-23 |
| 1788 | Massachusetts | 1788-02-06 | Virginia | 1788-06-25 |
| 1788 | Massachusetts | 1788-02-06 | Virginia | 1788-06-25 |
| 1788 | New Hampshire | 1788-06-21 | New York | 1788-07-26 |
| 1788 | New Hampshire | 1788-06-21 | New York | 1788-07-26 |
| 1788 | New Hampshire | 1788-06-21 | South Carolina | 1788-05-23 |
| 1788 | New Hampshire | 1788-06-21 | South Carolina | 1788-05-23 |
| 1788 | New Hampshire | 1788-06-21 | Virginia | 1788-06-25 |
| 1788 | New Hampshire | 1788-06-21 | Virginia | 1788-06-25 |
| 1788 | New York | 1788-07-26 | South Carolina | 1788-05-23 |
| 1788 | New York | 1788-07-26 | South Carolina | 1788-05-23 |
| 1788 | New York | 1788-07-26 | Virginia | 1788-06-25 |
| 1788 | New York | 1788-07-26 | Virginia | 1788-06-25 |
| 1788 | South Carolina | 1788-05-23 | Virginia | 1788-06-25 |
| 1788 | South Carolina | 1788-05-23 | Virginia | 1788-06-25 |
| 1845 | Florida | 1845-03-03 | Texas | 1845-12-29 |
| 1845 | Florida | 1845-03-03 | Texas | 1845-12-29 |
| 1889 | Montana | 1889-11-08 | North Dakota | 1889-11-02 |
| 1889 | Montana | 1889-11-08 | North Dakota | 1889-11-02 |
| 1889 | Montana | 1889-11-08 | South Dakota | 1889-11-02 |
| 1889 | Montana | 1889-11-08 | South Dakota | 1889-11-02 |
| 1889 | Montana | 1889-11-08 | Washington | 1889-11-11 |
| 1889 | Montana | 1889-11-08 | Washington | 1889-11-11 |
| 1889 | North Dakota | 1889-11-02 | South Dakota | 1889-11-02 |
| 1889 | North Dakota | 1889-11-02 | South Dakota | 1889-11-02 |
| 1889 | North Dakota | 1889-11-02 | Washington | 1889-11-11 |
| 1889 | North Dakota | 1889-11-02 | Washington | 1889-11-11 |
| 1889 | South Dakota | 1889-11-02 | Washington | 1889-11-11 |
| 1889 | South Dakota | 1889-11-02 | Washington | 1889-11-11 |
| 1890 | Idaho | 1890-07-03 | Wyoming | 1890-07-10 |
| 1890 | Idaho | 1890-07-03 | Wyoming | 1890-07-10 |
| 1912 | Arizona | 1912-02-14 | New Mexico | 1912-01-06 |
| 1912 | Arizona | 1912-02-14 | New Mexico | 1912-01-06 |
| 1959 | Alaska | 1959-01-03 | Hawaii | 1959-08-21 |
| 1959 | Alaska | 1959-01-03 | Hawaii | 1959-08-21 |
+------+----------------+------------+----------------+------------+
82 rows in set (0.00 sec)增加distinct 消除多余的拷贝
mysql> SELECT distinct YEAR(s1.statehood) AS year,-> IF(s1.name < s2.name, s1.name, s2.name) AS name1,-> IF(s1.name < s2.name, s1.statehood, s2.statehood) AS statehood1,-> IF(s1.name < s2.name, s2.name, s1.name) AS name2,-> IF(s1.name < s2.name, s2.statehood, s1.statehood) AS statehood2-> FROM states AS s1-> INNER JOIN states AS s2-> ON YEAR(s1.statehood) = YEAR(s2.statehood) AND s1.name != s2.name-> ORDER BY year, name1, name2;
+------+----------------+------------+----------------+------------+
| year | name1 | statehood1 | name2 | statehood2 |
+------+----------------+------------+----------------+------------+
| 1787 | Delaware | 1787-12-07 | New Jersey | 1787-12-18 |
| 1787 | Delaware | 1787-12-07 | Pennsylvania | 1787-12-12 |
| 1787 | New Jersey | 1787-12-18 | Pennsylvania | 1787-12-12 |
| 1788 | Connecticut | 1788-01-09 | Georgia | 1788-01-02 |
| 1788 | Connecticut | 1788-01-09 | Maryland | 1788-04-28 |
| 1788 | Connecticut | 1788-01-09 | Massachusetts | 1788-02-06 |
| 1788 | Connecticut | 1788-01-09 | New Hampshire | 1788-06-21 |
| 1788 | Connecticut | 1788-01-09 | New York | 1788-07-26 |
| 1788 | Connecticut | 1788-01-09 | South Carolina | 1788-05-23 |
| 1788 | Connecticut | 1788-01-09 | Virginia | 1788-06-25 |
| 1788 | Georgia | 1788-01-02 | Maryland | 1788-04-28 |
| 1788 | Georgia | 1788-01-02 | Massachusetts | 1788-02-06 |
| 1788 | Georgia | 1788-01-02 | New Hampshire | 1788-06-21 |
| 1788 | Georgia | 1788-01-02 | New York | 1788-07-26 |
| 1788 | Georgia | 1788-01-02 | South Carolina | 1788-05-23 |
| 1788 | Georgia | 1788-01-02 | Virginia | 1788-06-25 |
| 1788 | Maryland | 1788-04-28 | Massachusetts | 1788-02-06 |
| 1788 | Maryland | 1788-04-28 | New Hampshire | 1788-06-21 |
| 1788 | Maryland | 1788-04-28 | New York | 1788-07-26 |
| 1788 | Maryland | 1788-04-28 | South Carolina | 1788-05-23 |
| 1788 | Maryland | 1788-04-28 | Virginia | 1788-06-25 |
| 1788 | Massachusetts | 1788-02-06 | New Hampshire | 1788-06-21 |
| 1788 | Massachusetts | 1788-02-06 | New York | 1788-07-26 |
| 1788 | Massachusetts | 1788-02-06 | South Carolina | 1788-05-23 |
| 1788 | Massachusetts | 1788-02-06 | Virginia | 1788-06-25 |
| 1788 | New Hampshire | 1788-06-21 | New York | 1788-07-26 |
| 1788 | New Hampshire | 1788-06-21 | South Carolina | 1788-05-23 |
| 1788 | New Hampshire | 1788-06-21 | Virginia | 1788-06-25 |
| 1788 | New York | 1788-07-26 | South Carolina | 1788-05-23 |
| 1788 | New York | 1788-07-26 | Virginia | 1788-06-25 |
| 1788 | South Carolina | 1788-05-23 | Virginia | 1788-06-25 |
| 1845 | Florida | 1845-03-03 | Texas | 1845-12-29 |
| 1889 | Montana | 1889-11-08 | North Dakota | 1889-11-02 |
| 1889 | Montana | 1889-11-08 | South Dakota | 1889-11-02 |
| 1889 | Montana | 1889-11-08 | Washington | 1889-11-11 |
| 1889 | North Dakota | 1889-11-02 | South Dakota | 1889-11-02 |
| 1889 | North Dakota | 1889-11-02 | Washington | 1889-11-11 |
| 1889 | South Dakota | 1889-11-02 | Washington | 1889-11-11 |
| 1890 | Idaho | 1890-07-03 | Wyoming | 1890-07-10 |
| 1912 | Arizona | 1912-02-14 | New Mexico | 1912-01-06 |
| 1959 | Alaska | 1959-01-03 | Hawaii | 1959-08-21 |
+------+----------------+------------+----------------+------------+
41 rows in set (0.00 sec)mysql> SELECT YEAR(s1.statehood) AS year,-> IF(s1.name < s2.name, s1.name, s2.name) AS name1,-> IF(s1.name < s2.name, s1.statehood, s2.statehood) AS statehood1,-> IF(s1.name < s2.name, s2.name, s1.name) AS name2,-> IF(s1.name < s2.name, s2.statehood, s1.statehood) AS statehood2-> FROM states AS s1-> INNER JOIN states AS s2-> ON YEAR(s1.statehood) = YEAR(s2.statehood) AND s1.name < s2.name-> ORDER BY year, name1, name2;
+------+----------------+------------+----------------+------------+
| year | name1 | statehood1 | name2 | statehood2 |
+------+----------------+------------+----------------+------------+
| 1787 | Delaware | 1787-12-07 | New Jersey | 1787-12-18 |
| 1787 | Delaware | 1787-12-07 | Pennsylvania | 1787-12-12 |
| 1787 | New Jersey | 1787-12-18 | Pennsylvania | 1787-12-12 |
| 1788 | Connecticut | 1788-01-09 | Georgia | 1788-01-02 |
| 1788 | Connecticut | 1788-01-09 | Maryland | 1788-04-28 |
| 1788 | Connecticut | 1788-01-09 | Massachusetts | 1788-02-06 |
| 1788 | Connecticut | 1788-01-09 | New Hampshire | 1788-06-21 |
| 1788 | Connecticut | 1788-01-09 | New York | 1788-07-26 |
| 1788 | Connecticut | 1788-01-09 | South Carolina | 1788-05-23 |
| 1788 | Connecticut | 1788-01-09 | Virginia | 1788-06-25 |
| 1788 | Georgia | 1788-01-02 | Maryland | 1788-04-28 |
| 1788 | Georgia | 1788-01-02 | Massachusetts | 1788-02-06 |
| 1788 | Georgia | 1788-01-02 | New Hampshire | 1788-06-21 |
| 1788 | Georgia | 1788-01-02 | New York | 1788-07-26 |
| 1788 | Georgia | 1788-01-02 | South Carolina | 1788-05-23 |
| 1788 | Georgia | 1788-01-02 | Virginia | 1788-06-25 |
| 1788 | Maryland | 1788-04-28 | Massachusetts | 1788-02-06 |
| 1788 | Maryland | 1788-04-28 | New Hampshire | 1788-06-21 |
| 1788 | Maryland | 1788-04-28 | New York | 1788-07-26 |
| 1788 | Maryland | 1788-04-28 | South Carolina | 1788-05-23 |
| 1788 | Maryland | 1788-04-28 | Virginia | 1788-06-25 |
| 1788 | Massachusetts | 1788-02-06 | New Hampshire | 1788-06-21 |
| 1788 | Massachusetts | 1788-02-06 | New York | 1788-07-26 |
| 1788 | Massachusetts | 1788-02-06 | South Carolina | 1788-05-23 |
| 1788 | Massachusetts | 1788-02-06 | Virginia | 1788-06-25 |
| 1788 | New Hampshire | 1788-06-21 | New York | 1788-07-26 |
| 1788 | New Hampshire | 1788-06-21 | South Carolina | 1788-05-23 |
| 1788 | New Hampshire | 1788-06-21 | Virginia | 1788-06-25 |
| 1788 | New York | 1788-07-26 | South Carolina | 1788-05-23 |
| 1788 | New York | 1788-07-26 | Virginia | 1788-06-25 |
| 1788 | South Carolina | 1788-05-23 | Virginia | 1788-06-25 |
| 1845 | Florida | 1845-03-03 | Texas | 1845-12-29 |
| 1889 | Montana | 1889-11-08 | North Dakota | 1889-11-02 |
| 1889 | Montana | 1889-11-08 | South Dakota | 1889-11-02 |
| 1889 | Montana | 1889-11-08 | Washington | 1889-11-11 |
| 1889 | North Dakota | 1889-11-02 | South Dakota | 1889-11-02 |
| 1889 | North Dakota | 1889-11-02 | Washington | 1889-11-11 |
| 1889 | South Dakota | 1889-11-02 | Washington | 1889-11-11 |
| 1890 | Idaho | 1890-07-03 | Wyoming | 1890-07-10 |
| 1912 | Arizona | 1912-02-14 | New Mexico | 1912-01-06 |
| 1959 | Alaska | 1959-01-03 | Hawaii | 1959-08-21 |
+------+----------------+------------+----------------+------------+
41 rows in set (0.00 sec)
第15章:执行事务
15.0 引言
mysql> CREATE TABLE pilot (-> pilot_id INT PRIMARY KEY,-> name VARCHAR(50),-> available ENUM('yes','no')-> );
Query OK, 0 rows affected (0.05 sec)mysql> select @p_val := pilot_id from pilot where available = 'yes' limit 1;
Empty set, 1 warning (0.00 sec)mysql> update pilot set available = 'no' where pilot_id = @p_val;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 0 Changed: 0 Warnings: 0mysql> update flight set pilot_id = @p_val where flight_id = 578;
ERROR 1146 (42S02): Table 'cookbook.flight' doesn't exist
mysql> INSERT INTO pilot (pilot_id, name, available) VALUES-> (1, 'John Smith', 'yes'),-> (2, 'Jane Doe', 'yes'),-> (3, 'Mike Johnson', 'no');
Query OK, 3 rows affected (0.01 sec)
Records: 3 Duplicates: 0 Warnings: 0mysql> SELECT @p_val := pilot_id FROM pilot WHERE available = 'yes' LIMIT 1;
+--------------------+
| @p_val := pilot_id |
+--------------------+
| 1 |
+--------------------+
1 row in set, 1 warning (0.00 sec)mysql> CREATE TABLE flight (-> flight_id INT PRIMARY KEY,-> pilot_id INT,-> flight_date DATETIME,-> -- 其他需要的列-> FOREIGN KEY (pilot_id) REFERENCES pilot(pilot_id)-> );
Query OK, 0 rows affected (0.09 sec)mysql>
mysql> -- 插入测试数据
mysql> INSERT INTO flight (flight_id, pilot_id, flight_date) VALUES-> (578, NULL, '2023-12-01 10:00:00');
Query OK, 1 row affected (0.01 sec)
15.1 使用事务存储引擎
mysql> show engines\g
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| Engine | Support | Comment | Transactions | XA | Savepoints |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO |
| MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO |
| CSV | YES | CSV storage engine | NO | NO | NO |
| FEDERATED | YES | Federated MySQL storage engine | NO | NO | NO |
| PERFORMANCE_SCHEMA | YES | Performance Schema | NO | NO | NO |
| MyISAM | YES | MyISAM storage engine | NO | NO | NO |
| InnoDB | DEFAULT | Supports transactions, row-level locking, and foreign keys | YES | YES | YES |
| ndbinfo | NO | MySQL Cluster system information storage engine | NULL | NULL | NULL |
| BLACKHOLE | YES | /dev/null storage engine (anything you write to it disappears) | NO | NO | NO |
| ARCHIVE | YES | Archive storage engine | NO | NO | NO |
| ndbcluster | NO | Clustered, fault-tolerant tables | NULL | NULL | NULL |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
11 rows in set (0.00 sec)mysql> create table ttt1 (i int) engine = InnoDB;
Query OK, 0 rows affected (0.05 sec)mysql> create table ttt2 (i int) engine = BDB;
ERROR 1286 (42000): Unknown storage engine 'BDB'
mysql> create table ttt2 (i int) engine = MyISAM;
Query OK, 0 rows affected (0.02 sec)mysql> alter table ttt engine = InnoDB;
Query OK, 0 rows affected (0.26 sec)
Records: 0 Duplicates: 0 Warnings: 0
15.2 使用sql执行事务
mysql> DROP TABLE ttt;
Query OK, 0 rows affected (0.04 sec)mysql> CREATE TABLE ttt (i INT) ENGINE = InnoDB;
Query OK, 0 rows affected (0.06 sec)mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)mysql> INSERT INTO ttt (i) VALUES(1);
Query OK, 1 row affected (0.00 sec)mysql> COMMIT;
Query OK, 0 rows affected (0.01 sec)mysql> INSERT INTO ttt (i) VALUES(2);
Query OK, 1 row affected (0.01 sec)mysql> commit;
Query OK, 0 rows affected (0.00 sec)mysql> select * from ttt;
+------+
| i |
+------+
| 1 |
| 2 |
+------+
2 rows in set (0.00 sec)mysql> insert into ttt (x) values(3);
ERROR 1054 (42S22): Unknown column 'x' in 'field list'
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)mysql> select * from ttt;
+------+
| i |
+------+
| 1 |
| 2 |
+------+
2 rows in set (0.00 sec)mysql> set autocommit = 0;
Query OK, 0 rows affected (0.00 sec)
• 作用:关闭自动提交模式(默认是 autocommit=1,即每条SQL语句自动提交)
• 效果:后续所有操作将在一个事务中,直到显式执行 COMMIT 或 ROLLBACK
• 类比:相当于打开了一个"编辑会话",所有修改不会立即生效mysql> insert into ttt (i) values(3);
Query OK, 1 row affected (0.00 sec)mysql> insert into ttt (i) values(4);
Query OK, 1 row affected (0.00 sec)mysql> commit;
Query OK, 0 rows affected (0.01 sec)mysql> select * from ttt;
+------+
| i |
+------+
| 1 |
| 2 |
| 3 |
| 4 |
+------+
4 rows in set (0.00 sec)mysql> set autocommit = 1;
Query OK, 0 rows affected (0.00 sec)
• 作用:重新开启自动提交模式
• 后续影响:
o 每条SQL语句将再次自动成为独立事务
o 不需要显式执行 COMMIT在 MySQL 中,执行 DROP DATABASE 后无法通过 ROLLBACK 恢复数据库,这是由以下几个关键原因决定的:
1. DDL 语句的自动提交特性
• 所有 DDL(数据定义语言)语句(如 CREATE, ALTER, DROP)会自动提交当前事务,不受 autocommit 设置影响。
• 即使你设置了 SET autocommit=0,执行 DROP DATABASE 时:
sql
复制
下载
SET autocommit=0;
DROP DATABASE mydb; -- 这条语句会立即提交
ROLLBACK; -- 此时已无效
2. 事务日志不记录 DDL 操作
• 事务的回滚依赖于事务日志(undo log),但 DDL 操作:
o 直接修改数据字典(元数据)
o 不生成可回滚的事务日志
o 会隐式提交当前所有未提交的事务
3. 物理文件删除
• DROP DATABASE 不仅删除元数据,还会直接删除磁盘上的数据文件(.ibd, .frm 等)
• 这种物理删除操作超出了事务系统的管理范围
对比示例
操作类型 是否可回滚 原因
INSERT/UPDATE ✅ 可以 生成 undo log,事务系统可回滚
DROP DATABASE ❌ 不可以 自动提交+无 undo log+物理文件删除
解决方案(如果误删数据库)
1. 从备份恢复:
bash
复制
下载
mysql -u root -p < backup.sql
2. 使用二进制日志(需提前开启):
sql
复制
下载
mysqlbinlog --start-datetime="2023-11-01 00:00:00" binlog.000123 | mysql -u root -p
3. 专业数据恢复工具(如 Percona Data Recovery Tool for InnoDB)
预防措施
sql
复制
下载
-- 重要操作前先备份
CREATE DATABASE mydb_backup;
USE mydb_backup;
CREATE TABLE ... SELECT * FROM original_db.*; -- 快速克隆-- 或使用 mysqldump
mysqldump -u root -p original_db > backup.sql
总结:DROP DATABASE 是设计上不可逆的操作,因其直接修改物理存储结构,这与事务系统的设计目标(管理数据修改而非结构变更)有本质区别。