Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Cách chọn tất cả các bảng có tên cột và cập nhật cột đó

Không, không phải trong một tuyên bố nào.

Để lấy tên của tất cả các bảng có chứa cột có tên Foo :

SELECT table_schema, table_name
  FROM information_schema.columns 
  WHERE column_name = 'Foo'

Sau đó, bạn cần một câu lệnh CẬP NHẬT cho mỗi bảng. (Có thể cập nhật nhiều bảng trong một câu lệnh duy nhất, nhưng đó sẽ cần phải là một phép nối chéo (không cần thiết).) Tốt hơn nên thực hiện từng bảng riêng biệt.

Bạn có thể sử dụng SQL động để thực thi các câu lệnh UPDATE trong chương trình được lưu trữ MySQL (ví dụ:PROCEDURE)

  DECLARE sql VARCHAR(2000);
  SET sql = 'UPDATE db.tbl SET Foo = 0';
  PREPARE stmt FROM sql;
  EXECUTE stmt;
  DEALLOCATE stmt;

Nếu bạn khai báo một con trỏ cho select từ information_schema.tables, bạn có thể sử dụng vòng lặp con trỏ để xử lý UPDATE động câu lệnh cho mỗi tên_bảng được trả về.

  DECLARE done TINYINT(1) DEFAULT FALSE;
  DECLARE sql  VARCHAR(2000);

  DECLARE csr FOR
  SELECT CONCAT('UPDATE `',c.table_schema,'`.`',c.table_name,'` SET `Foo` = 0') AS sql
    FROM information_schema.columns c
   WHERE c.column_name = 'Foo'
     AND c.table_schema NOT IN ('mysql','information_schema','performance_schema');
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

  OPEN csr;
  do_foo: LOOP
     FETCH csr INTO sql;
     IF done THEN
        LEAVE do_foo;
     END IF;
     PREPARE stmt FROM sql;
     EXECUTE stmt;
     DEALLOCATE PREPARE stmt;
  END LOOP do_foo;
  CLOSE csr;

(Đây chỉ là một phác thảo sơ bộ của một ví dụ, không được kiểm tra hoặc thử nghiệm cú pháp.)

THEO DÕI

Một số ghi chú ngắn gọn về một số ý tưởng có thể đã được lược bỏ trong câu trả lời ở trên.

Để lấy tên của các bảng chứa cột Foo , chúng tôi có thể chạy một truy vấn từ information_schema.columns bàn. (Đó là một trong những bảng được cung cấp trong MySQL information_schema cơ sở dữ liệu.)

Bởi vì chúng ta có thể có các bảng trong nhiều cơ sở dữ liệu, tên_bảng không đủ để xác định một bảng; chúng ta cần biết cơ sở dữ liệu của bảng đó là gì. Thay vì sử dụng " use db " "trước khi chúng tôi chạy một câu lệnh UPDATE , chúng ta chỉ có thể tham chiếu bảng UPDATE db.mytable SET Foo ... .

Chúng tôi có thể sử dụng truy vấn information_schema.columns của mình để tiếp tục và xâu chuỗi lại với nhau (nối) các phần chúng ta cần tạo cho một câu lệnh UPDATE và có câu lệnh SELECT trả về các câu lệnh thực mà chúng tôi cần chạy để cập nhật cột Foo , về cơ bản thế này:

UPDATE `mydatabase`.`mytable` SET `Foo` = 0 

Nhưng chúng tôi muốn thay thế các giá trị từ table_schema table_name thay cho mydatabase mytable . Nếu chúng tôi chạy SELECT này

SELECT 'UPDATE `mydatabase`.`mytable` SET `Foo` = 0' AS sql

Điều đó trả về cho chúng ta một hàng duy nhất, chứa một cột duy nhất (cột này có tên là sql , nhưng tên của cột không quan trọng đối với chúng tôi). Giá trị của cột sẽ chỉ là một chuỗi. Nhưng chuỗi mà chúng tôi nhận lại tình cờ là (chúng tôi hy vọng) là một câu lệnh SQL mà chúng tôi có thể chạy.

Chúng tôi sẽ nhận được điều tương tự nếu chúng tôi bẻ chuỗi đó thành nhiều mảnh và sử dụng CONCAT để xâu chuỗi chúng lại với nhau cho chúng tôi, ví dụ:

SELECT CONCAT('UPDATE `','mydatabase','`.`','mytable','` SET `Foo` = 0') AS sql

Chúng tôi có thể sử dụng truy vấn đó làm mô hình cho câu lệnh mà chúng tôi muốn chạy với information_schema.columns . Chúng tôi sẽ thay thế 'mydatabase' 'mytable' với các tham chiếu đến các cột từ information_schema.columns bảng cung cấp cho chúng tôi cơ sở dữ liệu và tên_bảng.

SELECT CONCAT('UPDATE `',c.table_schema,'`.`',c.table_name,'` SET `Foo` = 0') AS sql
  FROM information_schema.columns 
 WHERE c.column_name = 'Foo'

