Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Jak wybrać wszystkie tabele z nazwą kolumny i zaktualizować tę kolumnę?

Nie, nie w jednym oświadczeniu.

Aby uzyskać nazwy wszystkich tabel zawierających kolumnę o nazwie Foo :

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

Wtedy będziesz potrzebować instrukcji UPDATE dla każdej tabeli. (Możliwe jest aktualizowanie wielu tabel w jednej instrukcji, ale musiałoby to być (niepotrzebne) połączenie krzyżowe.) Lepiej zrobić każdą tabelę osobno.

Możesz użyć dynamicznego SQL do wykonania instrukcji UPDATE w programie przechowywanym w MySQL (np. PROCEDURA)

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

Jeśli zadeklarujesz kursor do wyboru z information_schema.tables, możesz użyć pętli kursora do przetworzenia dynamicznej UPDATE oświadczenie dla każdej zwróconej nazwy_tabeli.

  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;

(To tylko przybliżony zarys przykładu, a nie sprawdzanie lub testowanie składni.)

KONTYNUACJA

Kilka krótkich notatek na temat niektórych pomysłów, które prawdopodobnie zostały pominięte w powyższej odpowiedzi.

Aby uzyskać nazwy tabel zawierających kolumnę Foo , możemy uruchomić zapytanie z information_schema.columns stół. (To jedna z tabel zawartych w MySQL information_schema bazy danych.)

Ponieważ możemy mieć tabele w wielu bazach danych, nazwa_tabeli nie wystarcza do zidentyfikowania tabeli; musimy wiedzieć, w jakiej bazie danych znajduje się tabela. Zamiast oszukiwać za pomocą „use db ", zanim uruchomimy UPDATE , możemy po prostu odwołać się do tabeli UPDATE db.mytable SET Foo... .

Możemy użyć naszego zapytania information_schema.columns aby przejść dalej i połączyć (konkatenować) części, które musimy utworzyć dla instrukcji UPDATE, i aby SELECT zwrócił rzeczywiste instrukcje, które musielibyśmy uruchomić, aby zaktualizować kolumnę Foo , w zasadzie to:

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

Ale chcemy podstawić wartości z table_schema i table_name zamiast mydatabase i mytable . Jeśli uruchomimy to WYBIERZ

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

To zwraca nam pojedynczy wiersz zawierający pojedynczą kolumnę (tak się składa, że ​​kolumna ma nazwę sql , ale nazwa kolumny nie jest dla nas ważna). Wartość kolumny będzie po prostu ciągiem. Ale ciąg, który otrzymujemy, jest (mamy nadzieję) instrukcją SQL, którą możemy uruchomić.

Otrzymalibyśmy to samo, gdybyśmy rozbili ten sznurek na kawałki i użyli CONCAT, aby połączyć je z powrotem dla nas, np.

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

Możemy użyć tego zapytania jako modelu dla instrukcji, którą chcemy uruchomić na information_schema.columns . Zamienimy 'mydatabase' i 'mytable' z odwołaniami do kolumn z information_schema.columns tabela, która daje nam bazę danych i nazwę tabeli.

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

Istnieje kilka baz danych, których zdecydowanie nie chcesz zaktualizować... mysql , information_schema , performance_schema . Potrzebujemy albo białej listy baz danych zawierających tabelę, którą chcemy zaktualizować

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

-lub - musimy umieścić na czarnej liście bazy danych, których zdecydowanie nie chcemy aktualizować

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

Możemy uruchomić to zapytanie (możemy dodać ORDER BY jeśli chcemy, aby wiersze były zwracane w określonej kolejności), a otrzymujemy listę zawierającą instrukcje, które chcemy uruchomić. Gdybyśmy zapisali ten zestaw ciągów jako zwykły plik tekstowy (z wyłączeniem wiersza nagłówka i dodatkowego formatowania), dodając średnik na końcu każdej linii, mielibyśmy plik, który moglibyśmy wykonać z kodu mysql> klient wiersza poleceń.

(Jeśli którekolwiek z powyższych jest mylące, daj mi znać.)

Następna część jest nieco bardziej skomplikowana. Reszta tego dotyczy alternatywy do zapisywania danych wyjściowych z SELECT jako zwykłego pliku tekstowego i wykonywania instrukcji z mysql klient wiersza poleceń.

