เลือกคอลัมน์ทั้งหมดยกเว้นคอลัมน์เดียวใน MySQL?


365

ฉันพยายามใช้คำสั่ง select เพื่อรับคอลัมน์ทั้งหมดจากตาราง MySQL ยกเว้นหนึ่ง มีวิธีง่าย ๆ ในการทำเช่นนี้?

แก้ไข: มี 53 คอลัมน์ในตารางนี้ (ไม่ใช่การออกแบบของฉัน)


6
53 คอลัมน์ ฉันจะใช้ SELECT * ตามที่โธมัสแนะนำในกรณีนี้ ... เว้นแต่ว่าคอลัมน์พิเศษนั้นจะมีข้อมูลจำนวนมากที่ไม่พึงประสงค์ในการเรียกคืน ... ?
Mike Stone

ยกเว้นหนึ่ง colum ... ฉันคิดว่าคุณรู้ว่าควรจะละเว้นสิ่งใดดังนั้น Information_SCHEMA.columns จึงเป็นแนวทาง
Alfabravo

ลองอ่านคำตอบนี้ดูสิว่าคุณต้องการทำอะไร!
donL

คอลัมน์ข้อมูลขนาดใหญ่เป็นปัญหาจริงเมื่อเก็บข้อมูลทางภูมิศาสตร์ คอลัมน์สามารถมีขนาดได้หลายเมกะไบต์ มันทำงานได้ดีในที่ที่คำสั่งในการค้นหาแถว แต่คุณมักไม่ต้องการข้อมูลในผลลัพธ์
เจสัน

การใช้งานทั่วไปสำหรับสิ่งนี้คือการแยกคอลัมน์รหัสการเพิ่มขึ้นอัตโนมัติ ตัวอย่างเช่นเมื่อต้องการเลือกข้อมูลที่จะแทรกลงในตารางอื่นซึ่งมี ID ของตัวเอง
ToolmakerSteve

คำตอบ:


222

จริงๆแล้วมีวิธีหนึ่งคุณจำเป็นต้องได้รับการอนุญาตอย่างแน่นอนสำหรับการทำเช่นนี้ ...

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>


20
ข้อแม้: การสืบค้น Information_SCHEMA นั้นมีประสิทธิภาพค่อนข้างต่ำดังนั้นโปรดระวังแบบสอบถามประเภทนี้ไม่ได้อยู่ในเส้นทางที่สำคัญสำหรับสิ่งใด
Bill Karwin

9
เช่นเดียวกับ @Jan Koritak ที่กล่าวไว้ด้านล่างคำตอบนี้จะไม่ทำงานหากคอลัมน์ของชื่อที่คุณต้องการลบนั้นเป็นซับสตริงของชื่อสำหรับคอลัมน์ใด ๆ ที่คุณต้องการเก็บไว้ด้วย มีคำตอบที่ดีกว่าที่มีความคล้ายคลึงกับที่สามารถพบได้ที่นี่คือ
donL

8
นี่เป็นวิธีที่เลวร้ายยิ่งกว่าการระบุคอลัมน์ที่เป็นวิธีปฏิบัติที่ดีที่สุดที่รู้จักกันดี
HLGEM

3
วิธีนี้ใช้ไม่ได้หากมีช่องว่างในชื่อคอลัมน์ ควรอัปเดตเพื่อล้อมรอบชื่อใน backticks <column_name>
เสมอ

3
สิ่งนี้จะไม่ทำงานหากคอลัมน์ที่จะถูกเพิกเฉยคือคอลัมน์สุดท้ายที่แสดงในโครงสร้างตาราง (เนื่องจากการแทนที่จะไม่ตรงกับอาการโคม่าที่ต่อท้าย)
Vincent Pazeller

61

ในคำจำกัดความ mysql (ด้วยตนเอง) ไม่มีสิ่งนั้น แต่ถ้าคุณมีคอลัมน์จำนวนมากจริงๆcol1... , col100ต่อไปนี้จะเป็นประโยชน์:

