sql >> Databasteknik >  >> RDS >> Oracle

EXPORTERA SOM INFOGA UTTALANDE:Men i SQL Plus åsidosätter raden 2500 tecken!

Wow, dessa begränsningar är ganska begränsande men jag tror att det kan finnas en väg runt det. Jag tror att du kan behöva skriva ditt eget lilla manus för detta.

Jag skulle själv använda Java med JDBC (men vilket språk som helst som kan ansluta till och läsa databasen, och utdatasträngar, duger), skriver ett litet program som hämtade en rekorduppsättning av varje rad i databasen. Sedan, för var och en av dessa rader:

  • Konstruera en infogningssats med alla data. Om detta är mindre än 2 000 byte, matar du bara ut det till filen och går vidare till nästa rad.

  • Skapa annars en insert-sats för varje fält, men lämna c13 fält som '' (tom).

  • Sedan, så länge som din c13input strängen är större än 2000 tecken, mata ut en uppdateringssats av formen "update tbl set c13 = c13 || '" + c13input.substring (0,2000) + "' where ..." (lägger till de nästa 2000 tecknen) och gör sedan c13input = c13input.substring(2000) för att ta bort dessa tecken från din sträng.

  • En gång c13input är mindre än eller lika med 2 000 tecken lång, mata bara ut en sista uppdatering för att fixa den i slutet.

Detta gör att du kan hålla dina individuella SQL-satser runt 2000-tecken och effektivt köra rätt SQL för att fylla på en annan databastabell.

Det här är den typ av sak jag pratar om (för en tabell som bara innehåller en primärnyckel c1 och en stor honkin' varchar 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

Uppenbarligen kan du behöva modifiera strängarna för att tillåta infogning av specialtecken - jag är inte säker på vilket format Oracle förväntar sig dessa i, men det skulle förhoppningsvis vara en enkel fråga att skicka strängarna (r.get("c13") om längden på hela infogningen är mindre än 2000, f.substring(0,2000) och f om du också konstruerar uppdateringar) till en hjälpfunktion för att göra detta.

Om den förvandlingen sannolikt kommer att öka storleken på den utskrivna raden, kanske du vill sänka tröskeln tillbaka till 1000 för att vara säker, för att säkerställa att den omvandlade strängen inte resulterar i en rad som är större än PL/SQL-gränsen.

Ursäkta om det verkar krångligt, men de begränsningar du har angett gör att vi hamnar lite. Det kan mycket väl finnas ett bättre sätt, men jag kan inte komma på ett som uppfyller alla dina kriterier.

Uppdatering: Det verkar som att du är ännu fler förkrossad än vad du först trodde:om du måste begränsa dig till SQL för att generera manuset såväl som att köra det, det finns ett sätt, även om det är plågsamt.

Du kan använda SQL för att generera SQL. Använder min tidigare nämnda tabell med c1 och c13 , kan du göra:

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

Det ger dig all din baslinje insert satser för att duplicera allt utom c13 kolumn.

Vad du sedan behöver göra är att generera fler satser för att ställa in c13 . För att uppdatera c13 för alla värden med längd 1000 eller mindre (enkel uppsättning):

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

Sedan för att update c13 för alla värden mellan 1001 och 2000 tecken (ställ in och lägg sedan till):

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.

Och så vidare för de som är 2001 till 3000 och 3001 till 4000 långa.

Det kommer förmodligen behöva göras en del justeringar. Jag är glad att kunna ge dig ett sätt att lösa det, men min önskan att arbeta på en sådan monstrositet till slut är i bästa fall minimal :-)

Kommer det att få jobbet gjort? Ja. Är det snyggt? Jag skulle säga att det var ett rungande "NEJ!" men med tanke på dina begränsningar kan det vara det bästa du kan hoppas på.

Som ett bevis på konceptet, här är ett SQL-skript i DB2 (inga speciella funktioner dock, det borde fungera bra i alla DBMS som har en length och substr motsvarande):

# 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;

och detta genererar följande rader:

> 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';

När vi bryter ut utgångslinjerna får vi:

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';

vilket borde ge dig de ursprungliga raderna, om än på ett cirkulerande sätt.

Och det är ungefär lika mycket ansträngning som jag kan lägga på en fråga utan att min hjärna steker, så jag säger adieu om inte några allvarliga fel påpekas för mig.

Lycka till med ditt projekt och lyckönskningar.



  1. Gå igenom kolumner i RECORD

  2. Förhindra dropptabell vid målschema i Oracle Streams

  3. Datumkolumnaritmetik i PostgreSQL-fråga

  4. Identifiera och hantera uppdragskritiska åtkomstapplikationer under ett utvecklingsprojekt