sql >> Databáze >  >> RDS >> Mysql

Jak používat role, které se změnily v MySQL 8.0

Zabezpečení databáze je důležité pro jakékoli nastavení MySQL. Uživatelé jsou základem každého systému. Pokud jde o databázové systémy, obecně o nich uvažuji ve dvou odlišných skupinách:

  1. Uživatelé aplikací, služeb nebo programů - v podstatě zákazníci nebo klienti využívající službu.
  2. Vývojáři databází, administrátoři, analytici atd… - Ti, kteří spravují databázovou infrastrukturu, s ní pracují nebo ji monitorují.

I když každý uživatel potřebuje přistupovat k databázi na určité úrovni, tato oprávnění nejsou všechna stejná.

Klienti a zákazníci například potřebují přístup ke svým datům „souvisejícího uživatelského účtu“, ale i to by mělo být monitorováno s určitou úrovní kontroly. Některé tabulky a data by však měly být přísně zakázány (např. systémové tabulky).

Přesto:

  • Analytici potřebují 'přístup pro čtení ', k získání informací a náhledů pomocí tabulek dotazování…
  • Vývojáři potřebují k provádění své práce spoustu oprávnění a privilegií…
  • Ke spuštění pořadu potřebuje DBA oprávnění „root“ nebo podobná oprávnění…
  • Kupující služby potřebují vidět historii svých objednávek a plateb…

Dokážete si představit (já vím, že ano), jak obtížný je úkol spravovat více uživatelů nebo skupin uživatelů v rámci databázového ekosystému.

Ve starších verzích MySQL je prostředí pro více uživatelů vytvořeno poněkud monotónním a opakujícím se způsobem.

Přesto verze 8 implementuje výjimečnou a výkonnou standardní funkci SQL - Role - , která zmírňuje jednu z více nadbytečných oblastí celého procesu:přidělování oprávnění uživateli.

Jaká je tedy role v MySQL?

Určitě můžete navštívit MySQL v roce 2018:Co je v 8.0 a další pozorování, napsal jsem pro blog Somenines zde, kde zmiňuji role pro přehled na vysoké úrovni. Nicméně tam, kde jsem je pouze shrnul, tento aktuální příspěvek vypadá hlouběji a zaměřuje se pouze na role.

Zde je návod, jak online dokumentace MySQL definuje roli:"Role MySQL je pojmenovaná kolekce oprávnění."

Nezdá se vám tato definice užitečná?

Ale jak?

Uvidíme v následujících příkladech.

Upozornění na uvedené příklady

Příklady zahrnuté v tomto příspěvku jsou v osobní „jednouživatelské“ vývojové a výukové pracovní stanici/prostředí, takže si buďte jisti a implementujte ty osvědčené postupy, které jsou pro vás přínosem pro vaše konkrétní potřeby nebo požadavky. Předvedená uživatelská jména a hesla jsou čistě libovolná a slabá.

Uživatelé a oprávnění v předchozích verzích

V MySQL 5.7 role neexistují. Přidělování oprávnění uživatelům se provádí individuálně. Abychom lépe porozuměli tomu, co role poskytují, nepoužívejte je. To nedává vůbec žádný smysl, já vím. Ale jak budeme postupovat přes příspěvek, bude.

Níže vytvoříme některé uživatele:

CREATE USER 'reader_1'@'localhost' IDENTIFIED BY 'some_password'; 
CREATE USER 'reader_writer'@'localhost' IDENTIFIED BY 'another_password'; 
CREATE USER 'changer_1'@'localhost' IDENTIFIED BY 'a_password';

Poté jsou těmto uživatelům udělena některá oprávnění:

GRANT SELECT ON some_db.specific_table TO 'reader_1'@'localhost';
GRANT SELECT, INSERT ON some_db.specific_table TO 'reader_writer'@'localhost';
GRANT UPDATE, DELETE ON some_db.specific_table TO 'changer_1'@'localhost';

Uf, jsem rád, že je konec. Nyní zpět k…

A stejně tak máte požadavek na implementaci dalších dvou uživatelů „pouze pro čtení“…

Zpět na rýsovací prkno:

CREATE USER 'reader_2'@'localhost' IDENTIFIED BY 'password_2'; 
CREATE USER 'reader_3'@'localhost' IDENTIFIED BY 'password_3';

