जहाँ तक मुझे पता है, 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;
...यह पाप के रूप में बदसूरत है, लेकिन चाल चलनी चाहिए।
आप एक अतिरिक्त कॉलम "फ़ील्ड_फिल्ड" को बढ़ाने के लिए एक TRIGGER भी तैयार कर सकते हैं। UPDATE
. को ट्रिगर की कीमत आपको चुकानी होगी , 45 IFs ने आपको SELECT
. पर चोट पहुंचाई है; आपको वह मॉडल बनाना होगा जो अधिक सुविधाजनक हो।
ध्यान दें कि SELECT
को तेज़ करने के लिए सभी फ़ील्ड को इंडेक्स करना अपडेट करते समय आपको खर्च करना होगा (और 45 अलग-अलग इंडेक्स की कीमत संभवतः एक टेबल स्कैन जितनी है, यह कहने के लिए नहीं कि अनुक्रमित फ़ील्ड एक VARCHAR
है ) कुछ परीक्षण चलाएं, लेकिन मेरा मानना है कि 45-IF समाधान समग्र रूप से सर्वश्रेष्ठ होने की संभावना है।
अपडेट करें :अगर आप अपनी तालिका संरचना को कुछ हद तक सामान्य करने के लिए फिर से काम कर सकते हैं, आप फ़ील्ड को my_values
में रख सकते हैं मेज़। फिर आपके पास "हेडर टेबल" (शायद केवल एक अद्वितीय आईडी के साथ) और "डेटा टेबल" होगा। खाली फ़ील्ड बिल्कुल मौजूद नहीं होंगे, और फिर आप RIGHT JOIN
का उपयोग करके सॉर्ट कर सकते हैं कि कितने भरे हुए फ़ील्ड हैं , भरे हुए फ़ील्ड को COUNT()
. से गिनना . इससे UPDATE
में भी काफी तेजी आएगी संचालन, और आपको अनुक्रमणिका को कुशलतापूर्वक नियोजित करने की अनुमति देगा।
उदाहरण (तालिका सेटअप से दो सामान्यीकृत तालिका सेटअप तक) :
मान लें कि हमारे पास Customer
. का एक सेट है रिकॉर्ड। हमारे पास "अनिवार्य" डेटा का एक छोटा सबसेट होगा जैसे कि आईडी, उपयोगकर्ता नाम, पासवर्ड, ईमेल, आदि; तब हमारे पास "वैकल्पिक" डेटा का एक बहुत बड़ा उपसमुच्चय होगा जैसे उपनाम, अवतार, जन्म तिथि, और इसी तरह। पहले चरण के रूप में हम मान लेते हैं कि ये सभी डेटा varchar
. हैं (यह, पहली नजर में, एकल तालिका समाधान की तुलना में एक सीमा की तरह दिखता है जहां प्रत्येक कॉलम का अपना डेटाटाइप हो सकता है)।
तो हमारे पास एक टेबल है जैसे,
ID username ....
1 jdoe etc.
2 jqaverage etc.
3 jkilroy etc.
फिर हमारे पास वैकल्पिक-डेटा तालिका है। यहां जॉन डो ने सभी फ़ील्ड भरे हैं, जो क्यू। औसत केवल दो, और किलरॉय कोई नहीं (भले ही वह था था) यहाँ)।
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)
पर आधारित अनुक्रमणिका है (और भी बेहतर अगर हम var
के डेटाटाइप के लिए वर्चर के बजाय संख्यात्मक स्थिरांक या SET का उपयोग करते हैं :
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 ) में समाहित होगा।
और यह <FIELDNAME>s.val AS <FIELDNAME>
फॉर्म की एक लाइन देगा उपरोक्त क्वेरी के सेक्शन (1) में, LEFT JOIN userdata AS <FIELDNAME>s ON ( users.id = <FIELDNAME>s.id AND <FIELDNAME>s.var = '<FIELDNAME>')
खंड (2) में। इसलिए हम उपरोक्त क्वेरी की पहली टेक्स्टलाइन को डायनेमिक सेक्शन 1, टेक्स्ट 'FROM यूजर्स' और डायनामिकली-बिल्ट सेक्शन 2 के साथ जोड़कर डायनेमिक रूप से क्वेरी का निर्माण कर सकते हैं।
एक बार जब हम ऐसा कर लेते हैं, तो दृश्य पर चयन बिल्कुल पहले के समान होते हैं - लेकिन अब वे जॉइन के माध्यम से दो सामान्यीकृत तालिकाओं से डेटा प्राप्त करते हैं।
EXPLAIN SELECT * FROM usertable;
हमें बताएगा कि इस सेटअप में कॉलम जोड़ने से परिचालन की गति धीमी नहीं होती है, यानी, यह समाधान उचित रूप से स्केल करता है।
INSERTs को संशोधित करना होगा (हम केवल अनिवार्य डेटा सम्मिलित करते हैं, और केवल पहली तालिका में) और अद्यतन भी:हम या तो अनिवार्य डेटा तालिका, या वैकल्पिक डेटा तालिका की एक पंक्ति को अद्यतन करते हैं। लेकिन अगर लक्ष्य पंक्ति नहीं है, तो उसे INSERTed किया जाना चाहिए।
इसलिए हमें बदलना होगा
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);
(हमें उपयोगकर्ता डेटा (आईडी, var) पर एक UNIQUE INDEX on userdata(id, var)
ON DUPLICATE KEY
. के लिए काम करने के लिए)।
पंक्ति के आकार और डिस्क की समस्याओं के आधार पर, यह परिवर्तन एक सराहनीय प्रदर्शन लाभ प्राप्त कर सकता है।
ध्यान दें कि यदि यह संशोधन नहीं किया जाता है, तो मौजूदा क्वेरी में त्रुटियां नहीं होंगी - वे चुपचाप विफल हो जाएंगी ।
यहाँ उदाहरण के लिए हम दो उपयोगकर्ताओं के नाम संशोधित करते हैं; एक के पास रिकॉर्ड पर नाम है, दूसरे के पास न्यूल है। पहला संशोधित है, दूसरा नहीं है।
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)
प्रत्येक पंक्ति की रैंक जानने के लिए, उन उपयोगकर्ताओं के लिए जिनके पास रैंक है, हम बस प्रति आईडी उपयोगकर्ता डेटा पंक्तियों की संख्या प्राप्त करते हैं:
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
यह सुनिश्चित करता है कि रैंकहीन व्यक्तियों को भी पुनः प्राप्त किया जाए, और id
. द्वारा अतिरिक्त आदेश दिया जाए सुनिश्चित करता है कि समान रैंक वाले लोग हमेशा एक ही क्रम में बाहर आएं।