هل تريد تحديد جميع الأعمدة باستثناء عمود واحد في MySQL؟

StackOverflow https://stackoverflow.com/questions/9122

  •  08-06-2019
  •  | 
  •  

سؤال

أحاول استخدام عبارة تحديد للحصول على جميع الأعمدة من جدول MySQL معين باستثناء عمود واحد.هل هناك طريقة بسيطة للقيام بذلك؟

يحرر:يوجد 53 عمودًا في هذا الجدول (ليس من تصميمي)

هل كانت مفيدة؟

المحلول

في الواقع هناك طريقة، تحتاج إلى الحصول على أذونات بالطبع للقيام بذلك ...

SET @sql = CONCAT('SELECT ', (SELECT REPLACE(GROUP_CONCAT(COLUMN_NAME), '<columns_to_omit>,', '') FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '<table>' AND TABLE_SCHEMA = '<database>'), ' FROM <table>');

PREPARE stmt1 FROM @sql;
EXECUTE stmt1;

استبدال <table>, <database> and <columns_to_omit>

نصائح أخرى

في تعريفات MySQL (يدوية) لا يوجد شيء من هذا القبيل.ولكن إذا كان لديك عدد كبير جدًا من الأعمدة col1, ..., col100, ، يمكن أن يكون ما يلي مفيدًا:

mysql> CREATE TEMPORARY TABLE temp_tb SELECT * FROM orig_tb;
mysql> ALTER TABLE temp_tb DROP col_x;
mysql> SELECT * FROM temp_tb;

هل سيعمل العرض بشكل أفضل في هذه الحالة؟

CREATE VIEW vwTable
as  
SELECT  
    col1  
    , col2  
    , col3  
    , col..  
    , col53  
FROM table

يمكنك ان تفعل:

SELECT column1, column2, column4 FROM table WHERE whatever

دون الحصول على column3، رغم أنك ربما كنت تبحث عن حل أكثر عمومية؟

إذا كنت تتطلع إلى استبعاد قيمة الحقل، على سبيل المثال.بالنسبة للمخاوف الأمنية/المعلومات الحساسة، يمكنك استرداد هذا العمود باعتباره خاليًا.

على سبيل المثال

SELECT *, NULL AS salary FROM users

على حد علمي، لا يوجد.يمكنك القيام بشيء مثل:

SELECT col1, col2, col3, col4 FROM tbl

واختر الأعمدة التي تريدها يدويًا.ومع ذلك، إذا كنت تريد الكثير من الأعمدة، فقد تحتاج فقط إلى القيام بما يلي:

SELECT * FROM tbl 

وتجاهل فقط ما لا تريده.

في حالتك الخاصة، أود أن أقترح:

SELECT * FROM tbl

إلا إذا كنت تريد بضعة أعمدة فقط.إذا كنت تريد أربعة أعمدة فقط، فقم بما يلي:

SELECT col3, col6, col45, col 52 FROM tbl

سيكون جيدًا، ولكن إذا كنت تريد 50 عمودًا، فإن أي كود يجعل الاستعلام سيصبح (أيضًا؟) صعب القراءة.

أثناء تجربة الحلول بواسطة @Mahomedalid و @Junaid وجدت مشكلة.لذلك فكرت في مشاركتها.إذا كان اسم العمود يحتوي على مسافات أو واصلات مثل تسجيل الوصول، فسيفشل الاستعلام.الحل البسيط هو استخدام علامة الرجوع حول أسماء الأعمدة.الاستعلام المعدل أدناه

SET @SQL = CONCAT('SELECT ', (SELECT GROUP_CONCAT(CONCAT("`", COLUMN_NAME, "`")) FROM
INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'users' AND COLUMN_NAME NOT IN ('id')), ' FROM users');
PREPARE stmt1 FROM @SQL;
EXECUTE stmt1;

إذا كان العمود الذي لا تريد تحديده يحتوي على كمية هائلة من البيانات، ولم ترغب في تضمينه بسبب مشكلات السرعة وكنت تحدد الأعمدة الأخرى في كثير من الأحيان، أقترح عليك إنشاء جدول جديد باستخدام الحقل الوحيد الذي لا تحدده عادةً باستخدام مفتاح الجدول الأصلي وقم بإزالة الحقل من الجدول الأصلي.انضم إلى الجداول عندما يكون هذا الحقل الإضافي مطلوبًا بالفعل.

يمكنك استخدام وصف my_table واستخدم نتائج ذلك لإنشاء عبارة SELECT ديناميكيًا.

