Oracle
 sql >> Base de données >  >> RDS >> Oracle

EXPORT AS INSERT STATEMENTS :Mais dans SQL Plus, la ligne remplace 2 500 caractères !

Wow, ces contraintes sont assez limitantes mais je pense qu'il y a peut-être un moyen de les contourner. Je pense que vous devrez peut-être écrire votre propre petit script pour cela.

J'utiliserais Java avec JDBC moi-même (mais n'importe quel langage capable de se connecter et de lire la base de données, et de produire des chaînes, fera l'affaire), en écrivant un petit programme qui récupère un jeu d'enregistrements de chaque ligne de la base de données. Ensuite, pour chacune de ces lignes :

  • Construire une instruction d'insertion avec les données complètes. S'il s'agit de moins de 2 000 octets, il suffit de le sortir dans le fichier et de passer à la ligne suivante.

  • Sinon, créez une instruction d'insertion pour chaque champ, mais laissez le c13 champ comme '' (vide).

  • Ensuite, tant que votre c13input chaîne est supérieure à 2000 caractères, génère une instruction de mise à jour de la forme "update tbl set c13 = c13 || '" + c13input.substring (0,2000) + "' where ..." (en ajoutant les 2000 caractères suivants) puis faites c13input = c13input.substring(2000) pour supprimer ces caractères de votre chaîne.

  • Une fois c13input est inférieur ou égal à 2 000 caractères, il vous suffit de générer une dernière mise à jour pour y remédier à la fin.

Cela vous permet de conserver vos instructions SQL individuelles autour de la barre des 2000 caractères et d'exécuter efficacement le bon SQL pour repeupler une autre table de base de données.

C'est le genre de chose dont je parle (pour une table contenant juste une clé primaire c1 et un gros varchar honkin 'c13 ):

rowset r = db.exec ("select * from oldtable");
while r.next != NO_MORE_ROWS:
    string s = "insert into newtable (c1,c13) values ('" +
        r.get("c1") + "','" + r.get("c13") + "')"
    if s.len() < 2000:
        print s
    else:
        s = "insert into newtable (c1,c13) values ('" + r.get("c1") + "','')"
        print s
        f = r.get("c13")
        while f.len() > 2000:
            s = "update newtable set c13 = c13 || '" + f.substring(0,2000) + ')"
            f = f.substring(2000)
            print s
        endwhile
        s = "update newtable set c13 = c13 || '" + f + ')"
        print s
    endif
endwhile

De toute évidence, vous devrez peut-être transformer les chaînes pour autoriser les insertions de caractères spéciaux - je ne sais pas dans quel format Oracle les attend, mais j'espère que ce serait une simple question de passer les chaînes (r.get("c13") si la longueur de l'insertion complète est inférieure à 2000, f.substring(0,2000) et f si vous construisez également des mises à jour) à une fonction d'assistance pour ce faire.

Si ce morphing est susceptible d'augmenter la taille de la ligne imprimée, vous pouvez ramener le seuil à 1000 pour être sûr, pour vous assurer que la chaîne morphée ne donne pas une ligne supérieure à la limite PL/SQL.

Désolé si cela semble alambiqué, mais les restrictions que vous avez énoncées nous paralysent un peu. Il y a peut-être un meilleur moyen, mais je ne peux pas penser à un qui réponde à tous vos critères.

Mettre à jour : Il semble que vous soyez encore plus paralysé qu'on ne le pensait initialement :si vous devez vous limiter à SQL pour générer le script ainsi que son exécution, il existe un moyen, aussi tortueux soit-il.

Vous pouvez utiliser SQL pour générer SQL. Utilisation de ma table mentionnée ci-dessus avec c1 et c13 , vous pouvez faire :

select
    'insert into newtable (c1,c13) values ("' ||
    c1 ||
    '","");'
from oldtable;
# Xlates to: insert into newtable (c1,c13) values ("[c1]","");

Cela vous donnera tous vos insert de base déclarations pour dupliquer tout sauf le c13 colonne.

Ce que vous devez ensuite faire est de générer plus d'instructions pour définir c13 . Pour mettre à jour c13 pour toutes les valeurs de longueur 1000 ou moins (ensemble simple) :

select
    'update newtable set c13 = "' ||
    c13 ||
    '" where c1 = "' ||
    c1 ||
    '";'
from oldtable where length(c13) <= 1000;
# Xlates to: update newtable set c13 = "[c13]" where c1 = "[c1]";
#   but only for rows where length([c13]) <= 1000