Přidělte jim také oprávnění:

GRANT SELECT ON some_db.specific_table TO 'reader_2'@'localhost';
GRANT ALL ON some_db.specific_table TO 'reader_3'@'localhost';

Vidíte, jak je to méně produktivní, plné opakování a náchylné k chybám? Ale co je důležitější, zachytili jste chybu?

Dobře pro vás!

Při udělování oprávnění těmto dvěma dalším uživatelům jsem náhodou udělil VŠECHNA oprávnění novému uživateli reader_3.

Jejda.

Chyba, kterou může udělat každý.

Zadejte role MySQL

S rolemi, mnoho z výše uvedených systematických přidělování a delegování oprávnění lze poněkud zjednodušit .

Vytváření uživatelů v zásadě zůstává stejné, ale liší se přidělování oprávnění prostřednictvím rolí:

mysql> CREATE USER 'reader_1'@'localhost' IDENTIFIED BY 'some_password';
Query OK, 0 rows affected (0.19 sec)
mysql> CREATE USER 'reader_writer'@'localhost' IDENTIFIED BY 'another_password';
Query OK, 0 rows affected (0.22 sec)
mysql> CREATE USER 'changer_1'@'localhost' IDENTIFIED BY 'a_password';
Query OK, 0 rows affected (0.08 sec)
mysql> CREATE USER 'reader_2'@'localhost' IDENTIFIED BY 'password_2';
Query OK, 0 rows affected (0.28 sec)
mysql> CREATE USER 'reader_3'@'localhost' IDENTIFIED BY 'password_3';
Query OK, 0 rows affected (0.12 sec)

Při dotazu na systémovou tabulku mysql.user můžete vidět, že tito nově vytvoření uživatelé existují:

(Poznámka:V tomto výukovém/vývojovém prostředí mám několik uživatelských účtů a pro lepší přehlednost na obrazovce jsem potlačil většinu výstupu.)

mysql> SELECT User FROM mysql.user;
+------------------+
| User             |
+------------------+
| changer_1        |
| mysql.infoschema |
| mysql.session    |
| mysql.sys        |
| reader_1         |
| reader_2         |
| reader_3         |
| reader_writer    |
| root             |
|                  | --multiple rows remaining here...
+------------------+
23 rows in set (0.00 sec)

Mám tuto libovolnou tabulku a ukázková data:

mysql> SELECT * FROM name;
+--------+------------+
| f_name | l_name     |
+--------+------------+
| Jim    | Dandy      |
| Johhny | Applesauce |
| Ashley | Zerro      |
| Ashton | Zerra      |
| Ashmon | Zerro      |
+--------+------------+
5 rows in set (0.00 sec)

Pojďme nyní pomocí rolí vytvořit a přiřadit oprávnění pro nové uživatele používat tabulku jmen.

Nejprve vytvořte role:

mysql> CREATE ROLE main_read_only;
Query OK, 0 rows affected (0.11 sec)
mysql> CREATE ROLE main_read_write;
Query OK, 0 rows affected (0.11 sec)
mysql> CREATE ROLE main_changer;
Query OK, 0 rows affected (0.14 sec)

Všimněte si znovu tabulky mysql.user:

mysql> SELECT User FROM mysql.user;
+------------------+
| User             |
+------------------+
| main_changer     |
| main_read_only   |
| main_read_write  |
| changer_1        |
| mysql.infoschema |
| mysql.session    |
| mysql.sys        |
| reader_1         |
| reader_2         |
| reader_3         |
| reader_writer    |
| root             |
|                  |
+------------------+
26 rows in set (0.00 sec)

Na základě tohoto výstupu můžeme usuzovat; že ve vší podstatě jsou role ve skutečnosti sami uživatelé.

Dále přiřazení oprávnění:

mysql> GRANT SELECT ON practice.name TO 'main_read_only';
Query OK, 0 rows affected (0.14 sec)
mysql> GRANT SELECT, INSERT ON practice.name TO 'main_read_write';
Query OK, 0 rows affected (0.07 sec)
mysql> GRANT UPDATE, DELETE ON practice.name TO 'main_changer';
Query OK, 0 rows affected (0.16 sec)

Krátká přestávka