مشكلتي الرئيسية هي الأعمدة العديدة التي أحصل عليها عند الانضمام إلى الجداول.في حين أن هذا ليس هو الجواب على سؤالك (كيفية تحديد جميع الأعمدة باستثناء بعض الأعمدة من واحد الجدول)، وأعتقد أنه من الجدير بالذكر أنه يمكنك تحديد table. للحصول على كافة الأعمدة من جدول معين، بدلاً من التحديد فقط .

فيما يلي مثال على كيف يمكن أن يكون هذا مفيدًا جدًا:

select users.*, phone.meta_value as phone, zipcode.meta_value as zipcode

from users

left join user_meta as phone
on ( (users.user_id = phone.user_id) AND (phone.meta_key = 'phone') )

left join user_meta as zipcode
on ( (users.user_id = zipcode.user_id) AND (zipcode.meta_key = 'zipcode') )

والنتيجة هي جميع الأعمدة من جدول المستخدمين، بالإضافة إلى عمودين إضافيين تم ضمهما من جدول التعريف.

أعجبني الجواب من @Mahomedalid إلى جانب هذه الحقيقة أبلغت في تعليق من @Bill Karwin.المشكلة المحتملة التي أثارها @Jan Koritak صحيح أنني واجهت ذلك ولكني وجدت خدعة لذلك وأريد فقط مشاركتها هنا لأي شخص يواجه المشكلة.

يمكننا استبدال وظيفة REPLACE بجملة حيث في الاستعلام الفرعي للبيان المعد مثل هذا:

باستخدام اسم الجدول والعمود الخاص بي

SET @SQL = CONCAT('SELECT ', (SELECT GROUP_CONCAT(COLUMN_NAME) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'users' AND COLUMN_NAME NOT IN ('id')), ' FROM users');
PREPARE stmt1 FROM @SQL;
EXECUTE stmt1;

لذلك، هذا سوف يستبعد المجال فقط id لكن لا company_id

نأمل أن يساعد هذا أي شخص يبحث عن حل.

يعتبر

من الممارسات الجيدة تحديد الأعمدة التي تقوم بالاستعلام عنها حتى لو قمت بالاستعلام عن كافة الأعمدة.

لذا أقترح عليك كتابة اسم كل عمود في البيان (باستثناء العمود الذي لا تريده).

SELECT
    col1
    , col2
    , col3
    , col..
    , col53

FROM table

فقط افعل

SELECT * FROM table WHERE whatever

ثم قم بإسقاط العمود بلغة البرمجة المفضلة لديك:بي أتش بي

while (($data = mysql_fetch_array($result, MYSQL_ASSOC)) !== FALSE) {
   unset($data["id"]);
   foreach ($data as $k => $v) { 
      echo"$v,";
   }      
}

أتفق مع الحل "البسيط" المتمثل في إدراج جميع الأعمدة، لكن هذا قد يكون مرهقًا، كما يمكن أن تتسبب الأخطاء المطبعية في إضاعة الكثير من الوقت.أستخدم وظيفة "getTableColumns" لاسترداد أسماء أعمدتي المناسبة للصقه في الاستعلام.ثم كل ما علي فعله هو حذف الأشخاص الذين لا أريدهم.

CREATE FUNCTION `getTableColumns`(tablename varchar(100)) 
          RETURNS varchar(5000) CHARSET latin1
BEGIN
  DECLARE done INT DEFAULT 0;
  DECLARE res  VARCHAR(5000) DEFAULT "";

  DECLARE col  VARCHAR(200);
  DECLARE cur1 CURSOR FOR 
    select COLUMN_NAME from information_schema.columns 
    where TABLE_NAME=@table AND TABLE_SCHEMA="yourdatabase" ORDER BY ORDINAL_POSITION;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
  OPEN cur1;
  REPEAT
       FETCH cur1 INTO col;
       IF NOT done THEN 
          set res = CONCAT(res,IF(LENGTH(res)>0,",",""),col);
       END IF;
    UNTIL done END REPEAT;
  CLOSE cur1;
  RETURN res;

تُرجع النتيجة سلسلة مفصولة بفواصل، على سبيل المثال...

col1,col2,col3,col4,...col53

أوافق على أنه لا يكفي Select *, ، إذا كان هذا الشيء الذي لا تحتاجه، كما هو مذكور في مكان آخر، هو BLOB، فأنت لا تريد أن تتسلل هذه النفقات العامة.

سأقوم بإنشاء منظر مع البيانات المطلوبة، ثم يمكنك Select * براحة - إذا كان برنامج قاعدة البيانات يدعمهم.وإلا، ضع البيانات الضخمة في جدول آخر.

