Tôi đang cố gắng sử dụng một câu lệnh chọn để lấy tất cả các cột từ một bảng MySQL nhất định trừ một cột. Có một cách đơn giản để làm điều này?
EDIT: Có 53 cột trong bảng này (KHÔNG PHẢI THIẾT KẾ CỦA TÔI)
Tôi đang cố gắng sử dụng một câu lệnh chọn để lấy tất cả các cột từ một bảng MySQL nhất định trừ một cột. Có một cách đơn giản để làm điều này?
EDIT: Có 53 cột trong bảng này (KHÔNG PHẢI THIẾT KẾ CỦA TÔI)
Câu trả lời:
Trên thực tế có một cách, bạn cần phải có quyền tất nhiên để làm điều này ...
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;
Thay thế <table>, <database> and <columns_to_omit>
<column_name>
Trong định nghĩa mysql (thủ công) không có điều đó. Nhưng nếu bạn có số lượng cột thực sự lớn col1
, ... ,, col100
thì những điều sau đây có thể hữu ích:
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;
DROP TABLE IF EXISTS temp_tb;
Một View sẽ hoạt động tốt hơn trong trường hợp này?
CREATE VIEW vwTable
as
SELECT
col1
, col2
, col3
, col..
, col53
FROM table
Bạn có thể làm:
SELECT column1, column2, column4 FROM table WHERE whatever
mà không nhận được cột3, mặc dù có lẽ bạn đang tìm kiếm một giải pháp tổng quát hơn?
Nếu bạn đang tìm cách loại trừ giá trị của một trường, ví dụ: đối với các vấn đề bảo mật / thông tin nhạy cảm, bạn có thể truy xuất cột đó dưới dạng null.
ví dụ
SELECT *, NULL AS salary FROM users
salary
cột thứ hai . Nhưng vì nó được truy xuất sau dấu *, nó ghi đè lên bản gốc. Nó không đẹp, nhưng nó hoạt động.
Theo hiểu biết tốt nhất của tôi, không có. Bạn có thể làm một cái gì đó như:
SELECT col1, col2, col3, col4 FROM tbl
và tự chọn các cột bạn muốn. Tuy nhiên, nếu bạn muốn có nhiều cột, thì bạn có thể chỉ muốn thực hiện:
SELECT * FROM tbl
và chỉ cần bỏ qua những gì bạn không muốn.
Trong trường hợp cụ thể của bạn, tôi sẽ đề nghị:
SELECT * FROM tbl
trừ khi bạn chỉ muốn một vài cột. Nếu bạn chỉ muốn bốn cột, thì:
SELECT col3, col6, col45, col 52 FROM tbl
sẽ ổn, nhưng nếu bạn muốn 50 cột, thì bất kỳ mã nào làm cho truy vấn sẽ trở nên (quá?) khó đọc.
Trong khi thử các giải pháp của @Mahomedalid và @Junaid, tôi thấy có một vấn đề. Vì vậy, nghĩ về việc chia sẻ nó. Nếu tên cột có dấu cách hoặc dấu gạch nối như đăng ký thì truy vấn sẽ thất bại. Cách giải quyết đơn giản là sử dụng backtick xung quanh tên cột. Các truy vấn sửa đổi dưới đây
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;
Nếu cột mà bạn không muốn chọn có một lượng lớn dữ liệu trong đó và bạn không muốn đưa nó vào do vấn đề tốc độ và bạn thường xuyên chọn các cột khác, tôi sẽ đề nghị bạn tạo một bảng mới với một trường mà bạn thường không chọn bằng một phím cho bảng gốc và xóa trường khỏi bảng gốc. Tham gia các bảng khi trường đó thực sự cần thiết.
Bạn có thể sử dụng MÔ TẢ my_table và sử dụng kết quả của điều đó để tạo ra câu lệnh SELECT một cách linh hoạt.
Vấn đề chính của tôi là nhiều cột tôi nhận được khi tham gia các bảng. Mặc dù đây không phải là câu trả lời cho câu hỏi của bạn (cách chọn tất cả trừ một số cột nhất định từ một bảng), tôi nghĩ điều đáng nói là bạn có thể chỉ định để lấy tất cả các cột từ một bảng cụ thể, thay vì chỉ xác định .table.
Đây là một ví dụ về cách điều này có thể rất hữu ích:
chọn người dùng. *, phone.meta_value làm điện thoại, zipcode.meta_value làm zipcode từ người dùng còn lại tham gia user_meta như điện thoại bật ((users.user_id = phone.user_id) VÀ (phone.meta_key = 'phone')) còn lại tham gia user_meta dưới dạng mã zip bật ((users.user_id = zipcode.user_id) VÀ (zipcode.meta_key = 'zipcode'))
Kết quả là tất cả các cột từ bảng người dùng và hai cột bổ sung được nối từ bảng meta.
Tôi thích câu trả lời từ @Mahomedalid
bên cạnh thực tế này được thông báo trong nhận xét từ @Bill Karwin
. Vấn đề có thể xảy ra @Jan Koritak
là sự thật tôi đã đối mặt với điều đó nhưng tôi đã tìm ra một mẹo cho điều đó và chỉ muốn chia sẻ nó ở đây cho bất cứ ai phải đối mặt với vấn đề này.
chúng ta có thể thay thế hàm REPLACE bằng mệnh đề where trong truy vấn con của câu lệnh Prepared như thế này:
Sử dụng tên bảng và cột của tôi
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;
Vì vậy, điều này sẽ chỉ loại trừ trường id
nhưng khôngcompany_id
Đó là một thực hành tốt để xác định các cột mà bạn đang truy vấn ngay cả khi bạn truy vấn tất cả các cột.
Vì vậy, tôi sẽ đề nghị bạn viết tên của từng cột trong câu lệnh (không bao gồm cột bạn không muốn).
SELECT
col1
, col2
, col3
, col..
, col53
FROM table
Cứ làm đi
SELECT * FROM table WHERE whatever
Sau đó thả cột trong ngôn ngữ lập trình yêu thích của bạn: php
while (($data = mysql_fetch_array($result, MYSQL_ASSOC)) !== FALSE) {
unset($data["id"]);
foreach ($data as $k => $v) {
echo"$v,";
}
}
Tôi đồng ý với giải pháp "đơn giản" trong việc liệt kê tất cả các cột, nhưng điều này có thể gây gánh nặng và lỗi chính tả có thể gây lãng phí nhiều thời gian. Tôi sử dụng hàm "getTableColumns" để lấy tên của các cột phù hợp để dán vào truy vấn. Sau đó, tất cả những gì tôi cần làm là xóa những cái tôi không muốn.
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;
Kết quả của bạn trả về một chuỗi được phân cách bằng dấu phẩy, ví dụ ...
col1, col2, col3, col4, ... col53
Tôi đồng ý rằng nó không đủ để Select *
, nếu cái mà bạn không cần, như đã đề cập ở nơi khác, là một BLOB, bạn không muốn có cái đầu bò đó.
Tôi sẽ tạo một khung nhìn với dữ liệu cần thiết, sau đó bạn có thể Select *
thoải mái - nếu phần mềm cơ sở dữ liệu hỗ trợ chúng. Khác, đặt dữ liệu lớn trong một bảng khác.
Lúc đầu tôi nghĩ bạn có thể sử dụng các biểu thức thông thường, nhưng vì tôi đã đọc tài liệu MYSQL nên dường như bạn không thể. Nếu tôi là bạn, tôi sẽ sử dụng ngôn ngữ khác (như PHP) để tạo danh sách các cột bạn muốn lấy, lưu trữ dưới dạng chuỗi và sau đó sử dụng ngôn ngữ đó để tạo SQL.
Tôi cũng muốn điều này vì vậy tôi đã tạo ra một chức năng thay thế.
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)."`";
}
}
Vì vậy, cách nó hoạt động là bạn nhập vào bảng, sau đó một cột bạn không muốn hoặc như trong một mảng: mảng ("id", "name", "anythingcolumn")
Vì vậy, trong lựa chọn bạn có thể sử dụng nó như thế này:
mysql_query("SELECT ".$db->getColsExcept('table',array('id','bigtextcolumn'))." FROM table");
hoặc là
mysql_query("SELECT ".$db->getColsExcept('table','bigtextcolumn')." FROM table");
Tôi đồng ý với câu trả lời của @ Mahomedalid, nhưng tôi không muốn làm điều gì đó như một tuyên bố đã chuẩn bị và tôi không muốn gõ tất cả các lĩnh vực, vì vậy những gì tôi có là một giải pháp ngớ ngẩn.
Đi đến bảng trong phpmyadmin-> sql-> select, nó bỏ truy vấn: sao chép, thay thế và thực hiện! :)
Mặc dù tôi đồng ý với câu trả lời của Thomas (+1;)), tôi muốn thêm lời cảnh báo rằng tôi sẽ giả sử cột mà bạn không muốn chứa hầu như không có dữ liệu. Nếu nó chứa số lượng lớn văn bản, xml hoặc các đốm nhị phân, thì hãy dành thời gian để chọn từng cột riêng lẻ. Hiệu suất của bạn sẽ bị khác. Chúc mừng!
Câu trả lời được đăng bởi Mahomedalid có một vấn đề nhỏ:
Bên trong mã chức năng thay thế đã thay thế " <columns_to_delete>,
" bằng "", sự thay thế này có vấn đề nếu trường thay thế là trường cuối cùng trong chuỗi concat do cái cuối cùng không có dấu phẩy "," và không bị xóa khỏi chuỗi.
Đề nghị của tôi:
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>');
Thay thế <table>
, <database>
và '
Cột bị xóa được thay thế bằng chuỗi "FIELD_REMOVED" trong trường hợp của tôi, điều này hoạt động vì tôi đang cố gắng bảo vệ bộ nhớ. (Trường tôi đã xóa là BLOB khoảng 1MB)
Dựa trên câu trả lời @Mahomedalid, tôi đã thực hiện một số cải tiến để hỗ trợ "chọn tất cả các cột ngoại trừ một số cột trong 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;
Nếu bạn có nhiều cols, hãy sử dụng sql này để thay đổi group_concat_max_len
SET @@group_concat_max_len = 2048;
Có thể tôi có một giải pháp cho sự khác biệt được chỉ ra của 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' );
Bàn :
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
================================
Kết quả truy vấn:
'SELECT name_eid,sal FROM employee'
Nếu nó luôn luôn là cùng một cột, thì bạn có thể tạo chế độ xem không có cột đó.
Mặt khác, không, tôi không nghĩ vậy.
Bạn có thể sử dụng SQL để tạo SQL nếu bạn thích và đánh giá SQL mà nó tạo ra. Đây là một giải pháp chung vì nó trích xuất các tên cột từ lược đồ thông tin. Đây là một ví dụ từ dòng lệnh Unix.
Thay thế
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
Bạn thực sự sẽ chỉ cần trích xuất các tên cột theo cách này chỉ một lần để xây dựng danh sách cột loại trừ cột đó, và sau đó chỉ cần sử dụng truy vấn bạn đã xây dựng.
Vì vậy, một cái gì đó như:
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)
Bây giờ bạn có thể sử dụng lại $column_list
chuỗi trong các truy vấn bạn xây dựng.
Tôi muốn thêm một quan điểm khác để giải quyết vấn đề này, đặc biệt nếu bạn có một số lượng nhỏ cột cần loại bỏ.
Bạn có thể sử dụng một công cụ DB như MySQL Workbench để tạo câu lệnh chọn cho bạn, vì vậy bạn chỉ cần xóa thủ công các cột đó cho câu lệnh được tạo và sao chép nó vào tập lệnh SQL của bạn.
Trong MySQL Workbench cách để tạo ra nó là:
Nhấp chuột phải vào bảng -> gửi tới Sql Editor -> Chọn Tất cả Tuyên bố.
Câu trả lời được chấp nhận có một số thiếu sót.
Tất cả những vấn đề này có thể được khắc phục bằng cách đơn giản bao gồm các backticks SEPARATOR
cho bạn GROUP_CONCAT
và sử dụng một WHERE
điều kiện thay vì REPLACE()
. Đối với mục đích của tôi (và tôi tưởng tượng nhiều người khác), tôi muốn các tên cột được trả về theo thứ tự giống như chúng xuất hiện trong bảng. Để đạt được điều này, ở đây chúng tôi sử dụng một ORDER BY
mệnh đề rõ ràng bên trong GROUP_CONCAT()
hàm:
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';
Tôi khá muộn khi đưa ra câu trả lời cho điều này, đây là cách tôi luôn làm và thẳng thắn, nó tốt hơn và gọn gàng hơn gấp 100 lần so với câu trả lời hay nhất, tôi chỉ hy vọng ai đó sẽ nhìn thấy nó. Và thấy nó hữu ích
//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]);
SELECT
tuyên bố nào ở đây. Từ này thậm chí không xuất hiện một lần.
Chọn * là một phản mẫu SQL. Nó không nên được sử dụng trong mã sản xuất vì nhiều lý do bao gồm:
Phải mất một chút thời gian dài để xử lý. Khi mọi thứ được chạy hàng triệu lần, những bit nhỏ đó có thể quan trọng. Một cơ sở dữ liệu chậm trong đó sự chậm chạp được gây ra bởi loại mã hóa cẩu thả này là loại khó nhất để điều chỉnh hiệu suất.
Điều đó có nghĩa là bạn có thể đang gửi nhiều dữ liệu hơn mức bạn cần, điều này gây ra tắc nghẽn cả máy chủ và mạng. Nếu bạn có một tham gia bên trong, cơ hội gửi nhiều dữ liệu hơn bạn cần là 100%.
Nó gây ra vấn đề bảo trì đặc biệt là khi bạn đã thêm các cột mới mà bạn không muốn thấy ở mọi nơi. Hơn nữa nếu bạn có một cột mới, bạn có thể cần phải làm gì đó với giao diện để xác định phải làm gì với cột đó.
Nó có thể phá vỡ các khung nhìn (Tôi biết điều này đúng trong máy chủ SQl, nó có thể đúng hoặc không đúng trong mysql).
Nếu ai đó đủ ngớ ngẩn để xây dựng lại các bảng với các cột theo thứ tự khác nhau (điều bạn không nên làm nhưng nó xảy ra mọi lúc), tất cả các loại mã có thể bị phá vỡ. Mã đặc biệt cho một chèn chẳng hạn, trong đó đột nhiên bạn đặt thành phố vào trường address_3 vì không chỉ định, cơ sở dữ liệu chỉ có thể đi theo thứ tự của các cột. Điều này đủ tệ khi các kiểu dữ liệu thay đổi nhưng tệ hơn khi các cột được hoán đổi có cùng kiểu dữ liệu vì bạn đôi khi có thể chèn dữ liệu xấu là một mớ hỗn độn để dọn dẹp. Bạn cần quan tâm đến tính toàn vẹn dữ liệu.
Nếu nó được sử dụng trong một chèn, nó sẽ phá vỡ chèn nếu một cột mới được thêm vào trong một bảng nhưng không phải là một bảng khác.
Nó có thể phá vỡ các kích hoạt. Vấn đề kích hoạt có thể khó chẩn đoán.
Thêm tất cả điều này vào thời gian cần thêm vào các tên cột (bạn thậm chí có thể có một giao diện cho phép bạn kéo qua các tên cột (Tôi biết tôi làm trong SQL Server, tôi cá là có một số cách để làm điều này là một số công cụ bạn sử dụng để viết các truy vấn mysql.) Hãy xem, "Tôi có thể gây ra sự cố bảo trì, tôi có thể gây ra vấn đề về hiệu suất và tôi có thể gây ra sự cố toàn vẹn dữ liệu, nhưng tôi đã tiết kiệm được năm phút của thời gian phát triển." trong các cột cụ thể mà bạn muốn.
Tôi cũng đề nghị bạn đọc cuốn sách này: http://www.amazon.com 1 & Keywords = sql + antipotypes