MySQL, Kiểm tra xem một cột có tồn tại trong một bảng có SQL không


130

Tôi đang cố gắng viết một truy vấn sẽ kiểm tra xem một bảng cụ thể trong MySQL có một cột cụ thể không và nếu không - hãy tạo nó. Nếu không thì không làm gì cả. Đây thực sự là một thủ tục dễ dàng trong bất kỳ cơ sở dữ liệu cấp doanh nghiệp nào, nhưng MySQL dường như là một ngoại lệ.

Tôi đã nghĩ một cái gì đó như

IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS 
           WHERE TABLE_NAME='prefix_topic' AND column_name='topic_last_update') 
BEGIN 
ALTER TABLE `prefix_topic` ADD `topic_last_update` DATETIME NOT NULL;
UPDATE `prefix_topic` SET `topic_last_update` = `topic_date_add`;
END;

sẽ làm việc, nhưng nó thất bại nặng nề. Là có một cách?



Tại sao không chỉ tạo ra nó? Nếu nó tồn tại, việc tạo sẽ thất bại nhưng bạn không quan tâm.
Brian Hooper

việc tạo ra diễn ra bên trong một giao dịch và sự thất bại sẽ chấm dứt toàn bộ giao dịch, thật đáng buồn nhưng đúng
clops