MySQL udostępnia narzędzie/funkcję, która pozwala nam wykonywać w zasadzie dowolne ciąg znaków jako instrukcja SQL w kontekście programu składowanego MySQL (na przykład procedury składowanej. Funkcja, której będziemy używać, nazywa się dynamiczny SQL .

Aby używać dynamicznego SQL , używamy instrukcji PREPARE , EXECUTE i DEALLOCATE PREPARE . (Zwolnienie nie jest konieczne, MySQL oczyści za nas, jeśli go nie użyjemy, ale myślę, że i tak warto to zrobić).

Ponownie, dynamiczny SQL jest dostępny TYLKO w kontekście programu przechowywanego w MySQL. Aby to zrobić, musimy mieć ciąg znaków zawierający instrukcję SQL, którą chcemy wykonać. Jako prosty przykład załóżmy, że mamy to:

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

Aby pobrać zawartość str oceniane i wykonywane jako instrukcja SQL, podstawowy zarys to:

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

Kolejną skomplikowaną częścią jest zestawienie tego wraz z zapytaniem, które wykonujemy, aby uzyskać wartość ciągu, którą chcemy wykonać jako instrukcje SQL. Aby to zrobić, tworzymy pętlę kursora. Podstawowym zarysem tego jest skorzystanie z naszej instrukcji SELECT:

SELECT bah FROM humbug

I zamień to w definicję kursora:

DECLARE mycursor FOR SELECT bah FROM humbug ;

Chcemy to wykonać i przejść przez zwracane wiersze. Aby wykonać instrukcję i przygotować zestaw wyników, „otwieramy” kursor

OPEN mycursor; 

Kiedy to skończymy, wydamy "zamknięcie", aby opublikować zestaw wyników, aby serwer MySQL wiedział, że już go nie potrzebujemy, i może oczyścić i zwolnić przydzielone do tego zasoby.

CLOSE mycursor;

Ale zanim zamkniemy kursor, chcemy "zapętlić" zestaw wyników, pobrać każdy wiersz i zrobić coś z wierszem. Instrukcja, której używamy do pobrania następnego wiersza ze zbioru wyników do zmiennej procedury, to:

FETCH mycursor INTO some_variable;

Zanim będziemy mogli pobrać wiersze do zmiennych, musimy zdefiniować zmienne, np.

DECLARE some_variable VARCHAR(2000); 

Ponieważ nasz kursor (wyrażenie SELECT) zwraca tylko jedną kolumnę, potrzebujemy tylko jednej zmiennej. Gdybyśmy mieli więcej kolumn, potrzebowalibyśmy zmiennej dla każdej kolumny.

W końcu pobierzemy ostatni wiersz ze zbioru wyników. Gdy spróbujemy pobrać następny, MySQL zgłosi błąd.

Inne języki programowania pozwolą nam po prostu wykonać while pętli i pobierzmy wiersze i wyjdźmy z pętli, gdy przetworzymy je wszystkie. MySQL jest bardziej tajemniczy. Aby zrobić pętlę:

mylabel: LOOP
  -- do something
END LOOP mylabel;

To samo w sobie tworzy bardzo dobrą nieskończoną pętlę, ponieważ ta pętla nie ma „wyjścia”. Na szczęście MySQL daje nam LEAVE instrukcja jako sposób na wyjście z pętli. Zazwyczaj nie chcemy wychodzić z pętli za pierwszym razem, gdy do niej wchodzimy, więc zwykle używamy testu warunkowego, którego używamy do określenia, czy skończyliśmy i czy powinniśmy wyjść z pętli, czy jeszcze nie skończyliśmy i powinniśmy go obejść pętla ponownie.

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

W naszym przypadku chcemy przejść przez wszystkie wiersze w zestawie wyników, więc umieścimy FETCH a pierwsza instrukcja wewnątrz pętli (coś przydatnego, co chcemy zrobić).

Aby uzyskać powiązanie między błędem, który zgłasza MySQL, gdy próbujemy pobrać ostatni wiersz w zestawie wyników, a testem warunkowym, musimy określić, czy powinniśmy wyjść...

MySQL umożliwia nam zdefiniowanie CONTINUE HANDLER (jakaś instrukcja, którą chcemy wykonać), gdy zostanie zgłoszony błąd...

 DECLARE CONTINUE HANDLER FOR NOT FOUND 

Akcja, którą chcemy wykonać, to ustawienie zmiennej na TRUE.

 SET done = TRUE;

Zanim będziemy mogli uruchomić SET, musimy zdefiniować zmienną:

 DECLARE done TINYINT(1) DEFAULT FALSE;

Dzięki temu możemy zmienić naszą LOOP, aby sprawdzić, czy done zmienna jest ustawiona na TRUE, jako warunek wyjścia, więc nasza pętla wygląda mniej więcej tak:

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

"Zrób coś z wierszem" to miejsce, w którym chcemy pobrać zawartość some_variable i zrób z nim coś pożytecznego. Nasz kursor zwraca nam ciąg, który chcemy wykonać jako instrukcję SQL. MySQL daje nam dynamiczny SQL funkcja, której możemy użyć do tego.

UWAGA:MySQL ma reguły dotyczące kolejności instrukcji w procedurze. Na przykład DECLARE oświadczenie musi przyjść na początku. I myślę, że KONTYNUACJA OBSŁUGI musi być ostatnią zadeklarowaną rzeczą.

Znowu:kursor i dynamiczny SQL funkcje są dostępne TYLKO w kontekście programu przechowywanego MySQL, takiego jak procedura składowana. Przykład, który podałem powyżej, był tylko przykładem ciała procedury.

Aby utworzyć to jako procedurę składowaną, musiałoby być włączone jako część czegoś takiego:

DELIMITER $$

DROP PROCEDURE IF EXISTS myproc $$

CREATE PROCEDURE myproc 
NOT DETERMINISTIC
MODIFIES SQL DATA
BEGIN

   -- procedure body goes here

END$$

DELIMITER ;

Mam nadzieję, że to wyjaśnia bardziej szczegółowo podany przeze mnie przykład.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Połączyć wiersz z wierszem MAX w innej tabeli?

  2. SQLSTATE[22007]:Nieprawidłowy format daty i godziny:1292 Niepoprawna wartość daty i godziny:„2008-03-30 02:56:12”

  3. mysql(i)_real_escape_string, na którym można bezpiecznie polegać?

  4. Połącz dwa zapytania mysql w jedno

  5. Środowisko pracy MySQL nie może połączyć się z serwerem bazy danych