MySQL查询顺序我有一个表女巫有45列,但尚未完成只有几个。这个表是不断更新和添加等。在我的自动完成功能,我想选择这些记录排序最完整的领域(我希望你明白)?以“最全领域”
解决的办法之一是创建另一个(下称“等级”字段),并创建一个PHP函数,选择*记录,并给出每个记录的等级。
...但我想知道是否有这样做只是白衣一个ORDER BY的一个更简单的方法?
MySQL查询顺序我有一个表女巫有45列,但尚未完成只有几个。这个表是不断更新和添加等。在我的自动完成功能,我想选择这些记录排序最完整的领域(我希望你明白)?以“最全领域”
解决的办法之一是创建另一个(下称“等级”字段),并创建一个PHP函数,选择*记录,并给出每个记录的等级。
...但我想知道是否有这样做只是白衣一个ORDER BY的一个更简单的方法?
MySQL有没有功能,指望一排非NULL字段数,据我所知。
所以,我能想到的唯一的办法就是使用一个明确的条件:
SELECT * FROM mytable
ORDER BY (IF(column1 IS NULL, 0, 1)
+IF(column2 IS NULL, 0, 1)
...
+IF(column45 IS NULL, 0, 1)) DESC;
...它是丑陋的罪过,但应该做的伎俩。
你也可以设计一个触发器来增加一个额外的列“fields_filled”。触发器花费在UPDATE
上,45个IF对你造成伤害SELECT
;你必须建立更方便的模型。
请注意,索引所有字段以加快SELECT
会在更新时花费你(并且45个不同的索引的成本可能高于select上的表扫描,而不是索引字段是VARCHAR
)。运行一些测试,但我相信45-IF解决方案可能是最好的整体。
UPDATE: 如果可以返工你的表结构在一定程度上规范它,你可以把领域的my_values
表。然后你会有一个“头表”(也许只有一个唯一的ID)和一个“数据表”。空字段根本不存在,然后您可以通过使用RIGHT JOIN
来排序填充字段的数量,用COUNT()
对填充字段进行计数。这也会大大加快UPDATE
操作,并且可以让您有效地使用索引。
实例(从表设置两个规范化表设置):
让我们说我们有一组Customer
记录。我们将有一小段“强制性”数据,如ID,用户名,密码,电子邮件等。那么我们可能会有更多的“可选”数据子集,如昵称,头像,出生日期等。作为第一步,让我们假设所有这些数据都是varchar
(与其中每列可能有自己的数据类型的单表解决方案相比,这初看起来似乎是一个限制)。
所以我们有一个表像,
ID username ....
1 jdoe etc.
2 jqaverage etc.
3 jkilroy etc.
然后我们有可选的数据表。这里John Doe填补了所有领域,Joe Q.平均只有两个,而Kilroy没有(即使他在这里是)。
userid var val
1 name John
1 born Stratford-upon-Avon
1 when 11-07-1974
2 name Joe Quentin
2 when 09-04-1962
为了再现在MySQL中“单个表”的输出,我们必须创建一个相当复杂的VIEW
有很多LEFT JOIN
秒。这种观点将仍然是非常快的,如果我们有一个基于(userid, var)
(甚至更好,如果我们用一个数字常量或SET而不是一个varchar的为var
数据类型的索引:
CREATE OR REPLACE VIEW usertable AS SELECT users.*,
names.val AS name // (1)
FROM users
LEFT JOIN userdata AS names ON (users.id = names.id AND names.var = 'name') // (2)
;
每个字段在我们的逻辑模型,例如,“名称”将包含在可选数据表中的元组(id,'name',value)中
并且它将产生表格中的一行,上面的查询,参考部分的线的形式LEFT JOIN userdata AS <FIELDNAME>s ON (users.id = <FIELDNAME>s.id AND <FIELDNAME>s.var = '<FIELDNAME>')
的(2)。因此,我们可以动态地通过用动态部1,TEX级联上述查询的第一个TextLine构造查询T'从用户的和动态建成第二节
一旦我们做到这一点,选择在视图上是完全相同之前 - 但现在他们取两个规范化表通过JOIN的数据。
EXPLAIN SELECT * FROM usertable;
会告诉我们,添加列到这个设置并不明显减缓行动,即,这个解决方案适用还算不错。我们要么更新强制性数据表,要么更新可选数据表的单个行。我们需要修改INSERT(我们只插入强制性数据,并且只在第一个表中)和UPDATE:但是如果目标行不在那里,那么它必须被插入。
所以我们必须用 'UPSERT' 来代替
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);
(我们需要一个UNIQUE INDEX on userdata(id, var)
为ON DUPLICATE KEY
工作)。
取决于行大小和磁盘问题,这种变化可能会产生可观的性能增益。
请注意,如果未执行此修改,现有查询将不会产生错误 - 它们将悄然失败。
这里有个例子,我们修改两个用户的名称;一个在记录上有一个名字,另一个有NULL。第一个是修改的,第二个不是。
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计数:
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;
的LEFT JOIN
确保rankless个人得到检索过,并通过id
额外的排序确保人们以identica l排名总是以相同的顺序出来。
是的,谢谢。这是最好的答案! – faq
你能向我们提供您的表结构的一个样本,你使用/不使用的数据类型。 –
该表格很简单:启动白名称,并且它们都是VARCHAR白名单最多200个字符 – faq
是否要按行中填充字段数(每个记录)或填充字段数一列(每桌)? –