DROP TABLE IF EXISTS temp_tb;
CREATE TEMPORARY TABLE ENGINE=MEMORY temp_tb SELECT * FROM orig_tb;
ALTER TABLE temp_tb DROP col_x;
SELECT * FROM temp_tb;

4
ให้ข้อความแสดงข้อผิดพลาดในขั้นตอนที่ 3: "จำนวนคอลัมน์ไม่ตรงกับจำนวนค่าที่แถว 1" ดังนั้นฉันจึงเปลี่ยนขั้นตอนที่ 2 เป็น "UPDATE temp_tb SET id = NULL" แล้วก็ใช้งานได้
oyvey

1
ตกลงใช้งานได้ แต่เมื่อฉันเรียกใช้แบบสอบถามนี้อีกครั้งมันทำให้ฉันมีข้อผิดพลาดนั่นคือ temp_tb มีอยู่แล้ว temp_tb อยู่ในหน่วยความจำนานเท่าใด ขอโทษถ้ามันเป็นคำถามที่โง่ ป.ล. ตอบโต้คำตอบของคุณ
Karan

2
@ Karan หากต้องการเรียกใช้แบบสอบถามนี้ซ้ำ ๆ ให้เพิ่มคำสั่งอื่นไปที่จุดเริ่มต้น:DROP TABLE IF EXISTS temp_tb;
gregn3

1
@Karan ในการระบุเอ็นจิ้นหน่วยความจำให้ใช้คำสั่ง: CREATE TEMPORARY TABLE temp_tb ENGINE=MEMORY (SELECT * FROM orig_tb); ไม่เช่นนั้นมันจะถูกบันทึกลงดิสก์โดยค่าเริ่มต้นและจะมีการรีสตาร์ทเซิร์ฟเวอร์ ( ขอบคุณ )
gregn3

คำตอบที่ยอดเยี่ยม สำหรับการวางหลายคอลัมน์อ้างอิงคำตอบนี้
S3DEV

45

มุมมองจะทำงานได้ดีขึ้นในกรณีนี้หรือไม่

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

15
ฮ่า ๆ ! ใช่แน่นอน. ตอนนี้คุณจะสร้างมุมมองเพื่อรวมทั้งหมด แต่หนึ่งในคอลัมน์ได้อย่างไร ฉันคิดว่าคุณเห็นว่าสิ่งนี้ทำให้เกิดคำถามเดิม ที่จริงแล้วฉันพบกระทู้นี้โดยเฉพาะเพราะฉันต้องการสร้างมุมมองที่ยกเว้นคอลัมน์บางคอลัมน์โดยไม่ถูกบังคับให้แสดงรายการคอลัมน์ที่เหลือทั้งหมดอย่างชัดเจนในคำจำกัดความมุมมอง
Chris Nadovich

31

คุณทำได้:

SELECT column1, column2, column4 FROM table WHERE whatever

โดยไม่ได้รับ column3 แม้ว่าบางทีคุณกำลังมองหาวิธีแก้ปัญหาทั่วไปเพิ่มเติมหรือไม่


3
คำตอบที่ได้รับคะแนนสูงที่สุดส่วนใหญ่เป็นเพียงการหาวิธีสร้างแบบสอบถามที่แน่นอนนี้โดยไม่ต้องพิมพ์ด้วยมือ
mehtunguh

5
ที่จริงแล้วด้วยเหตุผลการบำรุงรักษามีประโยชน์ที่จะมีคำสั่ง "ทุกอย่างยกเว้น" มิฉะนั้นจะต้องอัปเดตรายการฟิลด์ที่ชัดเจนหากมีการเพิ่มฟิลด์ใหม่ในภายหลัง
leiavoia