Počkej chvíli. Mohu se pouze přihlásit a provádět úkoly se samotnými účty rolí? Koneckonců jsou to uživatelé a mají požadovaná oprávnění.

Zkusme se přihlásit do cvičné databáze s rolí main_changer:

:~$ mysql -u main_changer -p practice
Enter password: 
ERROR 1045 (28000): Access denied for user 'main_changer'@'localhost' (using password: YES

Prostý fakt, že se nám zobrazí výzva k zadání hesla, je dobrým znamením, že nemůžeme (alespoň v tuto chvíli). Jak si vzpomínáte, pro žádnou z rolí jsem při jejich vytváření nenastavil heslo.

Co má říkat sloupec authentication_string systémových tabulek mysql.user?

mysql> SELECT User, authentication_string, password_expired
    -> FROM mysql.user
    -> WHERE User IN ('main_read_only', 'root', 'main_read_write', 'main_changer')\G
*************************** 1. row ***************************
                 User: main_changer
authentication_string: 
     password_expired: Y
*************************** 2. row ***************************
                 User: main_read_only
authentication_string: 
     password_expired: Y
*************************** 3. row ***************************
                 User: main_read_write
authentication_string: 
     password_expired: Y
*************************** 4. row ***************************
                 User: root
authentication_string: ***various_jumbled_mess_here*&&*&*&*##
     password_expired: N
4 rows in set (0.00 sec)

Zahrnul jsem uživatele root mezi názvy rolí pro kontrolu predikátu IN(), abych jednoduše ukázal, že má autentizační_řetězec, kde role nemají.

Tato pasáž v dokumentaci CREATE ROLE to pěkně objasňuje:"Role při vytvoření je uzamčena, nemá žádné heslo a je jí přiřazen výchozí ověřovací plugin. (Tyto atributy role mohou být později změněny pomocí příkazu ALTER USER, uživatelé, kteří mají globální oprávnění CREATE USER.)"

Zpět k aktuální úloze, nyní můžeme uživatelům přidělit role na základě jejich potřebné úrovně oprávnění.

Všimněte si, že v příkazu není přítomna žádná klauzule ON:

mysql> GRANT 'main_read_only' TO 'reader_1'@'localhost', 'reader_2'@'localhost', 'reader_3'@'localhost';
Query OK, 0 rows affected (0.13 sec)
mysql> GRANT 'main_read_write' TO 'reader_writer'@'localhost';
Query OK, 0 rows affected (0.16 sec)
mysql> GRANT 'main_changer', 'main_read_only' TO 'changer_1'@'localhost';
Query OK, 0 rows affected (0.13 sec)

Pokud použijete nějaký druh 'konvence pojmenování, může to být méně matoucí ' při stanovování názvů rolí (nevím, jestli MySQL v současné době nějaké poskytuje... Komunita?), pokud pro nic jiného, ​​než pro vizuální rozlišení mezi nimi a běžnými uživateli „bez rolí“.

Zbývá ještě něco udělat

To bylo super snadné, že?

Méně nadbytečné než starý způsob přidělení oprávnění.

Nechme tyto uživatele nyní pracovat.

Můžeme vidět udělená oprávnění pro uživatele se syntaxí SHOW GRANTS. Zde je to, co je aktuálně přiřazeno uživatelskému účtu reader_1:

mysql> SHOW GRANTS FOR 'reader_1'@'localhost';
+------------------------------------------------------+
| Grants for [email protected]                        |
+------------------------------------------------------+
| GRANT USAGE ON *.* TO `reader_1`@`localhost`         |
| GRANT `main_read_only`@`%` TO `reader_1`@`localhost` |
+------------------------------------------------------+
2 rows in set (0.02 sec)

Ačkoli to poskytuje informativní výstup, můžete 'vyladit ' prohlášení pro ještě podrobnější informace o jakýchkoli přesných oprávněních, která přiřazená role poskytuje, zahrnutím klauzule USING do příkazu SHOW GRANTS a pojmenováním názvu přiřazené role:

mysql> SHOW GRANTS FOR 'reader_1'@'localhost' USING 'main_read_only';
+-------------------------------------------------------------+
| Grants for [email protected]                               |
+-------------------------------------------------------------+
| GRANT USAGE ON *.* TO `reader_1`@`localhost`                |
| GRANT SELECT ON `practice`.`name` TO `reader_1`@`localhost` |
| GRANT `main_read_only`@`%` TO `reader_1`@`localhost`        |
+-------------------------------------------------------------+
3 rows in set (0.00 sec)

Po přihlášení pomocí reader_1:

mysql> SELECT * FROM practice.name;
ERROR 1142 (42000): SELECT command denied to user 'reader_1'@'localhost' for table 'name'

To si děláš srandu? Tomuto uživateli byla udělena oprávnění SELECT prostřednictvím role main_read_only.

Abychom to prozkoumali, pojďme navštívit 2 nové tabulky ve verzi 8, konkrétně pro role.

Tabulka mysql.role_edges ukazuje, jaké role byly přiděleny všem uživatelům:

mysql> SELECT * FROM mysql.role_edges;
+-----------+-----------------+-----------+---------------+-------------------+
| FROM_HOST | FROM_USER       | TO_HOST   | TO_USER       | WITH_ADMIN_OPTION |
+-----------+-----------------+-----------+---------------+-------------------+
| %         | main_changer    | localhost | changer_1     | N                 |
| %         | main_read_only  | localhost | changer_1     | N                 |
| %         | main_read_only  | localhost | reader_1      | N                 |
| %         | main_read_only  | localhost | reader_2      | N                 |
| %         | main_read_only  | localhost | reader_3      | N                 |
| %         | main_read_write | localhost | reader_writer | N                 |
+-----------+-----------------+-----------+---------------+-------------------+
6 rows in set (0.00 sec)

Ale mám pocit, že další dodatečná tabulka, mysql.default_roles, nám lépe pomůže vyřešit problémy SELECT pro uživatele reader_1:

mysql> DESC mysql.default_roles;
+-------------------+----------+------+-----+---------+-------+
| Field             | Type     | Null | Key | Default | Extra |
+-------------------+----------+------+-----+---------+-------+
| HOST              | char(60) | NO   | PRI |         |       |
| USER              | char(32) | NO   | PRI |         |       |
| DEFAULT_ROLE_HOST | char(60) | NO   | PRI | %       |       |
| DEFAULT_ROLE_USER | char(32) | NO   | PRI |         |       |
+-------------------+----------+------+-----+---------+-------+
4 rows in set (0.00 sec)
mysql> SELECT * FROM mysql.default_roles;
Empty set (0.00 sec)

Sada prázdných výsledků.

Ukázalo se, že aby uživatel mohl používat roli - a nakonec i oprávnění – musí mít uživatel přiřazenou výchozí roli.

mysql> SET DEFAULT ROLE main_read_only TO 'reader_1'@'localhost', 'reader_2'@'localhost', 'reader_3'@'localhost';
Query OK, 0 rows affected (0.11 sec)

(Výchozí role může být přiřazena více uživatelům v jednom příkazu, jak je uvedeno výše…)

mysql> SET DEFAULT ROLE main_read_only, main_changer TO 'changer_1'@'localhost';
Query OK, 0 rows affected (0.10 sec)

(Uživatel může mít specifikovaných více výchozích rolí jako v případě uživatele changer_1…)

Uživatel reader_1 je nyní přihlášen...

mysql> SELECT CURRENT_USER();
+--------------------+
| CURRENT_USER()     |
+--------------------+
| [email protected] |
+--------------------+
1 row in set (0.00 sec)
mysql> SELECT CURRENT_ROLE();
+----------------------+
| CURRENT_ROLE()       |
+----------------------+
| `main_read_only`@`%` |
+----------------------+
1 row in set (0.03 sec)

Vidíme aktuálně aktivní roli a také to, že reader_1 nyní může zadávat příkazy SELECT:

mysql> SELECT * FROM practice.name;
+--------+------------+
| f_name | l_name     |
+--------+------------+
| Jim    | Dandy      |
| Johhny | Applesauce |
| Ashley | Zerro      |
| Ashton | Zerra      |
| Ashmon | Zerro      |
+--------+------------+
5 rows in set (0.00 sec)

Další skryté nuance

Je tu ještě jedna důležitá část skládačky musíme pochopit.

Potenciálně existují 3 různé „úrovně“ nebo „varianty“ přiřazení rolí:

SET ROLE …;
SET DEFAULT ROLE …;
SET ROLE DEFAULT …;

UDĚLUJI další roli uživateli reader_1 a poté se s tímto uživatelem přihlásím (nezobrazeno):

mysql> GRANT 'main_read_write' TO 'reader_1'@'localhost';
Query OK, 0 rows affected (0.17 sec)

Vzhledem k tomu, že role main_read_write má oprávnění INSERT, může nyní uživatel reader_1 tento příkaz spustit, že?

mysql> INSERT INTO name(f_name, l_name)
    -> VALUES('Josh', 'Otwell');
ERROR 1142 (42000): INSERT command denied to user 'reader_1'@'localhost' for table 'name'

Co se tady děje?

To může pomoci...

mysql> SELECT CURRENT_ROLE();
+----------------------+
| CURRENT_ROLE()       |
+----------------------+
| `main_read_only`@`%` |
+----------------------+
1 row in set (0.00 sec)

Připomeňme, že jsme zpočátku nastavili uživatele reader_1 jako výchozí roli main_read_only. Zde musíme použít jednu z těchto odlišných „úrovní“ toho, co volně nazývám 'nastavení role':

mysql> SET ROLE main_read_write;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT CURRENT_ROLE();
+-----------------------+
| CURRENT_ROLE()        |
+-----------------------+
| `main_read_write`@`%` |
+-----------------------+
1 row in set (0.00 sec)

Nyní zkuste tento INSERT znovu:

mysql> INSERT INTO name(f_name, l_name)
    -> VALUES('Josh', 'Otwell');
Query OK, 1 row affected (0.12 sec)

Jakmile se však uživatel reader_1 odhlásí, role main_read_write již nebude aktivní, když se reader_1 opět přihlásí. Přestože má uživatel read_1 přidělenou roli main_read_write, není výchozí.

Pojďme se nyní seznámit s 3. 'úrovní' 'nastavení role', SET ROLE DEFAULT.

Předpokládejme, že uživatel reader_1 ještě nemá přiřazené žádné role:

mysql> SHOW GRANTS FOR 'reader_1'@'localhost';
+----------------------------------------------+
| Grants for [email protected]                |
+----------------------------------------------+
| GRANT USAGE ON *.* TO `reader_1`@`localhost` |
+----------------------------------------------+
1 row in set (0.00 sec)

UDĚLEME tomuto uživateli 2 role:

mysql> GRANT 'main_changer', 'main_read_write' TO 'reader_1'@'localhost';
Query OK, 0 rows affected (0.07 sec)

Přiřadit výchozí roli:

mysql> SET DEFAULT ROLE ‘main_changer’ TO 'reader_1'@'localhost';
Query OK, 0 rows affected (0.17 sec)

Poté s přihlášeným uživatelem reader_1 je tato výchozí role aktivní:

mysql> SELECT CURRENT_ROLE();
+--------------------+
| CURRENT_ROLE()     |
+--------------------+
| `main_changer`@`%` |
+--------------------+
1 row in set (0.00 sec)

Nyní přepněte na roli main_read_write:

mysql> SET ROLE 'main_read_write';
Query OK, 0 rows affected (0.01 sec)
mysql> SELECT CURRENT_ROLE();
+-----------------------+
| CURRENT_ROLE()        |
+-----------------------+
| `main_read_write`@`%` |
+-----------------------+
1 row in set (0.00 sec)

Chcete-li se však vrátit zpět k přiřazené výchozí roli, použijte SET ROLE DEFAULT, jak je znázorněno níže:

mysql> SET ROLE DEFAULT;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT CURRENT_ROLE();
+--------------------+
| CURRENT_ROLE()     |
+--------------------+
| `main_changer`@`%` |
+--------------------+
1 row in set (0.00 sec)

Role nejsou uděleny

I když má uživatel changer_1 během relace k dispozici 2 role:

mysql> SELECT CURRENT_ROLE();
+-----------------------------------------+
| CURRENT_ROLE()                          |
+-----------------------------------------+
| `main_changer`@`%`,`main_read_only`@`%` |
+-----------------------------------------+
1 row in set (0.00 sec)

Co se stane, když se pokusíte nastavit uživateli roli, která mu nebyla udělena?

mysql> SET ROLE main_read_write;
ERROR 3530 (HY000): `main_read_write`@`%` is not granted to `changer_1`@`localhost`

Zamítnuto.

Taketh Away

Žádný systém správy uživatelů by nebyl úplný bez možnosti omezit nebo dokonce odebrat přístup k určitým operacím, pokud by to bylo potřeba.

Máme k dispozici příkaz SQL REVOKE pro odebrání oprávnění uživatelům a rolím.

Připomeňme, že role main_changer má tuto sadu oprávnění, v podstatě všichni uživatelé, kterým byla tato role udělena, také:

mysql> SHOW GRANTS FOR main_changer;
+-----------------------------------------------------------------+
| Grants for [email protected]%                                       |
+-----------------------------------------------------------------+
| GRANT USAGE ON *.* TO `main_changer`@`%`                        |
| GRANT UPDATE, DELETE ON `practice`.`name` TO `main_changer`@`%` |
+-----------------------------------------------------------------+
2 rows in set (0.00 sec)
mysql> REVOKE DELETE ON practice.name FROM 'main_changer';
Query OK, 0 rows affected (0.11 sec)
mysql> SHOW GRANTS FOR main_changer;
+---------------------------------------------------------+
| Grants for [email protected]%                               |
+---------------------------------------------------------+
| GRANT USAGE ON *.* TO `main_changer`@`%`                |
| GRANT UPDATE ON `practice`.`name` TO `main_changer`@`%` |
+---------------------------------------------------------+
2 rows in set (0.00 sec)

Chcete-li vědět, jaké uživatele tato změna ovlivnila, můžeme znovu navštívit tabulku mysql.role_edges:

mysql> SELECT * FROM mysql.role_edges WHERE FROM_USER = 'main_changer';
+-----------+--------------+-----------+-----------+-------------------+
| FROM_HOST | FROM_USER    | TO_HOST   | TO_USER   | WITH_ADMIN_OPTION |
+-----------+--------------+-----------+-----------+-------------------+
| %         | main_changer | localhost | changer_1 | N                 |
+-----------+--------------+-----------+-----------+-------------------+
1 row in set (0.00 sec)

A vidíme, že uživatel changer_1 již nemá oprávnění DELETE:

mysql> SHOW GRANTS FOR 'changer_1'@'localhost' USING 'main_changer';
+--------------------------------------------------------------------------+
| Grants for [email protected]                                           |
+--------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO `changer_1`@`localhost`                            |
| GRANT UPDATE ON `practice`.`name` TO `changer_1`@`localhost`             |
| GRANT `main_changer`@`%`,`main_read_only`@`%` TO `changer_1`@`localhost` |
+--------------------------------------------------------------------------+
3 rows in set (0.00 sec)

A konečně, pokud se potřebujeme role úplně zbavit, máme k tomu příkaz DROP ROLE:

mysql> DROP ROLE main_read_only;
Query OK, 0 rows affected (0.17 sec)

A při dotazu na tabulku mysql.role_edges byla role main_read_only odstraněna:

mysql> SELECT * FROM mysql.role_edges;
+-----------+-----------------+-----------+---------------+-------------------+
| FROM_HOST | FROM_USER       | TO_HOST   | TO_USER       | WITH_ADMIN_OPTION |
+-----------+-----------------+-----------+---------------+-------------------+
| %         | main_changer    | localhost | changer_1     | N                 |
| %         | main_read_write | localhost | reader_1      | N                 |
| %         | main_read_write | localhost | reader_writer | N                 |
+-----------+-----------------+-----------+---------------+-------------------+
3 rows in set (0.00 sec)

(Bonus:Toto fantastické video na YouTube pro mě bylo skvělým zdrojem informací o rolích.)

Tento příklad vytvoření uživatele, přiřazení role a nastavení je přinejlepším základní. Přesto mají role svůj vlastní soubor pravidel, díky nimž nejsou triviální. Doufám, že jsem prostřednictvím tohoto příspěvku na blogu osvětlil ty oblasti, které jsou méně intuitivní než ostatní, a umožním tak čtenářům lépe porozumět potenciálnímu využití rolí v jejich systémech.

Děkuji za přečtení.


  1. Funkce UPPER() v Oracle

  2. Doporučené postupy replikace PostgreSQL – část 1

  3. Rychlejší načítání velkých dat

  4. Oracle SQL pro změnu typu sloupce z čísla na varchar2, když obsahuje data