如何维护 insert-select 脚本的排序?
How to maintain the sort at insert-select scripts?
我们有一个叫做tblINUser
的table
,它有很多条记录,占据了大量的space。为了减少使用的 space 的数量,我们创建了一个名为 tblINUserSortByFilter
的 table,它包含该字段的所有可能的文本值,并且我们在 [=17= 中创建了一个外键] 以数字方式引用此值。我们有几个数据库,因为这个数据库是分片的,所以跨数据库对值进行类似排序会很好。这是第一次尝试:
CREATE TABLE MC.tblINUserSortByFilterType(
pkINUserSortByFilterTypeID SMALLINT(6) PRIMARY KEY AUTO_INCREMENT,
SortByFilter varchar(45) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'first',
INDEX(SortByFilter)
);
INSERT INTO MC.tblINUserSortByFilterType(SortByFilter)
SELECT DISTINCT SortByFilter
FROM MC.tblINUser
ORDER BY SortByFilter = 'first';
ALTER TABLE MC.tblINUser
ADD COLUMN fkINUserSortByFilterTypeID SMALLINT(6) DEFAULT 1,
ADD INDEX (fkINUserSortByFilterTypeID);
UPDATE MC.tblINUser INUser
JOIN MC.tblINUserSortByFilterType INUserSortByFilterType
ON INUser.SortByFilter = INUserSortByFilterType.SortByFilter
SET INUser.fkINUserSortByFilterTypeID = INUserSortByFilterType.pkINUserSortByFilterTypeID;
ALTER TABLE MC.tblINUser
DROP COLUMN SortByFilter;
您可能会正确地争辩说,排序具有唯一的标准,即 ORDER BY SortByFilter = 'first'
,而 ORDER BY SortByFilter = 'first', SortByFilter
的子句将是一个明显的改进。这是一个正确的批评,然而,即使我们可能从第二条记录开始有混乱的行为,也可以合理地预期第一个插入的记录将是 first
,但不幸的是,这不是案子。 运行 select * from MC.tblINUserSortByFilterType;
产量
+----------------------------+----------------------------+
| pkINUserSortByFilterTypeID | SortByFilter |
+----------------------------+----------------------------+
| 5 | first |
| 4 | first-ASC |
| 3 | last |
| 1 | none |
| 2 | StatTeacher.IsActive DESC |
+----------------------------+----------------------------+
正如我们所见,甚至没有满足这个期望,因为 first
的 id 为 5。通过将插入更改为
可以实现改进
INSERT INTO MC.tblINUserSortByFilterType(SortByFilter)
SELECT DISTINCT SortByFilter
FROM MC.tblINUser
WHERE SortByFilter = 'first';
INSERT INTO MC.tblINUserSortByFilterType(SortByFilter)
SELECT DISTINCT SortByFilter
FROM MC.tblINUser
WHERE SortByFilter <> 'first';
然后同样选择的结果我们得到这个结果:
+----------------------------+----------------------------+
| pkINUserSortByFilterTypeID | SortByFilter |
+----------------------------+----------------------------+
| 1 | first |
| 3 | first-ASC |
| 4 | last |
| 2 | none |
| 5 | StatTeacher.IsActive DESC |
+----------------------------+----------------------------+
5 rows in set (0.00 sec)
如我们所见,first
正确接收值 1。然而,似乎如果我们 运行 在数据库的不同副本上进行相同的插入,后续行的顺序可能不可靠。那么,我们如何确保按照以下查询产生的确切顺序插入记录?
SELECT DISTINCT SortByFilter
FROM MC.tblINUser
WHERE SortByFilter = 'first', SortByFilter;
我知道我们可以通过
解决这个问题
- 使用游标进行插入
- 循环收到的记录
- 单独插入它们
但是,insert
语句的数量与上述查询产生的记录数量一样多。有没有办法用一条命令实现同样的效果?
it would be reasonable to expect that the very first inserted record would be first
我不这么认为。您使用 ORDER BY SortByFilter = 'first'
其中 returns 0 表示所有值 除了 'first',然后是 1 表示 'first'。值 1 排在值 0 之后,因此条目 'first' 最终成为 last。其他值最终或多或少随机排序。
演示:
mysql> create table mytable (SortByFilter varchar(64));
Query OK, 0 rows affected (0.02 sec)
mysql> insert into mytable values ('first'), ('first-ASC'),
('last'), ('none'), ('StatTeacher.IsActive DESC');
Query OK, 5 rows affected (0.01 sec)
Records: 5 Duplicates: 0 Warnings: 0
mysql> select SortByFilter='first', SortByFilter from mytable
order by SortByFilter = 'first';
+----------------------+---------------------------+
| SortByFilter='first' | SortByFilter |
+----------------------+---------------------------+
| 0 | first-ASC |
| 0 | last |
| 0 | none |
| 0 | StatTeacher.IsActive DESC |
| 1 | first |
+----------------------+---------------------------+
我建议不要依赖自动排序。具体说明每个值的排序顺序。这是一种方法:
mysql> select field(SortByFilter, 'first', 'first-ASC',
'none', 'StatTeacher.IsActive DESC', 'last') AS SortOrder,
SortByFilter
from mytable order by SortOrder;
+-----------+---------------------------+
| SortOrder | SortByFilter |
+-----------+---------------------------+
| 1 | first |
| 2 | first-ASC |
| 3 | none |
| 4 | StatTeacher.IsActive DESC |
| 5 | last |
+-----------+---------------------------+
要获得特定顺序的行,您必须使用ORDER BY
。如果 ORDER BY
的对象是一个字符串并且您希望按字母顺序排列,或者它是数字并且您希望它按数字顺序排列,那么这很简单。同上使用 DESC
.
相反
对于一些不正常的排序,这里有一个技巧:
ORDER BY FIND_IN_SET(my_column, "first,second,third,fourth")
另一个:
ORDER BY my_column != 'first', my_column
这将首先列出 'first',然后按字母顺序排列其余部分。 (我假设 my_column
是 VARCHAR
。)
ORDER BY my_column = 'last', my_column
请注意,布尔表达式的计算结果为 0(表示假)或 1(表示真);然后我根据0和1的排序顺序。
我们有一个叫做tblINUser
的table
,它有很多条记录,占据了大量的space。为了减少使用的 space 的数量,我们创建了一个名为 tblINUserSortByFilter
的 table,它包含该字段的所有可能的文本值,并且我们在 [=17= 中创建了一个外键] 以数字方式引用此值。我们有几个数据库,因为这个数据库是分片的,所以跨数据库对值进行类似排序会很好。这是第一次尝试:
CREATE TABLE MC.tblINUserSortByFilterType(
pkINUserSortByFilterTypeID SMALLINT(6) PRIMARY KEY AUTO_INCREMENT,
SortByFilter varchar(45) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'first',
INDEX(SortByFilter)
);
INSERT INTO MC.tblINUserSortByFilterType(SortByFilter)
SELECT DISTINCT SortByFilter
FROM MC.tblINUser
ORDER BY SortByFilter = 'first';
ALTER TABLE MC.tblINUser
ADD COLUMN fkINUserSortByFilterTypeID SMALLINT(6) DEFAULT 1,
ADD INDEX (fkINUserSortByFilterTypeID);
UPDATE MC.tblINUser INUser
JOIN MC.tblINUserSortByFilterType INUserSortByFilterType
ON INUser.SortByFilter = INUserSortByFilterType.SortByFilter
SET INUser.fkINUserSortByFilterTypeID = INUserSortByFilterType.pkINUserSortByFilterTypeID;
ALTER TABLE MC.tblINUser
DROP COLUMN SortByFilter;
您可能会正确地争辩说,排序具有唯一的标准,即 ORDER BY SortByFilter = 'first'
,而 ORDER BY SortByFilter = 'first', SortByFilter
的子句将是一个明显的改进。这是一个正确的批评,然而,即使我们可能从第二条记录开始有混乱的行为,也可以合理地预期第一个插入的记录将是 first
,但不幸的是,这不是案子。 运行 select * from MC.tblINUserSortByFilterType;
产量
+----------------------------+----------------------------+
| pkINUserSortByFilterTypeID | SortByFilter |
+----------------------------+----------------------------+
| 5 | first |
| 4 | first-ASC |
| 3 | last |
| 1 | none |
| 2 | StatTeacher.IsActive DESC |
+----------------------------+----------------------------+
正如我们所见,甚至没有满足这个期望,因为 first
的 id 为 5。通过将插入更改为
INSERT INTO MC.tblINUserSortByFilterType(SortByFilter)
SELECT DISTINCT SortByFilter
FROM MC.tblINUser
WHERE SortByFilter = 'first';
INSERT INTO MC.tblINUserSortByFilterType(SortByFilter)
SELECT DISTINCT SortByFilter
FROM MC.tblINUser
WHERE SortByFilter <> 'first';
然后同样选择的结果我们得到这个结果:
+----------------------------+----------------------------+
| pkINUserSortByFilterTypeID | SortByFilter |
+----------------------------+----------------------------+
| 1 | first |
| 3 | first-ASC |
| 4 | last |
| 2 | none |
| 5 | StatTeacher.IsActive DESC |
+----------------------------+----------------------------+
5 rows in set (0.00 sec)
如我们所见,first
正确接收值 1。然而,似乎如果我们 运行 在数据库的不同副本上进行相同的插入,后续行的顺序可能不可靠。那么,我们如何确保按照以下查询产生的确切顺序插入记录?
SELECT DISTINCT SortByFilter
FROM MC.tblINUser
WHERE SortByFilter = 'first', SortByFilter;
我知道我们可以通过
解决这个问题- 使用游标进行插入
- 循环收到的记录
- 单独插入它们
但是,insert
语句的数量与上述查询产生的记录数量一样多。有没有办法用一条命令实现同样的效果?
it would be reasonable to expect that the very first inserted record would be
first
我不这么认为。您使用 ORDER BY SortByFilter = 'first'
其中 returns 0 表示所有值 除了 'first',然后是 1 表示 'first'。值 1 排在值 0 之后,因此条目 'first' 最终成为 last。其他值最终或多或少随机排序。
演示:
mysql> create table mytable (SortByFilter varchar(64));
Query OK, 0 rows affected (0.02 sec)
mysql> insert into mytable values ('first'), ('first-ASC'),
('last'), ('none'), ('StatTeacher.IsActive DESC');
Query OK, 5 rows affected (0.01 sec)
Records: 5 Duplicates: 0 Warnings: 0
mysql> select SortByFilter='first', SortByFilter from mytable
order by SortByFilter = 'first';
+----------------------+---------------------------+
| SortByFilter='first' | SortByFilter |
+----------------------+---------------------------+
| 0 | first-ASC |
| 0 | last |
| 0 | none |
| 0 | StatTeacher.IsActive DESC |
| 1 | first |
+----------------------+---------------------------+
我建议不要依赖自动排序。具体说明每个值的排序顺序。这是一种方法:
mysql> select field(SortByFilter, 'first', 'first-ASC',
'none', 'StatTeacher.IsActive DESC', 'last') AS SortOrder,
SortByFilter
from mytable order by SortOrder;
+-----------+---------------------------+
| SortOrder | SortByFilter |
+-----------+---------------------------+
| 1 | first |
| 2 | first-ASC |
| 3 | none |
| 4 | StatTeacher.IsActive DESC |
| 5 | last |
+-----------+---------------------------+
要获得特定顺序的行,您必须使用ORDER BY
。如果 ORDER BY
的对象是一个字符串并且您希望按字母顺序排列,或者它是数字并且您希望它按数字顺序排列,那么这很简单。同上使用 DESC
.
对于一些不正常的排序,这里有一个技巧:
ORDER BY FIND_IN_SET(my_column, "first,second,third,fourth")
另一个:
ORDER BY my_column != 'first', my_column
这将首先列出 'first',然后按字母顺序排列其余部分。 (我假设 my_column
是 VARCHAR
。)
ORDER BY my_column = 'last', my_column
请注意,布尔表达式的计算结果为 0(表示假)或 1(表示真);然后我根据0和1的排序顺序。