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
是否要按行中填充字段數(每個記錄)或填充字段數一列(每桌)? –