في البداية اعتقدت أنه يمكنك استخدام التعبيرات العادية، ولكن بينما كنت أقرأ مستندات ماي إس كيو إل يبدو أنك لا تستطيع ذلك.لو كنت مكانك لاستخدمت لغة أخرى (مثل PHP) لإنشاء قائمة بالأعمدة التي تريد الحصول عليها، وتخزينها كسلسلة ثم استخدامها لإنشاء SQL.

أردت هذا أيضًا لذا قمت بإنشاء وظيفة بدلاً من ذلك.

public function getColsExcept($table,$remove){
    $res =mysql_query("SHOW COLUMNS FROM $table");

    while($arr = mysql_fetch_assoc($res)){
        $cols[] = $arr['Field'];
    }
    if(is_array($remove)){
        $newCols = array_diff($cols,$remove);
        return "`".implode("`,`",$newCols)."`";
    }else{
        $length = count($cols);
        for($i=0;$i<$length;$i++){
            if($cols[$i] == $remove)
                unset($cols[$i]);
        }
        return "`".implode("`,`",$cols)."`";
    }
}

إذن كيف يعمل الأمر هو أن تدخل الجدول، ثم العمود الذي لا تريده أو كما هو الحال في المصفوفة:صفيف ("المعرف"، "الاسم"، "أي عمود")

لذلك في التحديد يمكنك استخدامه مثل هذا:

mysql_query("SELECT ".$db->getColsExcept('table',array('id','bigtextcolumn'))." FROM table");

أو

mysql_query("SELECT ".$db->getColsExcept('table','bigtextcolumn')." FROM table");

أتفق مع إجابة @ Mahomedalid.لكنني لم أرغب في القيام بشيء مثل البيان المجهز ولم أرغب في كتابة جميع الحقول.إذن ما كان لدي كان حلاً سخيفًا.انتقل إلى الجدول في phpmyadmin->sql->select، حيث يقوم بتفريغ نسخة الاستعلام واستبدالها ويتم ذلك!:)

بينما أتفق مع إجابة توماس (+1؛))، أود أن أضيف التحذير بأنني سأفترض العمود الذي لا Want يحتوي بالكاد على أي بيانات.إذا كان يحتوي على كميات هائلة من النص أو XML أو النقط الثنائية، فخذ الوقت الكافي لتحديد كل عمود على حدة.أدائك سوف يعاني خلاف ذلك.هتافات!

نعم، على الرغم من أنه يمكن أن يكون الإدخال/الإخراج مرتفعًا اعتمادًا على الجدول، فإليك الحل البديل الذي وجدته لذلك.

Select *
into #temp
from table

alter table #temp drop column column_name

Select *
from #temp

الإجابة التي نشرها محمداليد بها مشكلة صغيرة:

تم استبدال رمز وظيفة الاستبدال الداخلي "<columns_to_delete>,"بواسطة ""، يواجه هذا الاستبدال مشكلة إذا كان الحقل المراد استبداله هو الحقل الأخير في السلسلة المترابطة نظرًا لأن الحقل الأخير لا يحتوي على فاصلة char ""، ولم تتم إزالته من السلسلة.

اقتراحي:

SET @sql = CONCAT('SELECT ', (SELECT REPLACE(GROUP_CONCAT(COLUMN_NAME),
                  '<columns_to_delete>', '\'FIELD_REMOVED\'')
           FROM INFORMATION_SCHEMA.COLUMNS
           WHERE TABLE_NAME = '<table>'
             AND TABLE_SCHEMA = '<database>'), ' FROM <table>');