1
@lev ที่ถูกต้องและพวกเขาควรจะ !!! โปรดทราบว่าคุณไม่ทราบว่าคุณต้องการมีคอลัมน์ในอนาคตหรือไม่ (อาจเป็นคอลัมน์ข้อมูลเมตาหรือรายการที่ไม่ใช้กับหน้าจอเฉพาะ) คุณไม่; ต้องการเป็นอันตรายต่อประสิทธิภาพการทำงานโดยส่งคืนมากกว่าที่คุณต้องการ (ซึ่งเป็นจริง 100% ของเวลาเมื่อคุณมีการรวมภายใน) ฉันขอแนะนำให้คุณอ่านบางอย่างว่าเหตุใด select * จึงเป็น SQL antipattern
HLGEM

26
สถานะ OP มี> 50 คอลัมน์ดังนั้นนี่จึงเป็นไปไม่ได้เลย
สิงหาคม

1
@HLGEM ไม่จริงฉันต้องการเลือกคอลัมน์ทั้งหมดโดยไม่รักษาข้อความค้นหาทุกครั้งที่ฉันเพิ่มคอลัมน์ใหม่ยกเว้นคอลัมน์ใดคอลัมน์หนึ่งและสิ่งนี้จะไม่ทำงานในกรณีของฉัน แต่อย่างไรก็ตามฉันใช้โซลูชันของ Sean O ด้วยตัวเอง
OverCoder

26

หากคุณต้องการยกเว้นค่าของเขตข้อมูลเช่นเกี่ยวกับความปลอดภัย / ข้อมูลที่ละเอียดอ่อนคุณสามารถดึงข้อมูลคอลัมน์นั้นเป็นค่าว่าง

เช่น

SELECT *, NULL AS salary FROM users

13
ทำไม? มันไม่ทำงาน หากคุณมีเงินเดือนคอลัมน์แบบสอบถามนี้จะจบลงด้วยผลลัพธ์ที่มีสองคอลัมน์ชื่อเงินเดือนหนึ่งเต็มไปด้วยโมฆะและหนึ่งที่มีเงินเดือนที่แท้จริง
Myforwik

4
@Myforwik แบบสอบถามนี้แน่นอนเพิ่มsalaryคอลัมน์ที่สอง แต่เนื่องจากมันถูกค้นคืนหลังจาก * มันจะเขียนทับต้นฉบับ มันไม่สวย แต่ใช้งานได้
Sean O

67
SQL อนุญาตให้ชื่อคอลัมน์ซ้ำกันเสมอในชุดผลลัพธ์ หากคุณต้องการให้มันใช้งานได้คุณจะต้องรันมันด้วยแอพพลิเคชั่นไคลเอนต์ที่ไม่รองรับการใช้งานแบบสองทางและให้ความสำคัญกับงานที่ผ่านมา ไคลเอนต์บรรทัดคำสั่งอย่างเป็นทางการรองรับการใช้งานซ้ำ HeidiSQL ก็รองรับเช่นกัน SQL Fiddleไม่ได้ แต่จะแสดงรายการล่อลวงครั้งแรกไม่ใช่ครั้งสุดท้าย เพื่อสรุป: นี้ไม่ได้ทำงาน
ÁlvaroGonzález

9
แน่นอนมันไม่ทำงาน นี่เป็นตัวอย่างที่ดีว่าทำไมคุณควรทดสอบคำตอบของคุณใน mysql แทนการใช้ไลบรารี่ที่คุยกับ mysql
Myforwik

8
@SeanO, @ Alastair, @ ทุกคนไม่ได้แทนที่ เซิร์ฟเวอร์ยังคงส่งคืนข้อมูลที่ละเอียดอ่อน
Pacerier

22

เท่าที่ฉันรู้ คุณสามารถทำสิ่งที่ชอบ:

SELECT col1, col2, col3, col4 FROM tbl

และเลือกคอลัมน์ที่คุณต้องการด้วยตนเอง อย่างไรก็ตามหากคุณต้องการคอลัมน์จำนวนมากคุณอาจต้องการ:

SELECT * FROM tbl 