Ensuite, pour update c13 pour toutes les valeurs comprises entre 1 001 et 2 000 caractères (définir puis ajouter) :

select
    'update newtable set c13 = "' ||
    substring(c13,1,1000) ||
    '" where c1 = "' ||
    c1 ||
    '";'
from oldtable where length(c13) > 1000 and length(c13) <= 2000;
select
    'update newtable set c13 = c13 || "' ||
    substring(c13,1001,1000) ||
    '" where c1 = "' ||
    c1 ||
    '";'
from oldtable where length(c13) > 1000 and length(c13) <= 2000;
# Xlates to: update newtable set c13 =        "[c13a]" where c1 = "[c1]";
#            update newtable set c13 = c13 || "[c13b]" where c1 = "[c1]";
#   but only for rows where length([c13]) > 1000 and <= 2000
#   and [c13a]/[c13b] are the first/second thousand chars of c13.

Et ainsi de suite pour ceux qui ont une longueur de 2 001 à 3 000 et de 3 001 à 4 000.

Il faudra probablement faire quelques ajustements. Je suis heureux de vous donner un moyen de le résoudre, mais mon désir de travailler sur une telle monstruosité jusqu'à son achèvement est au mieux minime :-)

Fera-t-il le travail? Oui. Est-ce joli ? Je dirais que c'était un "NON !" mais, compte tenu de vos contraintes, c'est peut-être le mieux que vous puissiez espérer.