استبدال <table>, <database> و `

يتم استبدال العمود الذي تمت إزالته بالسلسلة "FIELD_REMOVED" في حالتي، وهذا يعمل لأنني كنت أحاول تأمين الذاكرة.(الحقل الذي كنت أقوم بإزالته هو BLOB يبلغ حجمه حوالي 1 ميجابايت)

بناءً على إجابة @Mahomedalid، قمت ببعض التحسينات لدعم "تحديد جميع الأعمدة باستثناء بعضها في MySQL"

SET @database    = 'database_name';
SET @tablename   = 'table_name';
SET @cols2delete = 'col1,col2,col3';

SET @sql = CONCAT(
'SELECT ', 
(
    SELECT GROUP_CONCAT( IF(FIND_IN_SET(COLUMN_NAME, @cols2delete), NULL, COLUMN_NAME ) )
    FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @tablename AND TABLE_SCHEMA = @database
), 
' FROM ',
@tablename);

SELECT @sql;

إذا كان لديك الكثير من الأعمدة، استخدم SQL هذا لتغيير group_concat_max_len

SET @@group_concat_max_len = 2048;

ربما يكون لدي حل ل جان كوريتاك وأشار التناقض

SELECT CONCAT('SELECT ',
( SELECT GROUP_CONCAT(t.col)
FROM
(
    SELECT CASE
    WHEN COLUMN_NAME = 'eid' THEN NULL
    ELSE COLUMN_NAME
    END AS col 
    FROM INFORMATION_SCHEMA.COLUMNS 
    WHERE TABLE_NAME = 'employee' AND TABLE_SCHEMA = 'test'
) t
WHERE t.col IS NOT NULL) ,
' FROM employee' );

طاولة :

SELECT table_name,column_name 
FROM INFORMATION_SCHEMA.COLUMNS 
WHERE TABLE_NAME = 'employee' AND TABLE_SCHEMA = 'test'

================================

table_name  column_name
employee    eid
employee    name_eid
employee    sal

================================

نتيجة الاستعلام:

'SELECT name_eid,sal FROM employee'

إذا كان دائمًا نفس العمود، فيمكنك إنشاء طريقة عرض لا تحتوي عليه.

غير ذلك، لا، لا أعتقد ذلك.

يمكنك استخدام SQL لإنشاء SQL إذا أردت وتقييم SQL الذي ينتجه.يعد هذا حلاً عامًا لأنه يستخرج أسماء الأعمدة من مخطط المعلومات.فيما يلي مثال من سطر أوامر Unix.

أستعاض

  • MYSQL باستخدام أمر mysql الخاص بك
  • TABLE مع اسم الجدول
  • الحقل المستبعد مع اسم الحقل المستبعد
echo $(echo 'select concat("select ", group_concat(column_name) , " from TABLE") from information_schema.columns where table_name="TABLE" and column_name != "EXCLUDEDFIELD" group by "t"' | MYSQL | tail -n 1) | MYSQL

ستحتاج حقًا إلى استخراج أسماء الأعمدة بهذه الطريقة مرة واحدة فقط لإنشاء قائمة الأعمدة التي تستبعد هذا العمود، ثم استخدم الاستعلام الذي قمت بإنشائه فقط.

لذلك شيء مثل:

column_list=$(echo 'select group_concat(column_name) from information_schema.columns where table_name="TABLE" and column_name != "EXCLUDEDFIELD" group by "t"' | MYSQL | tail -n 1)

الآن يمكنك إعادة استخدام $column_list سلسلة في الاستعلامات التي تقوم بإنشائها.

أود أن أضيف وجهة نظر أخرى لحل هذه المشكلة، خاصة إذا كان لديك عدد قليل من الأعمدة التي تريد إزالتها.

يمكنك استخدام أداة قاعدة البيانات مثل منضدة MySQL من أجل إنشاء عبارة التحديد لك، لذا عليك فقط إزالة تلك الأعمدة يدويًا للعبارة التي تم إنشاؤها ونسخها إلى برنامج SQL النصي الخاص بك.

في MySQL Workbench طريقة إنشائه هي:

انقر بزر الماوس الأيمن على الجدول -> أرسل إلى محرر Sql -> حدد كل البيان.

الإجابة المقبولة بها عدة عيوب.

  • يفشل عندما تتطلب أسماء الجدول أو الأعمدة علامات عكسية
  • يفشل إذا كان العمود الذي تريد حذفه هو الأخير في القائمة
  • يتطلب إدراج اسم الجدول مرتين (مرة للتحديد وأخرى لنص الاستعلام) وهو أمر زائد عن الحاجة وغير ضروري
  • من المحتمل أن يُرجع أسماء الأعمدة في ملف ترتيب خاطئ

يمكن التغلب على كل هذه المشكلات ببساطة عن طريق تضمين علامات التراجع في ملف SEPARATOR من اجلك GROUP_CONCAT واستخدام أ WHERE شرط بدلا من REPLACE().لأغراضي (وأنا أتخيل العديد من الأغراض الأخرى) كنت أرغب في إرجاع أسماء الأعمدة بنفس الترتيب الذي تظهر به في الجدول نفسه.لتحقيق ذلك، هنا نستخدم صريحة ORDER BY جملة داخل GROUP_CONCAT() وظيفة:

SELECT CONCAT(
    'SELECT `',
    GROUP_CONCAT(COLUMN_NAME ORDER BY `ORDINAL_POSITION` SEPARATOR '`,`'),
    '` FROM `',
    `TABLE_SCHEMA`,
    '`.`',
    TABLE_NAME,
    '`;'
)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE `TABLE_SCHEMA` = 'my_database'
    AND `TABLE_NAME` = 'my_table'
    AND `COLUMN_NAME` != 'column_to_omit';