และไม่สนใจสิ่งที่คุณไม่ต้องการ

ในกรณีเฉพาะของคุณฉันขอแนะนำ:

SELECT * FROM tbl

นอกเสียจากว่าคุณจะต้องการคอลัมน์เพียงไม่กี่คอลัมน์ หากคุณต้องการสี่คอลัมน์เท่านั้น:

SELECT col3, col6, col45, col 52 FROM tbl

จะดี แต่ถ้าคุณต้องการ 50 คอลัมน์แล้วรหัสใด ๆ ที่ทำให้แบบสอบถามจะกลายเป็น (เกินไป?) อ่านยาก


3
Select * เป็นตัวเลือกที่แย่เสมอ ไม่แนะนำเลย อ่านเกี่ยวกับสาเหตุที่เป็น Antipattern SQl
HLGEM

18

ขณะลองแก้ไขปัญหาโดย @Mahomedalid และ @Junaid ฉันพบปัญหา คิดว่าจะแบ่งปันมัน หากชื่อคอลัมน์มีช่องว่างหรือยัติภังค์เช่นเช็คอินแบบสอบถามจะล้มเหลว วิธีแก้ปัญหาง่ายๆคือใช้ backtick รอบชื่อคอลัมน์ แบบสอบถามที่แก้ไขอยู่ด้านล่าง

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;

11

หากคอลัมน์ที่คุณไม่ต้องการเลือกมีข้อมูลจำนวนมากและคุณไม่ต้องการรวมเนื่องจากปัญหาเรื่องความเร็วและคุณเลือกคอลัมน์อื่นบ่อยครั้งฉันขอแนะนำให้คุณสร้างตารางใหม่ ด้วยเขตข้อมูลหนึ่งที่คุณมักไม่ได้เลือกด้วยรหัสไปยังตารางต้นฉบับและลบเขตข้อมูลออกจากตารางต้นฉบับ เข้าร่วมตารางเมื่อจำเป็นต้องมีฟิลด์พิเศษจริง ๆ



8

ปัญหาหลักของฉันคือคอลัมน์จำนวนมากที่ฉันได้รับเมื่อเข้าร่วมตาราง แม้ว่านี่ไม่ใช่คำตอบสำหรับคำถามของคุณ (วิธีเลือกทั้งหมดยกเว้นคอลัมน์จากตารางหนึ่ง ) ฉันคิดว่ามันคุ้มค่าที่จะกล่าวถึงว่าคุณสามารถระบุให้รับคอลัมน์ทั้งหมดจากตารางใดตารางหนึ่งแทนที่จะระบุเพียงอย่างเดียวtable.

นี่คือตัวอย่างของสิ่งที่มีประโยชน์มาก:

เลือกผู้ใช้ *, phone.meta_value เป็นโทรศัพท์, zipcode.meta_value เป็นรหัสไปรษณีย์

จากผู้ใช้

เหลือผู้ใช้เข้าร่วม user_meta เป็นโทรศัพท์
เปิด ((users.user_id = phone.user_id) และ (phone.meta_key = 'โทรศัพท์'))

เหลือให้เข้าร่วม user_meta เป็นรหัสไปรษณีย์
เปิด ((users.user_id = zipcode.user_id) AND (zipcode.meta_key = 'zipcode'))

ผลลัพธ์คือคอลัมน์ทั้งหมดจากตารางผู้ใช้และสองคอลัมน์เพิ่มเติมซึ่งรวมจากตารางเมตา


2
ขอบคุณฉันต้องเลือกคอลัมน์ทั้งหมดของตารางแรกและมีเพียงหนึ่งเขตข้อมูลจากตารางที่สองในการเข้าร่วมและคำตอบของคุณช่วยฉันได้
Mohammad falahat

5

ผมชอบคำตอบจากนอกเหนือจากความเป็นจริงนี้แจ้งในความคิดเห็นจาก@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


4