Có một số cơ sở dữ liệu mà chúng tôi chắc chắn không muốn cập nhật ... mysql , information_schema , performance_schema . Chúng tôi cần đưa vào danh sách trắng các cơ sở dữ liệu có chứa bảng mà chúng tôi muốn cập nhật

  AND c.table_schema IN ('mydatabase','anotherdatabase')

- hoặc - chúng tôi cần đưa vào danh sách đen những cơ sở dữ liệu mà chúng tôi chắc chắn không muốn cập nhật

  AND c.table_schema NOT IN ('mysql','information_schema','performance_schema')

Chúng tôi có thể chạy truy vấn đó (chúng tôi có thể thêm ORDER BY nếu chúng ta muốn các hàng được trả về theo một thứ tự cụ thể) và những gì chúng ta nhận lại là danh sách chứa các câu lệnh mà chúng ta muốn chạy. Nếu chúng tôi lưu tập hợp chuỗi đó dưới dạng tệp văn bản thuần túy (không bao gồm hàng tiêu đề và định dạng bổ sung), thêm dấu chấm phẩy ở cuối mỗi dòng, chúng tôi sẽ có một tệp mà chúng tôi có thể thực thi từ mã mysql> máy khách dòng lệnh.

(Nếu bất kỳ điều nào ở trên gây nhầm lẫn, hãy cho tôi biết.)

Phần tiếp theo phức tạp hơn một chút. Phần còn lại của phần này đề cập đến một giải pháp thay thế để lưu đầu ra từ SELECT dưới dạng tệp văn bản thuần túy và thực thi các câu lệnh từ mysql máy khách dòng lệnh.

