sql >> Databasteknik >  >> RDS >> Oracle

Oracle SQL-Loader hanterar effektivt interna dubbla citat i värden

Om du aldrig haft rör i de slutna fälten kan du göra det från kontrollfilen. Om du kan ha både pipes och dubbla citattecken inom ett fält så tror jag att du inte har något annat val än att förbehandla filerna, tyvärr.

Din lösning [1], för att ersätta dubbla citattecken med en SQL-operator , händer för sent för att vara användbar; avgränsningarna och bilagorna har redan tolkats av SQL*Loader innan den gör SQL-steget. Din lösning [2], att ignorera inneslutningen, skulle fungera i kombination med [1] - tills ett av fälten innehöll ett rörtecken. Och lösning [3] har samma problem som att använda [1] och/eller [2] globalt.

Dokumentationen för att specificera avgränsare nämner att:

Med andra ord, om du upprepade dubbla citattecken inuti fälten då skulle de escapes och skulle visas i tabelldata. Eftersom du inte kan styra datagenereringen kan du förbehandla filerna du får för att ersätta alla dubbla citattecken med escaped dubbla citattecken. Förutom att du inte vill ersätta alla av dem - de som faktiskt är riktiga inhägnader bör inte undkomma.

Du kan använda ett reguljärt uttryck för att rikta in sig på att relevanta tecken hoppar över andra. Inte mitt starka område, men jag tror att du kan göra det här med lookahead och lookbehind-påståenden .

Om du hade en fil som heter orig.txt som innehåller:

"1"|A|"B"|"C|D"
"2"|A|"B"|"C"D"
3|A|""B""|"C|D"
4|A|"B"|"C"D|E"F"G|H""

du kan göra:

perl -pe 's/(?<!^)(?<!\|)"(?!\|)(?!$)/""/g' orig.txt > new.txt

Det letar efter ett dubbelcitattecken som inte föregås av linjestartankaret eller ett rörtecken; och följs inte av ett rörkaraktär eller linjeändankare; och ersätter endast de med escaped (dubbla) dubbla citattecken. Vilket skulle göra new.txt innehåller:

"1"|A|"B"|"C|D"
"2"|A|"B"|"C""D"
3|A|"""B"""|"C|D"
4|A|"B"|"C""D|E""F""G|H"""

Dubbla citattecken i början och slutet av fält ändras inte, men de i mitten är nu escaped. Om du sedan laddade det med en kontrollfil med dubbla citattecken:

load data
truncate
into table t42
fields terminated by '|' optionally enclosed by '"'
(
  col1,
  col2,
  col3,
  col4
)

Då skulle du sluta med:

select * from t42 order by col1;

      COL1 COL2       COL3       COL4                
---------- ---------- ---------- --------------------
         1 A          B          C|D                 
         2 A          B          C"D                 
         3 A          "B"        C|D                 
         3 A          B          C"D|E"F"G|H"        

som förhoppningsvis matchar dina ursprungliga uppgifter. Det kan finnas kantfall som inte fungerar (som ett dubbelcitattecken följt av ett rör inom ett fält) men det finns en gräns för vad du kan göra för att försöka tolka någon annans data... Det kan naturligtvis också finnas (mycket) bättre reguljära uttrycksmönster.

Du kan också överväga att använda en extern tabell istället för SQL*Loader, om datafilen finns (eller kan finnas) i en Oracle-katalog och du har rätt behörigheter. Du måste fortfarande ändra filen, men du kan göra det automatiskt med preprocessor direktiv, snarare än att behöva göra det explicit innan du anropar SQL*Loader.




  1. Misslyckas med att bygga mysql connector/c (libmysql) från källan i cygwin

  2. Är addslashes() tillräckligt säkert för att undvika SQL-INJEKTIONER?

  3. MySQL:Inner join vs Where

  4. Returnerar en Min() och ett annat fält?