เป็นวิธีปฏิบัติที่ดีในการระบุคอลัมน์ที่คุณทำการสืบค้นแม้ว่าคุณจะทำการค้นหาคอลัมน์ทั้งหมด

ดังนั้นฉันขอแนะนำให้คุณเขียนชื่อของแต่ละคอลัมน์ในคำสั่ง (ยกเว้นที่คุณไม่ต้องการ)

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

FROM table

มันทำหน้าที่เหมือนสัญญากับรหัสและเมื่อดูที่การสืบค้นคุณจะรู้ได้อย่างชัดเจนว่าข้อมูลใดที่คุณสามารถดึงออกมาจากมันได้โดยไม่ต้องดูที่สคีมาของตาราง
mbillard

6
@ kodecraft: เป็นวิธีปฏิบัติที่ดีด้วยเหตุผลเดียวกันว่าเป็นวิธีปฏิบัติที่ดีในการส่งคืนชนิดเดียวกันจากฟังก์ชัน (แม้ว่าคุณจะทำงานในภาษาที่ไม่ได้บังคับใช้) โดยพื้นฐานแล้วเป็นเพียงหลักการของความประหลาดใจน้อยที่สุด
Daniel Pryden

4

แค่ทำ

SELECT * FROM table WHERE whatever

จากนั้นให้วางคอลัมน์ลงในภาษาโปรแกรมที่คุณโปรดปราน: php

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

6
เว้นแต่คอลัมน์ที่คุณต้องการยกเว้นนั้นเป็น BLOB ขนาดใหญ่หรือบางอย่าง
Bill Karwin

1
สิ่งนี้ไม่ดีถ้าคุณพยายามหลีกเลี่ยงข้อมูลที่สูญเปล่า
Kristopher Ives

1 คอลัมน์จาก 53 ไม่ควรสร้างความแตกต่าง ถ้าเป็นเช่นนั้นมันอาจเป็นการออกแบบที่ไม่ดี
Petr Peller

1
SElect * เป็น antipattern SQL และไม่ควรใช้ในรหัสการผลิต
HLGEM

1
ฉันไม่เห็นด้วยว่า SELECT * เป็นรูปแบบการต่อต้านบางอย่างที่ไม่ควรใช้ในรหัสการผลิต เป็นที่ชัดเจนว่าคุณได้รับคอลัมน์ทั้งหมดของคุณแล้วเมื่อเทียบกับการอ้างอิงข้ามรายการคอลัมน์แบบยาวที่จริงหรือไม่อาจเป็นเขตข้อมูลทั้งหมด นอกจากนี้ยังเห็นได้ชัดว่าโค้ดเร็วกว่ามาก และมีหลายกรณีหลายกรณีที่เขตข้อมูลของตารางจะตรงกับเขตข้อมูลในมุมมองหรือแบบฟอร์ม
Geoff Kendall

4

ฉันเห็นด้วยกับวิธีการ "เรียบง่าย" ในการแสดงรายการคอลัมน์ทั้งหมด แต่อาจเป็นภาระและการพิมพ์ผิดอาจทำให้เสียเวลามากมาย ฉันใช้ฟังก์ชัน "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



4

ใช่แม้ว่ามันจะสูง I / O ขึ้นอยู่กับตารางที่นี่เป็นวิธีแก้ปัญหาที่ฉันพบมัน

SELECT *
INTO #temp
FROM table

ALTER TABLE #temp DROP COlUMN column_name

SELECT *
FROM #temp

นี่จะช้ามากสำหรับตารางที่มีขนาดปานกลาง
Joel

3

ฉันยอมรับว่ามันไม่เพียงพอSelect *หากหากสิ่งที่คุณไม่ต้องการดังที่กล่าวไว้ในที่อื่นคือ BLOB คุณไม่ต้องการให้ค่าใช้จ่ายดังกล่าวคืบคลานเข้ามา