Comme preuve de concept, voici un script SQL dans DB2 (pas de fonctionnalités spéciales cependant, il devrait fonctionner correctement dans n'importe quel SGBD qui a une length et substr équivalent):

# Create table and populate.

DROP TABLE XYZ;
COMMIT;
CREATE TABLE XYZ (F1 VARCHAR(1),F2 VARCHAR(20));
COMMIT;
INSERT INTO XYZ VALUES ('1','PAX');
INSERT INTO XYZ VALUES ('2','GEORGE');
INSERT INTO XYZ VALUES ('3','VLADIMIR');
INSERT INTO XYZ VALUES ('4','ALEXANDRETTA');
SELECT * FROM XYZ ORDER BY F1;

# Create initial insert statem,ents.

SELECT 'INSERT INTO XYZ (F1,F2) VALUES (' || F1 ','''');' 
    FROM XYZ;

# Updates for 1-5 character F2 fields.

SELECT 'UPDATE XYZ SET F2 = ''' || F2 ||
    ''' WHERE F1 = ''' || F1 || ''';'
    FROM XYZ WHERE LENGTH(F2) <= 5;

# Updates for 6-10 character F2 fields.

SELECT 'UPDATE XYZ SET F2 = ''' || SUBSTR(F2,1,5) ||
    ''' WHERE F1 = ''' || F1 || ''';'
    FROM XYZ WHERE LENGTH(F2) > 5 AND LENGTH(F2) <= 10;

SELECT 'UPDATE XYZ SET F2 = F2 || ''' || SUBSTR(F2,6) ||
    ''' WHERE F1 = ''' || F1 || ''';'
    FROM XYZ WHERE LENGTH(F2) > 5 AND LENGTH(F2) <= 10;

# Updates for 11-15 character F2 fields.

SELECT 'UPDATE XYZ SET F2 = ''' || SUBSTR(F2,1,5) ||
    ''' WHERE F1 = ''' || F1 || ''';'
    FROM XYZ WHERE LENGTH(F2) > 10 AND LENGTH(F2) <= 15;

SELECT 'UPDATE XYZ SET F2 = F2 || ''' || SUBSTR(F2,6,5) ||
    ''' WHERE F1 = ''' || F1 || ''';'
  FROM XYZ WHERE LENGTH(F2) > 10 AND LENGTH(F2) <= 15;

SELECT 'UPDATE XYZ SET F2 = F2 || ''' || SUBSTR(F2,11) || 
    ''' WHERE F1 = ''' || F1 || ''';'
    FROM XYZ WHERE LENGTH(F2) > 10 AND LENGTH(F2) <= 15;

et cela génère les lignes suivantes :

> DROP TABLE XYZ;
> COMMIT;
> CREATE TABLE XYZ (F1 VARCHAR(1),F2 VARCHAR(20));
> COMMIT;
> INSERT INTO XYZ VALUES ('1','PAX');
> INSERT INTO XYZ VALUES ('2','GEORGE');
> INSERT INTO XYZ VALUES ('3','VLADIMIR');
> INSERT INTO XYZ VALUES ('4','ALEXANDRETTA');
> SELECT * FROM XYZ;
    F1  F2
    --  ------------
    1   PAX
    2   GEORGE
    3   VLADIMIR
    4   ALEXANDRETTA

> SELECT 'INSERT INTO XYZ (F1,F2) VALUES (' || F1 || ','''');'
> FROM XYZ;
    INSERT INTO XYZ (F1,F2) VALUES (1,'');
    INSERT INTO XYZ (F1,F2) VALUES (2,'');
    INSERT INTO XYZ (F1,F2) VALUES (3,'');
    INSERT INTO XYZ (F1,F2) VALUES (4,'');

> SELECT 'UPDATE XYZ SET F2 = ''' || F2 ||
> ''' WHERE F1 = ''' || F1 || ''';'
> FROM XYZ WHERE LENGTH(F2) <= 5;
    UPDATE XYZ SET F2 = 'PAX' WHERE F1 = '1';

> SELECT 'UPDATE XYZ SET F2 = ''' || SUBSTR(F2,1,5) ||
> ''' WHERE F1 = ''' || F1 || ''';'
> FROM XYZ WHERE LENGTH(F2) > 5 AND LENGTH(F2) <= 10;
    UPDATE XYZ SET F2 = 'GEORG' WHERE F1 = '2';
    UPDATE XYZ SET F2 = 'VLADI' WHERE F1 = '3';

> SELECT 'UPDATE XYZ SET F2 = F2 || ''' || SUBSTR(F2,6) ||
> ''' WHERE F1 = ''' || F1 || ''';'
> FROM XYZ WHERE LENGTH(F2) > 5 AND LENGTH(F2) <= 10;
    UPDATE XYZ SET F2 = F2 || 'E' WHERE F1 = '2';
    UPDATE XYZ SET F2 = F2 || 'MIR' WHERE F1 = '3';

> SELECT 'UPDATE XYZ SET F2 = ''' || SUBSTR(F2,1,5) ||
> ''' WHERE F1 = ''' || F1 || ''';'
> FROM XYZ WHERE LENGTH(F2) > 10 AND LENGTH(F2) <= 15;
    UPDATE XYZ SET F2 = 'ALEXA' WHERE F1 = '4';

> SELECT 'UPDATE XYZ SET F2 = F2 || ''' || SUBSTR(F2,6,5) ||
> ''' WHERE F1 = ''' || F1 || ''';'
> FROM XYZ WHERE LENGTH(F2) > 10 AND LENGTH(F2) <= 15;
    UPDATE XYZ SET F2 = F2 || 'NDRET' WHERE F1 = '4';

> SELECT 'UPDATE XYZ SET F2 = F2 || ''' || SUBSTR(F2,11) ||
> ''' WHERE F1 = ''' || F1 || ''';'
> FROM XYZ WHERE LENGTH(F2) > 10 AND LENGTH(F2) <= 15;
    UPDATE XYZ SET F2 = F2 || 'TA' WHERE F1 = '4';

En décomposant les lignes de sortie, nous obtenons :

INSERT INTO XYZ (F1,F2) VALUES (1,'');
INSERT INTO XYZ (F1,F2) VALUES (2,'');
INSERT INTO XYZ (F1,F2) VALUES (3,'');
INSERT INTO XYZ (F1,F2) VALUES (4,'');
UPDATE XYZ SET F2 = 'PAX' WHERE F1 = '1';
UPDATE XYZ SET F2 = 'GEORG' WHERE F1 = '2';
UPDATE XYZ SET F2 = 'VLADI' WHERE F1 = '3';
UPDATE XYZ SET F2 = F2 || 'E' WHERE F1 = '2';
UPDATE XYZ SET F2 = F2 || 'MIR' WHERE F1 = '3';
UPDATE XYZ SET F2 = 'ALEXA' WHERE F1 = '4';
UPDATE XYZ SET F2 = F2 || 'NDRET' WHERE F1 = '4';
UPDATE XYZ SET F2 = F2 || 'TA' WHERE F1 = '4';

qui devrait vous donner les lignes d'origine, quoique de manière détournée.

Et c'est à peu près autant d'efforts que je peux mettre dans n'importe quelle question sans que mon cerveau ne brûle, donc je vous dis adieu à moins que des erreurs graves ne me soient signalées.

Bonne chance avec votre projet, et meilleurs voeux.