@haim - thans cho các phần đầu, nhưng truy vấn được đề xuất trong liên kết của bạn chỉ hoạt động trong một quy trình :(
clops

2
Báo cáo DDL gây ra cam kết ngầm trong giao dịch hiện tại. dev.mysql.com/doc/refman/5.0/en/implicit-commit.html
Mchl

Câu trả lời:


259

Công việc này tốt cho tôi.

SHOW COLUMNS FROM `table` LIKE 'fieldname';

Với PHP, nó sẽ giống như ...

$result = mysql_query("SHOW COLUMNS FROM `table` LIKE 'fieldname'");
$exists = (mysql_num_rows($result))?TRUE:FALSE;

8
Câu hỏi không phải là làm thế nào để sử dụng php + sql hay java + sql, mà là làm thế nào để sử dụng sql / mysql thuần túy do đó downvote
Yuriy Nakonechnyy

61
Bạn trả lời câu hỏi + một số thông tin đã giúp tôi và có thể là những người khác, +1
Francisco Presencia

@Mfoo Cảm ơn Mfoo, bạn đã cứu ngày của tôi! Hoạt động như quyến rũ. Một trong những giải pháp tốt nhất ngoài việc tạo Thủ tục cho nhiệm vụ này.
webblover

8
Yura: Câu trả lời SQL / MySQL thuần túy là phần đầu tiên mà anh ta nói sử dụng "SHOW COLUMNS TỪ bảng THÍCH 'tên trường'". Bạn có thể bỏ qua mã PHP, đó chỉ là một ví dụ về một cách để truy xuất và giải thích kết quả nếu bạn tình cờ sử dụng PHP.
orrd

1
@codenamezero Tôi giả sử bạn đang đề cập đến việc sử dụng MSSQL, câu hỏi này liên quan đến MySQL. tham khảo bài đăng này cho MSSQL
Mfoo

158

@julio

Cảm ơn ví dụ SQL. Tôi đã thử truy vấn và tôi nghĩ rằng nó cần một sự thay đổi nhỏ để làm cho nó hoạt động đúng.

SELECT * 
FROM information_schema.COLUMNS 
WHERE 
    TABLE_SCHEMA = 'db_name' 
AND TABLE_NAME = 'table_name' 
AND COLUMN_NAME = 'column_name'

Điều đó làm việc cho tôi.

Cảm ơn!


Nó xuất hiện từ nghiên cứu hạn chế của tôi rằng không phải tất cả các môi trường lưu trữ đều có DB thông tin_schema. Tất cả các môi trường cpanel tôi đã sử dụng có nó. Giải pháp được cung cấp này phụ thuộc vào DB này hiện có.
cardi777

2
Câu trả lời này tốt hơn so với sử dụng "SHOW COLUMNS" bởi vì nó sử dụng cách tiêu chuẩn ANSI để lấy thông tin bảng, không giống như SHOW COLUMNS dành riêng cho MySQL. Vì vậy, giải pháp này sẽ làm việc với các cơ sở dữ liệu khác. Sử dụng "information_schema" nghe có vẻ kỳ quặc và bạn sẽ nghĩ rằng đó sẽ không phải là cách SQL tiêu chuẩn để làm điều này, nhưng thực tế là như vậy.
orrd

5
Lưu ý rằng câu trả lời này chỉ giúp bạn có được thông tin về sự tồn tại của cột. Nếu bạn muốn thực thi có điều kiện một số câu lệnh DDL, bạn sẽ phải bọc toàn bộ trong một quy trình cho phép các câu lệnh như IF, v.v. Xem stackoverflow.com/questions/7384711/ để biết ví dụ về cách bọc một thủ tục xung quanh kiểm tra cho cột và câu lệnh DML có điều kiện.
Christopher Schultz

@Iain: stackoverflow.com/questions/32962149/ Tôi đã giới thiệu câu trả lời của bạn
Amar Singh

Cách này tốt hơn so với cách tiếp cận "SHOW COLUMNS" bên dưới vì có thể được sử dụng trong các truy vấn được tham số hóa làm giảm nguy cơ tiêm SQL. Chỉ muốn thêm bạn có thể sử dụng hàm DATABASE () để điền vào cột TABLE_SCHema.
Andrew

16

Chỉ để giúp bất cứ ai đang tìm kiếm một ví dụ cụ thể về những gì @Mchl đã mô tả, hãy thử một cái gì đó như

SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'my_schema' AND TABLE_NAME = 'my_table' AND COLUMN_NAME = 'my_column'

Nếu nó trả về false (không có kết quả) thì bạn biết cột không tồn tại.


2
Tôi tin rằng nó phải như vậy TABLE_NAME = 'my_table', TABLE_SCHema là lược đồ mà bảng đang ở. Tức làSELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'my_schema' AND TABLE_NAME = 'my_table' AND COLUMN_NAME = 'my_column'
AaronHolland

10

Sau đây là một cách khác để thực hiện bằng PHP đơn giản mà không cần cơ sở dữ liệu information_schema:

$chkcol = mysql_query("SELECT * FROM `my_table_name` LIMIT 1");
$mycol = mysql_fetch_array($chkcol);
if(!isset($mycol['my_new_column']))
  mysql_query("ALTER TABLE `my_table_name` ADD `my_new_column` BOOL NOT NULL DEFAULT '0'");

Tại sao bạn muốn tránh sử dụng information_schema? Nó tồn tại chỉ cho mục đích này. (Ngoài ra, chủ đề này khá cũ và đã được trả lời.)
Leigh

1
Trong các thử nghiệm của tôi, tốc độ này nhanh hơn khoảng 10-50 lần so với sử dụng information_schema. Nó đòi hỏi rằng bảng có ít nhất một hàng, mà bạn không thể luôn đảm bảo.
Martijn

isset()sẽ trow 'false' nếu khóa mảng tồn tại nhưng giá trị là NULL . Tốt hơn là sử dụng array_key_exists()nhưif( !array_key_exists( 'my_new_column', $mycol ) )
Paul Geisler

1
Câu trả lời này làm cho tôi facepalm vì tôi bỏ qua một isset()kiểm tra đơn giản . Nó không giải quyết được câu hỏi, nhưng sẽ tốt hơn nếu bạn đã cần thực hiện truy vấn chọn và có kết quả trong bộ nhớ.
Siphon

10

Tôi đã ném thủ tục được lưu trữ này cùng với một sự khởi đầu từ các bình luận của @ lain ở trên, thật tuyệt nếu bạn cần gọi nó nhiều hơn một vài lần (và không cần php):

delimiter //
-- ------------------------------------------------------------
-- Use the inforamtion_schema to tell if a field exists.
-- Optional param dbName, defaults to current database
-- ------------------------------------------------------------
CREATE PROCEDURE fieldExists (
OUT _exists BOOLEAN,      -- return value
IN tableName CHAR(255),   -- name of table to look for
IN columnName CHAR(255),  -- name of column to look for
IN dbName CHAR(255)       -- optional specific db
) BEGIN
-- try to lookup db if none provided
SET @_dbName := IF(dbName IS NULL, database(), dbName);

IF CHAR_LENGTH(@_dbName) = 0
THEN -- no specific or current db to check against
  SELECT FALSE INTO _exists;
ELSE -- we have a db to work with
  SELECT IF(count(*) > 0, TRUE, FALSE) INTO _exists
  FROM information_schema.COLUMNS c
  WHERE 
  c.TABLE_SCHEMA    = @_dbName
  AND c.TABLE_NAME  = tableName
  AND c.COLUMN_NAME = columnName;
END IF;
END //
delimiter ;

Làm việc với fieldExists

mysql> call fieldExists(@_exists, 'jos_vm_product', 'child_option', NULL) //
Query OK, 0 rows affected (0.01 sec)

mysql> select @_exists //
+----------+
| @_exists |
+----------+
|        0 |
+----------+
1 row in set (0.00 sec)

mysql> call fieldExists(@_exists, 'jos_vm_product', 'child_options', 'etrophies') //
Query OK, 0 rows affected (0.01 sec)

mysql> select @_exists //
+----------+
| @_exists |
+----------+
|        1 |
+----------+

MIster @quickshiftin, cảm ơn bạn rất nhiều. Điều này giúp tôi kiểm tra nếu một bảng là hết hạn , bằng cách kiểm tra nếu có một ExpirationDatetrường. 😊
Jeancarlo Fontalvo

@JeancarloFontalvo Niềm vui của tôi! Ngoài ra kiểm tra dự án thanh tra mysql của tôi , tôi bắt đầu kiểm tra lược đồ với các phương thức cấp cao hơn.
quickshiftin

1
OMG Nó giống như một thư viện. Cảm ơn đã chia sẻ nó Mister!
Jeancarlo Fontalvo

8

Chọn chỉ cột_name từ lược đồ thông tin và đặt kết quả của truy vấn này vào biến. Sau đó kiểm tra biến để quyết định xem bảng có cần thay đổi hay không.

PS Đừng tạo sương mù để chỉ định TABLE_SCHema cho bảng COLUMNS.


1
Tôi còn khá mới với MySQL, bạn có thể đăng một ví dụ nhỏ ở đây không?
clops

2

Tôi đang sử dụng tập lệnh đơn giản này:

mysql_query("select $column from $table") or mysql_query("alter table $table add $column varchar (20)");

Nó hoạt động nếu bạn đã kết nối với cơ sở dữ liệu.


Điều này sẽ chỉ hoạt động nếu bảng cũng có hàng dữ liệu trong đó. Nhưng nếu cái bàn trống, cái này sẽ không hoạt động.
orrd

1
không hoàn hảo, sử dụng trình điều khiển cũ, không hoạt động nếu bảng trống, đầu vào không thoát, nhưng tôi thích cách bạn đã làm nó trong một dòng. +1
Tôi đã vật lộn một con gấu một lần.

1

Rất cám ơn Mfoo, người đã đặt tập lệnh thực sự hay để thêm các cột một cách linh hoạt nếu không tồn tại trong bảng. Tôi đã cải thiện câu trả lời của anh ấy với PHP . Tập lệnh cũng giúp bạn tìm thấy có bao nhiêu bảng thực sự cần thiết 'Thêm cột' comand comand. Chỉ cần nếm thử công thức. Hoạt động như quyến rũ.

<?php
ini_set('max_execution_time', 0);

$host = 'localhost';
$username = 'root';
$password = '';
$database = 'books';

$con = mysqli_connect($host, $username, $password);
if(!$con) { echo "Cannot connect to the database ";die();}
mysqli_select_db($con, $database);
$result=mysqli_query($con, 'show tables');
$tableArray = array();
while($tables = mysqli_fetch_row($result)) 
{
     $tableArray[] = $tables[0];    
}

$already = 0;
$new = 0;
for($rs = 0; $rs < count($tableArray); $rs++)
{
    $exists = FALSE;

    $result = mysqli_query($con, "SHOW COLUMNS FROM ".$tableArray[$rs]." LIKE 'tags'");
    $exists = (mysqli_num_rows($result))?TRUE:FALSE;

    if($exists == FALSE)
    {
        mysqli_query($con, "ALTER TABLE ".$tableArray[$rs]." ADD COLUMN tags VARCHAR(500) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL");
        ++$new;
        echo '#'.$new.' Table DONE!<br/>';
    }
    else
    {
        ++$already;
        echo '#'.$already.' Field defined alrady!<br/>';    
    }
    echo '<br/>';
}
?>

1

Công việc này đối với tôi với mẫu PDO:

public function GetTableColumn() {      
$query  = $this->db->prepare("SHOW COLUMNS FROM `what_table` LIKE 'what_column'");  
try{            
    $query->execute();                                          
    if($query->fetchColumn()) { return 1; }else{ return 0; }
    }catch(PDOException $e){die($e->getMessage());}     
}

0

KHÔNG đặt ALTER TABLE / MODIFY COLS hoặc bất kỳ hoạt động mod bảng nào khác như vậy trong GIAO DỊCH. Các giao dịch là để có thể khôi phục một lỗi QUẤT không phải vì THAY ĐỔI ... nó sẽ bị lỗi mỗi lần trong một giao dịch.

Chỉ cần chạy truy vấn CHỌN * trên bảng và kiểm tra xem cột có ở đó không ...


ALTER(và DDL như thế) trong MySQL thực sự cam kết (ngầm) giao dịch. Nhưng sử dụng CHỌN * sẽ tạo ra một chi phí lớn trong mạng chỉ để kiểm tra sự tồn tại của cột. Thay vào đó, bạn có thể thử SELECT my_col_to_check FROM t LIMIT 0: nếu mysql tạo ra lỗi, thì cột có thể không tồn tại (vẫn vậy, hãy kiểm tra lỗi, vì đó có thể là sự cố mạng hoặc bất cứ điều gì!); nếu nó tạo ra không có lỗi, thì cột tồn tại. Tôi không chắc đó là cách tốt nhất để kiểm tra sự tồn tại của cột.
Xenos
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.