ฉันจะสร้างมุมมองพร้อมข้อมูลที่จำเป็นจากนั้นคุณสามารถทำได้Select *อย่างสะดวกสบายหากซอฟต์แวร์ฐานข้อมูลรองรับ อื่นใส่ข้อมูลขนาดใหญ่ในตารางอื่น


3

ตอนแรกฉันคิดว่าคุณสามารถใช้นิพจน์ปกติ แต่เมื่อฉันอ่านเอกสาร MYSQLดูเหมือนว่าคุณทำไม่ได้ ถ้าฉันเป็นคุณฉันจะใช้ภาษาอื่น (เช่น PHP) เพื่อสร้างรายการคอลัมน์ที่คุณต้องการรับจัดเก็บเป็นสตริงแล้วใช้เพื่อสร้าง SQL


3

ฉันต้องการสิ่งนี้ด้วยดังนั้นฉันจึงสร้างฟังก์ชั่นแทน

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)."`";
    }
}

ดังนั้นวิธีการทำงานคือการที่คุณป้อนตารางจากนั้นคอลัมน์ที่คุณไม่ต้องการหรือในอาร์เรย์: array ("id", "name", "anycolumn")

ดังนั้นในการเลือกคุณสามารถใช้มันเช่นนี้:

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

หรือ

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

3

ฉันเห็นด้วยกับคำตอบของ @ Mahomedalid แต่ฉันไม่ต้องการทำอะไรเช่นคำสั่งที่เตรียมไว้และฉันไม่ต้องการพิมพ์ฟิลด์ทั้งหมดดังนั้นสิ่งที่ฉันมีก็คือวิธีแก้ปัญหาที่โง่

ไปที่ตารางใน phpmyadmin-> sql-> select มันดัมพ์เคียวรี: คัดลอกแทนที่และทำ! :)


2

ในขณะที่ฉันเห็นด้วยกับคำตอบของโทมัส (+1;)) ฉันต้องการเพิ่มข้อแม้ที่ฉันจะถือว่าคอลัมน์ที่คุณไม่ต้องการมีข้อมูลใด ๆ ถ้ามันมีข้อความจำนวนมหาศาล, xml หรือไบนารี blobs, ให้ใช้เวลาในการเลือกแต่ละคอลัมน์ การแสดงของคุณจะประสบเป็นอย่างอื่น ไชโย!


2

คำตอบที่โพสต์โดย Mahomedalid มีปัญหาเล็ก ๆ :

ภายในฟังก์ชั่นการแทนที่รหัสถูกแทนที่ " <columns_to_delete>," โดย "" การแทนที่นี้มีปัญหาหากฟิลด์ที่จะแทนที่เป็นฟิลด์สุดท้ายในสตริง concat เนื่องจากฟิลด์สุดท้ายไม่ได้มีเครื่องหมายจุลภาค "," และไม่ถูกลบออกจาก สตริง

ข้อเสนอของฉัน:

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 ประมาณ 1MB)


2

จากคำตอบของ @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;

หากคุณมี cols จำนวนมากให้ใช้ sql นี้เพื่อเปลี่ยน group_concat_max_len

SET @@group_concat_max_len = 2048;

2

อาจเป็นเพราะฉันมีวิธีแก้ไขปัญหาของJan Koritak ที่ชี้ให้เห็นความแตกต่าง

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'

1

หากเป็นหนึ่งในคอลัมน์เดียวกันเสมอคุณสามารถสร้างมุมมองที่ไม่มีในคอลัมน์นั้นได้

ไม่อย่างนั้นฉันก็ไม่คิดอย่างนั้น


1

คุณสามารถใช้ SQL เพื่อสร้าง SQL ได้หากคุณต้องการและประเมิน SQL ที่สร้างขึ้น นี่เป็นโซลูชันทั่วไปเนื่องจากแยกชื่อคอลัมน์จากสกีมาข้อมูล นี่คือตัวอย่างจากบรรทัดคำสั่ง Unix