لقد تأخرت جدًا في تقديم إجابة لهذا، ضع هذه هي الطريقة التي اتبعتها دائمًا وبصراحة، إنها أفضل وأكثر دقة 100 مرة من أفضل إجابة، وآمل فقط أن يراها شخص ما.وتجدها مفيدة

    //create an array, we will call it here. 
    $here = array();
    //create an SQL query in order to get all of the column names
    $SQL = "SHOW COLUMNS FROM Table";
        //put all of the column names in the array
        foreach($conn->query($SQL) as $row) {
            $here[] = $row[0];
        }
    //now search through the array containing the column names for the name of the column, in this case i used the common ID field as an example
    $key = array_search('ID', $here);
    //now delete the entry
    unset($here[$key]);

حدد * هو نمط مضاد لـ SQL.لا ينبغي استخدامه في كود الإنتاج لعدة أسباب منها:

تستغرق المعالجة وقتًا أطول قليلاً.عندما يتم تشغيل الأشياء ملايين المرات، يمكن لهذه الأجزاء الصغيرة أن تكون ذات أهمية.قاعدة البيانات البطيئة التي يحدث فيها البطء بسبب هذا النوع من الترميز غير المتقن طوال الوقت هي أصعب نوع في ضبط الأداء.

هذا يعني أنك ربما ترسل بيانات أكثر مما تحتاج إليه مما يسبب اختناقات في الخادم والشبكة.إذا كان لديك صلة داخلية، فإن فرص إرسال بيانات أكثر مما تحتاجه هي 100%.

إنه يسبب مشاكل في الصيانة خاصة عند إضافة أعمدة جديدة لا تريد رؤيتها في كل مكان.علاوة على ذلك، إذا كان لديك عمود جديد، فقد تحتاج إلى القيام بشيء ما بالواجهة لتحديد ما يجب فعله بهذا العمود.

يمكنه كسر طرق العرض (أعلم أن هذا صحيح في خادم SQl، وقد يكون أو لا يكون صحيحًا في MySQL).

إذا كان شخص ما سخيفًا بما يكفي لإعادة إنشاء الجداول باستخدام الأعمدة بترتيب مختلف (وهو ما لا ينبغي عليك فعله ولكنه يحدث طوال الوقت)، فيمكن أن تنكسر جميع أنواع التعليمات البرمجية.بشكل خاص، رمز للإدراج على سبيل المثال حيث تقوم فجأة بوضع المدينة في حقل العنوان_3 لأنه بدون تحديد، يمكن لقاعدة البيانات أن تعمل فقط بترتيب الأعمدة.يعد هذا أمرًا سيئًا بدرجة كافية عندما تتغير أنواع البيانات ولكنه يكون أسوأ عندما تحتوي الأعمدة التي تم تبديلها على نفس نوع البيانات لأنه يمكنك إدخال بيانات سيئة في وقت ما مما يمثل فوضى في التنظيف.أنت بحاجة إلى الاهتمام بسلامة البيانات.

إذا تم استخدامه في إدراج، فسيتم قطع الإدراج إذا تمت إضافة عمود جديد في جدول واحد دون الجدول الآخر.

قد يكسر المشغلات.قد يكون من الصعب تشخيص مشاكل الزناد.

أضف كل هذا مقابل الوقت الذي تستغرقه إضافة أسماء الأعمدة (حتى أنه قد يكون لديك واجهة تسمح لك بالسحب فوق أسماء الأعمدة (أعلم أنني أفعل ذلك في SQL Server، وأراهن أن هناك طريقة ما لذلك افعل هذه إحدى الأدوات التي تستخدمها لكتابة استعلامات mysql.) دعنا نرى، "يمكنني أن أتسبب في مشكلات في الصيانة، ويمكنني أن أتسبب في مشكلات في الأداء، ويمكنني أن أتسبب في مشكلات في سلامة البيانات، لكنني وفرت خمس دقائق من وقت التطوير". في الأعمدة المحددة التي تريدها.

كما أنصحك بقراءة هذا الكتاب:http://www.amazon.com/SQL-Antipatterns-Programming-Pragmatic-Programmers-ebook/dp/B00A376BB2/ref=sr_1_1?s=digital-text&ie=UTF8&qid=1389896688&sr=1-1&keywords=sql+antipatterns

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top