MySQL cung cấp một cơ sở / tính năng cho phép chúng tôi thực thi về cơ bản bất kỳ chuỗi dưới dạng câu lệnh SQL, trong ngữ cảnh của chương trình được lưu trữ MySQL (ví dụ:một thủ tục được lưu trữ. Tính năng chúng tôi sẽ sử dụng được gọi là dynamic SQL .

Để sử dụng SQL động , chúng tôi sử dụng các câu lệnh PREPARE , THỰC HIỆN DEALLOCATE PREPARE . (Thỏa thuận phân bổ không thực sự cần thiết, MySQL sẽ dọn dẹp cho chúng tôi nếu chúng tôi không sử dụng nó, nhưng tôi nghĩ dù sao cũng nên làm điều đó.)

Một lần nữa, SQL động có sẵn CHỈ trong ngữ cảnh của một chương trình được lưu trữ MySQL. Để làm điều này, chúng ta cần có một chuỗi chứa câu lệnh SQL mà chúng ta muốn thực thi. Ví dụ đơn giản, giả sử chúng ta có cái này:

DECLARE str VARCHAR(2000);
SET str = 'UPDATE mytable SET mycol = 0 WHERE mycol < 0';

Để lấy nội dung của str được đánh giá và thực thi như một câu lệnh SQL, phác thảo cơ bản là:

PREPARE stmt FROM str;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

Phần phức tạp tiếp theo là đặt điều đó cùng với truy vấn mà chúng tôi đang chạy để nhận giá trị chuỗi mà chúng tôi muốn thực thi dưới dạng câu lệnh SQL. Để làm điều đó, chúng tôi đặt một vòng lặp con trỏ lại với nhau. Đề cương cơ bản cho điều đó là sử dụng câu lệnh SELECT của chúng tôi:

SELECT bah FROM humbug

Và biến nó thành một định nghĩa con trỏ:

DECLARE mycursor FOR SELECT bah FROM humbug ;

Những gì chúng ta muốn là thực thi điều đó và lặp qua các hàng mà nó trả về. Để thực hiện câu lệnh và chuẩn bị tập kết quả, chúng tôi "mở" con trỏ

OPEN mycursor; 

Khi chúng tôi hoàn thành nó, chúng tôi sẽ đưa ra một "đóng", để phát hành tập kết quả, vì vậy máy chủ MySQL biết chúng tôi không cần nó nữa và có thể dọn dẹp và giải phóng tài nguyên được phân bổ cho tập hợp đó.

CLOSE mycursor;

Tuy nhiên, trước khi đóng con trỏ, chúng ta muốn "lặp" qua tập kết quả, tìm nạp từng hàng và làm điều gì đó với hàng đó. Câu lệnh mà chúng tôi sử dụng để chuyển hàng tiếp theo từ tập kết quả thành một biến thủ tục là:

FETCH mycursor INTO some_variable;

Trước khi có thể tìm nạp các hàng vào các biến, chúng ta cần xác định các biến, ví dụ:

DECLARE some_variable VARCHAR(2000); 

Vì con trỏ của chúng tôi (câu lệnh SELECT) chỉ trả về một cột duy nhất, chúng tôi chỉ cần một biến. Nếu chúng tôi có nhiều cột hơn, chúng tôi sẽ cần một biến cho mỗi cột.

Cuối cùng, chúng tôi đã tìm nạp hàng cuối cùng từ tập kết quả. Khi chúng tôi cố gắng tìm nạp cái tiếp theo, MySQL sẽ gặp lỗi.

Các ngôn ngữ lập trình khác sẽ cho phép chúng tôi thực hiện while vòng lặp và hãy để chúng tôi tìm nạp các hàng và thoát khỏi vòng lặp khi chúng tôi đã xử lý tất cả. MySQL phức tạp hơn. Để thực hiện một vòng lặp:

mylabel: LOOP
  -- do something
END LOOP mylabel;

Điều đó tự nó tạo nên một vòng lặp vô hạn rất tốt, bởi vì vòng lặp đó không có "lối ra". May mắn thay, MySQL cung cấp cho chúng ta LEAVE câu lệnh như một cách để thoát khỏi một vòng lặp. Chúng tôi thường không muốn thoát khỏi vòng lặp ngay lần đầu tiên chúng tôi nhập nó, vì vậy thường có một số kiểm tra có điều kiện mà chúng tôi sử dụng để xác định xem chúng tôi đã hoàn thành chưa và nên thoát khỏi vòng lặp hay chúng tôi chưa hoàn thành và nên đi vòng lại vòng lặp lại.

 mylabel: LOOP
     -- do something useful
     IF some_condition THEN 
         LEAVE mylabel;
     END IF;
 END LOOP mylabel;

Trong trường hợp của chúng tôi, chúng tôi muốn lặp lại tất cả các hàng trong tập kết quả, vì vậy chúng tôi sẽ đặt một FETCH câu lệnh đầu tiên bên trong vòng lặp (điều hữu ích mà chúng tôi muốn làm).

Để có được mối liên hệ giữa lỗi mà MySQL ném ra khi chúng tôi cố gắng tìm nạp qua hàng cuối cùng trong tập kết quả và kiểm tra có điều kiện, chúng tôi phải xác định xem chúng tôi có nên rời khỏi ...

MySQL cung cấp một cách để chúng tôi xác định một TIẾP TỤC XỬ LÝ (một số câu lệnh chúng tôi muốn thực hiện) khi lỗi được ném ra ...

 DECLARE CONTINUE HANDLER FOR NOT FOUND 

Hành động chúng tôi muốn thực hiện là đặt một biến thành TRUE.

 SET done = TRUE;

Trước khi có thể chạy SET, chúng ta cần xác định biến:

 DECLARE done TINYINT(1) DEFAULT FALSE;

Với điều đó, chúng tôi có thể thay đổi LOOP của mình để kiểm tra xem đã xong biến được đặt thành TRUE, làm điều kiện thoát, vì vậy vòng lặp của chúng ta trông giống như sau:

 mylabel: LOOP
     FETCH mycursor INTO some_variable;
     IF done THEN 
         LEAVE mylabel;
     END IF;
     -- do something with the row
 END LOOP mylabel;

"Làm điều gì đó với hàng" là nơi chúng tôi muốn lấy nội dung của some_variable và làm điều gì đó hữu ích với nó. Con trỏ của chúng tôi đang trả về cho chúng tôi một chuỗi mà chúng tôi muốn thực thi dưới dạng một câu lệnh SQL. Và MySQL cung cấp cho chúng ta SQL động tính năng mà chúng tôi có thể sử dụng để làm điều đó.

LƯU Ý:MySQL có các quy tắc về thứ tự của các câu lệnh trong thủ tục. Ví dụ: DECLARE tuyên bố phải xuất hiện ở đầu. Và tôi nghĩ BỘ XỬ LÝ TIẾP TỤC phải là thứ cuối cùng được khai báo.

Một lần nữa: Con trỏ SQL động các tính năng có sẵn CHỈ trong ngữ cảnh của một chương trình được lưu trữ MySQL, chẳng hạn như một thủ tục được lưu trữ. Ví dụ tôi đưa ra ở trên chỉ là ví dụ của body của một thủ tục.

Để tạo điều này dưới dạng một thủ tục được lưu trữ, nó sẽ cần được kết hợp như một phần của một cái gì đó như sau:

DELIMITER $$

DROP PROCEDURE IF EXISTS myproc $$

CREATE PROCEDURE myproc 
NOT DETERMINISTIC
MODIFIES SQL DATA
BEGIN

   -- procedure body goes here

END$$

DELIMITER ;

Hy vọng rằng điều đó giải thích ví dụ tôi đã đưa ra một cách chi tiết hơn.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Tìm tất cả cha mẹ trong bảng mysql với một truy vấn duy nhất (Truy vấn đệ quy)

  2. Đăng dữ liệu Biểu mẫu lên MySQL bằng nodejs w / Express

  3. Kết nối MySQL từ xa trong PHP

  4. Làm cách nào để lấy tên cột của bảng trong cơ sở dữ liệu bằng zend?

  5. Cách quản lý cơ sở dữ liệu của bạn với Adminer