แทน

  • MySQL ด้วยคำสั่ง mysql ของคุณ
  • ตารางที่มีชื่อตาราง
  • EXCLUDEDFIELD ที่มีชื่อฟิลด์ที่ยกเว้น
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สตริงกลับมาใช้ใหม่ได้ในคิวรีที่คุณสร้าง


1

ฉันต้องการเพิ่มมุมมองอื่นเพื่อแก้ไขปัญหานี้โดยเฉพาะถ้าคุณมีคอลัมน์จำนวนน้อยที่จะลบ

คุณสามารถใช้เครื่องมือ DB เช่นMySQL Workbenchเพื่อสร้างคำสั่ง select สำหรับคุณดังนั้นคุณเพียงแค่ลบคอลัมน์เหล่านั้นสำหรับคำสั่งที่สร้างและคัดลอกไปยังสคริปต์ SQL ของคุณ

ใน MySQL Workbench วิธีสร้าง:

คลิกขวาที่ตาราง -> ส่งไปยังเครื่องมือแก้ไข SQL -> เลือกคำชี้แจงทั้งหมด


1

คำตอบที่ยอมรับมีข้อบกพร่องหลายประการ

  • มันล้มเหลวที่ชื่อตารางหรือคอลัมน์ต้องมี backticks
  • มันล้มเหลวถ้าคอลัมน์ที่คุณต้องการละเว้นนั้นเป็นรายการสุดท้ายในรายการ
  • มันต้องการรายชื่อชื่อตารางสองครั้ง (หนึ่งครั้งสำหรับการเลือกและอีกครั้งสำหรับข้อความแบบสอบถาม) ซึ่งซ้ำซ้อนและไม่จำเป็น
  • มันอาจส่งกลับชื่อคอลัมน์ในลำดับที่ไม่ถูกต้อง

ทั้งหมดของปัญหาเหล่านี้จะสามารถเอาชนะได้โดยเพียงแค่รวมทั้ง backticks ใน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';

0

ฉันมีข้อเสนอแนะ แต่ไม่ใช่วิธีแก้ปัญหา หากคอลัมน์บางคอลัมน์ของคุณมีชุดข้อมูลที่ใหญ่ขึ้นคุณควรลองทำตาม

SELECT *, LEFT(col1, 0) AS col1, LEFT(col2, 0) as col2 FROM table

-1

ฉันค่อนข้างจะสายในการตอบคำถามนี้ทำให้นี่เป็นวิธีที่ฉันทำมาตลอดและตรงไปตรงมาดีกว่า 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]);

อาจเรียบร้อย แต่ไม่ตอบคำถาม: เขาไม่ได้ถามเกี่ยวกับ php และคุณไม่ได้ให้คำสั่งที่เลือกหรือผลลัพธ์ของสิ่งที่เขาต้องการ แต่มีเพียง php array ที่มีคอลัมน์ที่เขาต้องการ
gou1

2
-1 นี่ไม่ใช่รหัส SQL และไม่มีSELECTคำสั่งที่นี่ - คำว่าไม่เกิดขึ้นแม้แต่ครั้งเดียว
Frungi

นี่เป็นเพียงระดับที่ (a) คุณพอใจกับ PHP มากกว่า SQL หรือ (b) คุณชอบกระจายโค้ดของคุณผ่านหลายบรรทัดเพื่อให้สามารถอ่านได้ ฉันจะยอมรับจุด (b) วิธีการของคุณก็จะมีประสิทธิภาพน้อยกว่าแม้ว่าความแตกต่างจะเล็กน้อยในหลายกรณีการใช้งาน ดูความคิดเห็นอื่น ๆ สำหรับคำถามของคุณ ไม่คุ้มค่ากับการตะโกนดังนั้นแนะนำให้คุณลบความคิดเห็นที่ไม่เหมาะสมออกจากคำถามเดิม
mc0e

-5

Select * เป็น SQL antipattern ไม่ควรใช้รหัสการผลิตด้วยเหตุผลหลายประการรวมถึง:

