Php 按“最完整字段”排序的MySQL查询顺序

Php 按“最完整字段”排序的MySQL查询顺序,php,mysql,Php,Mysql,我有一个表,有45列,但其中只有少数尚未完成。此表不断更新和添加等。在我的自动完成功能中,我想选择按最完整字段排序的这些记录。希望您理解 解决方案之一是在rank字段中创建另一个字段,并创建一个php函数,用于选择*记录并为每个记录提供一个等级 。。。但我想知道是否有一种更简单的方法,只需要一个ORDER BY就可以做到这一点?据我所知,MySQL没有计算一行中非空字段数量的功能 所以我能想到的唯一方法就是使用显式条件: SELECT * FROM mytable ORDER BY (I

我有一个表,有45列,但其中只有少数尚未完成。此表不断更新和添加等。在我的自动完成功能中,我想选择按最完整字段排序的这些记录。希望您理解

解决方案之一是在rank字段中创建另一个字段,并创建一个php函数,用于选择*记录并为每个记录提供一个等级


。。。但我想知道是否有一种更简单的方法,只需要一个ORDER BY就可以做到这一点?

据我所知,MySQL没有计算一行中非空字段数量的功能

所以我能想到的唯一方法就是使用显式条件:

SELECT * FROM mytable
    ORDER BY (IF( column1 IS NULL, 0, 1)
             +IF( column2 IS NULL, 0, 1)
             ...
             +IF( column45 IS NULL, 0, 1)) DESC;
…这是丑陋的罪恶,但应该做的把戏

您还可以设计一个触发器来增加一个额外的列字段。在更新时触发的代价是你,在选择时45个如果伤害了你;你必须对更方便的东西进行建模

请注意,为所有字段编制索引以加快SELECT的速度将在更新时花费您的时间,45个不同的索引的花费可能相当于SELECT上的表扫描,更不用说索引字段是VARCHAR。运行一些测试,但我相信45-IF解决方案可能是总体上最好的

更新: 如果可以对表结构进行返工以使其正常化,则可以将字段放在my_values表中。然后你会有一个标题表,可能只有一个唯一的ID和一个数据表。空字段将根本不存在,然后您可以通过使用右连接对填充字段进行排序,使用COUNT对填充字段进行计数。这也将大大加快更新操作,并允许您有效地使用索引

从表格设置到两个标准化表格设置的示例:

假设我们有一组客户记录。我们将有一个简短的强制性数据子集,如ID、用户名、密码、电子邮件等。;然后我们将有一个更大的可选数据子集,比如昵称、化身、出生日期等等。作为第一步,让我们假设所有这些数据都是varchar。乍一看,与每个列都有自己的数据类型的单表解决方案相比,这似乎是一个限制

所以我们有一张这样的桌子

ID   username    ....
1    jdoe        etc.
2    jqaverage   etc.
3    jkilroy     etc.
然后我们有了可选的数据表。在这里,约翰·多伊填补了所有领域,乔·Q.平均只有两个领域,而基尔罗伊即使在这里也没有

为了在MySQL中重现单表输出,我们必须创建一个包含大量左连接的非常复杂的视图。尽管如此,如果我们有一个基于userid、var的索引,这个视图将非常快,如果我们对var的数据类型使用数值常量或集合而不是varchar,则更好:

逻辑模型中的每个字段(例如名称)将包含在可选数据表中的元组id“name”值中

它将产生一行形式为s.val的行,如上面查询的第1节所示,在第2节中引用形式为LEFT JOIN userdata的行,即s ON users.id=s.id和s.var=s。因此,我们可以通过将上述查询的第一个文本行与动态部分1、文本“FROM users”和动态构建的部分2连接起来来动态构造查询

一旦我们这样做了,视图上的选择与以前完全相同,但现在它们通过联接从两个规范化表中获取数据

EXPLAIN SELECT * FROM usertable;
将告诉我们,向该设置中添加列不会明显降低操作速度,也就是说,该解决方案的可扩展性相当好

必须修改插入。我们只插入必需的数据,并且只在第一个表中插入,并进行更新:我们要么更新必需的数据表,要么更新可选数据表的一行。但是如果目标行不存在,则必须插入它

所以我们必须更换

UPDATE usertable SET name = 'John Doe', born = 'New York' WHERE id = 1;
在这种情况下,使用“向上插入”

INSERT INTO userdata VALUES
        ( 1, 'name', 'John Doe' ),
        ( 1, 'born', 'New York' )
    ON DUPLICATE KEY UPDATE val = VALUES(val);
我们需要一个关于userdataid的唯一索引,var,以便在重复键上工作

根据行大小和磁盘问题,此更改可能会带来可观的性能提升

请注意,如果不执行此修改,现有查询将不会产生错误-它们将自动失败

例如,这里我们修改两个用户的名称;一个在记录中有名称,另一个为空。第一个是修改的,第二个不是

mysql> SELECT * FROM usertable;
+------+-----------+-------------+------+------+
| id   | username  | name        | born | age  |
+------+-----------+-------------+------+------+
|    1 | jdoe      | John Doe    | NULL | NULL |
|    2 | jqaverage | NULL        | NULL | NULL |
|    3 | jtkilroy  | NULL        | NULL | NULL |
+------+-----------+-------------+------+------+
3 rows in set (0.00 sec)
mysql> UPDATE usertable SET name = 'John Doe II' WHERE username = 'jdoe';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
mysql> UPDATE usertable SET name = 'James T. Kilroy' WHERE username = 'jtkilroy';
Query OK, 0 rows affected (0.00 sec)
Rows matched: 0  Changed: 0  Warnings: 0
mysql> select * from usertable;
+------+-----------+-------------+------+------+
| id   | username  | name        | born | age  |
+------+-----------+-------------+------+------+
|    1 | jdoe      | John Doe II | NULL | NULL |
|    2 | jqaverage | NULL        | NULL | NULL |
|    3 | jtkilroy  | NULL        | NULL | NULL |
+------+-----------+-------------+------+------+
3 rows in set (0.00 sec)
要知道每行的排名,对于那些确实有排名的用户,我们只需检索每个id的userdata行数:

SELECT id, COUNT(*) AS rank FROM userdata GROUP BY id
现在,要按填充状态顺序提取行,我们需要执行以下操作:

SELECT usertable.* FROM usertable
    LEFT JOIN ( SELECT id, COUNT(*) AS rank FROM userdata GROUP BY id ) AS ranking
ON (usertable.id = ranking.id)
ORDER BY rank DESC, id;

左连接确保了无生气的个体也能被检索到,而额外的id排序确保了具有相同等级的人总是以相同的顺序出现。

据我所知,MySQL没有计算一行中非空字段数量的功能

所以我能想到的唯一方法就是使用显式条件:

SELECT * FROM mytable
    ORDER BY (IF( column1 IS NULL, 0, 1)
             +IF( column2 IS NULL, 0, 1)
             ...
             +IF( column45 IS NULL, 0, 1)) DESC;
…这是丑陋的罪恶,但应该做的把戏

您还可以设计一个触发器来增加一个额外的列字段。触发器 更新时,45个如果在选择时伤害了你;你必须对更方便的东西进行建模

请注意,为所有字段编制索引以加快SELECT的速度将在更新时花费您的时间,45个不同的索引的花费可能相当于SELECT上的表扫描,更不用说索引字段是VARCHAR。运行一些测试,但我相信45-IF解决方案可能是总体上最好的

更新: 如果可以对表结构进行返工以使其正常化,则可以将字段放在my_values表中。然后你会有一个标题表,可能只有一个唯一的ID和一个数据表。空字段将根本不存在,然后您可以通过使用右连接对填充字段进行排序,使用COUNT对填充字段进行计数。这也将大大加快更新操作,并允许您有效地使用索引

从表格设置到两个标准化表格设置的示例:

假设我们有一组客户记录。我们将有一个简短的强制性数据子集,如ID、用户名、密码、电子邮件等。;然后我们将有一个更大的可选数据子集,比如昵称、化身、出生日期等等。作为第一步,让我们假设所有这些数据都是varchar。乍一看,与每个列都有自己的数据类型的单表解决方案相比,这似乎是一个限制

所以我们有一张这样的桌子

ID   username    ....
1    jdoe        etc.
2    jqaverage   etc.
3    jkilroy     etc.
然后我们有了可选的数据表。在这里,约翰·多伊填补了所有领域,乔·Q.平均只有两个领域,而基尔罗伊即使在这里也没有

为了在MySQL中重现单表输出,我们必须创建一个包含大量左连接的非常复杂的视图。尽管如此,如果我们有一个基于userid、var的索引,这个视图将非常快,如果我们对var的数据类型使用数值常量或集合而不是varchar,则更好:

逻辑模型中的每个字段(例如名称)将包含在可选数据表中的元组id“name”值中

它将产生一行形式为s.val的行,如上面查询的第1节所示,在第2节中引用形式为LEFT JOIN userdata的行,即s ON users.id=s.id和s.var=s。因此,我们可以通过将上述查询的第一个文本行与动态部分1、文本“FROM users”和动态构建的部分2连接起来来动态构造查询

一旦我们这样做了,视图上的选择与以前完全相同,但现在它们通过联接从两个规范化表中获取数据

EXPLAIN SELECT * FROM usertable;
将告诉我们,向该设置中添加列不会明显降低操作速度,也就是说,该解决方案的可扩展性相当好

必须修改插入。我们只插入必需的数据,并且只在第一个表中插入,并进行更新:我们要么更新必需的数据表,要么更新可选数据表的一行。但是如果目标行不存在,则必须插入它

所以我们必须更换

UPDATE usertable SET name = 'John Doe', born = 'New York' WHERE id = 1;
在这种情况下,使用“向上插入”

INSERT INTO userdata VALUES
        ( 1, 'name', 'John Doe' ),
        ( 1, 'born', 'New York' )
    ON DUPLICATE KEY UPDATE val = VALUES(val);
我们需要一个关于userdataid的唯一索引,var,以便在重复键上工作

根据行大小和磁盘问题,此更改可能会带来可观的性能提升

请注意,如果不执行此修改,现有查询将不会产生错误-它们将自动失败

例如,这里我们修改两个用户的名称;一个在记录中有名称,另一个为空。第一个是修改的,第二个不是

mysql> SELECT * FROM usertable;
+------+-----------+-------------+------+------+
| id   | username  | name        | born | age  |
+------+-----------+-------------+------+------+
|    1 | jdoe      | John Doe    | NULL | NULL |
|    2 | jqaverage | NULL        | NULL | NULL |
|    3 | jtkilroy  | NULL        | NULL | NULL |
+------+-----------+-------------+------+------+
3 rows in set (0.00 sec)
mysql> UPDATE usertable SET name = 'John Doe II' WHERE username = 'jdoe';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
mysql> UPDATE usertable SET name = 'James T. Kilroy' WHERE username = 'jtkilroy';
Query OK, 0 rows affected (0.00 sec)
Rows matched: 0  Changed: 0  Warnings: 0
mysql> select * from usertable;
+------+-----------+-------------+------+------+
| id   | username  | name        | born | age  |
+------+-----------+-------------+------+------+
|    1 | jdoe      | John Doe II | NULL | NULL |
|    2 | jqaverage | NULL        | NULL | NULL |
|    3 | jtkilroy  | NULL        | NULL | NULL |
+------+-----------+-------------+------+------+
3 rows in set (0.00 sec)
要知道每行的排名,对于那些确实有排名的用户,我们只需检索每个id的userdata行数:

SELECT id, COUNT(*) AS rank FROM userdata GROUP BY id
现在,要按填充状态顺序提取行,我们需要执行以下操作:

SELECT usertable.* FROM usertable
    LEFT JOIN ( SELECT id, COUNT(*) AS rank FROM userdata GROUP BY id ) AS ranking
ON (usertable.id = ranking.id)
ORDER BY rank DESC, id;

左连接可确保无生气的个体也能被找回,另外,通过id进行排序可以确保具有相同等级的人总是以相同的顺序出现。

您能否提供一个表结构示例以及您正在使用/未使用的数据类型。该表很简单:从id开始,所有都是VARCHAR,最多200个字符。您想按照填写的数量进行排序吗每个记录一行中的字段数或每个表一列中填写的字段数?能否向我们提供一个表结构示例以及您正在使用/未使用的数据类型。该表很简单:以ID开头,所有字段都是VARCHAR,最大值为200个字符。是否要按每个记录一行中填写的字段数排序按每个表的列中填写的字段数计算?