ใช้เวลาในการประมวลผลนานกว่าเล็กน้อย เมื่อสิ่งต่าง ๆ วิ่งเป็นล้าน ๆ ครั้ง ฐานข้อมูลช้าที่ความช้าเกิดจากการเขียนโค้ดเลอะเทอะแบบนี้ตลอดเป็นชนิดที่ยากที่สุดในการปรับแต่งประสิทธิภาพ

หมายความว่าคุณอาจส่งข้อมูลมากกว่าที่คุณต้องการซึ่งทำให้เกิดปัญหาทั้งคอขวดและเครือข่าย หากคุณมีส่วนร่วมภายในโอกาสในการส่งข้อมูลมากกว่าที่คุณต้องการคือ 100%

มันทำให้เกิดปัญหาการบำรุงรักษาโดยเฉพาะเมื่อคุณเพิ่มคอลัมน์ใหม่ที่คุณไม่ต้องการเห็นทุกที่ นอกจากนี้หากคุณมีคอลัมน์ใหม่คุณอาจต้องทำอะไรกับอินเทอร์เฟซเพื่อกำหนดว่าจะทำอย่างไรกับคอลัมน์นั้น

มันสามารถแยกมุมมอง (ฉันรู้ว่านี่เป็นจริงในเซิร์ฟเวอร์ SQl มันอาจจริงหรือไม่จริงใน mysql)

หากใครบางคนโง่พอที่จะสร้างตารางใหม่ด้วยคอลัมน์ในลำดับ differnt (ซึ่งคุณไม่ควรทำ แต่มันเกิดขึ้นตลอดเวลา) ทุกประเภทของรหัสสามารถแตก โค้ดเฉพาะสำหรับการแทรกตัวอย่างเช่นเมื่อคุณวางเมืองลงในฟิลด์ address_3 โดยไม่ต้องระบุฐานข้อมูลสามารถเรียงตามลำดับของคอลัมน์ได้เท่านั้น สิ่งนี้ไม่ดีพอเมื่อชนิดข้อมูลเปลี่ยนไป แต่แย่กว่านั้นเมื่อคอลัมน์สลับมีประเภทข้อมูลเดียวกันเนื่องจากคุณสามารถเข้าไปแทรกข้อมูลที่ไม่ดีซึ่งเป็นระเบียบเพื่อล้างข้อมูลในบางครั้ง คุณต้องใส่ใจกับความถูกต้องของข้อมูล

ถ้ามันถูกใช้ในการแทรกมันจะทำลายการแทรกถ้ามีการเพิ่มคอลัมน์ใหม่ในตารางหนึ่ง แต่ไม่ใช่คอลัมน์อื่น

มันอาจทริกเกอร์ ปัญหาทริกเกอร์อาจวินิจฉัยได้ยาก

เพิ่มทั้งหมดนี้เทียบกับเวลาที่ใช้ในการเพิ่มชื่อคอลัมน์ (heck คุณอาจมีส่วนต่อประสานที่ช่วยให้คุณสามารถลากชื่อคอลัมน์ (ฉันรู้ว่าฉันทำใน SQL Server ฉันจะพนันได้เลยว่ามีบางวิธีที่จะ ทำสิ่งนี้เป็นเครื่องมือที่คุณใช้ในการเขียนแบบสอบถาม mysql) ลองดู "ฉันสามารถทำให้เกิดปัญหาการบำรุงรักษาฉันสามารถทำให้เกิดปัญหาประสิทธิภาพการทำงานและฉันสามารถทำให้เกิดปัญหาความสมบูรณ์ของข้อมูล แต่เดี๋ยวก่อนฉันประหยัดเวลา dev ห้านาที" ในคอลัมน์ที่คุณต้องการ

ฉันขอแนะนำให้คุณอ่านหนังสือเล่มนี้: 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 และคำหลัก = SQL + antipatterns

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.