php.de

Zurück   php.de > Webentwicklung > Datenbanken

Datenbanken SQL und Co

Antwort
 
LinkBack Themen-Optionen Thema bewerten
Alt 12.04.2010, 17:21  
Benutzer
 
Registriert seit: 03.04.2009
Beiträge: 66
Donald befindet sich auf einem aufstrebenden Ast
Standard Erkenntnisse aus der MySQL -> Oracle migration

Hallo,

ich habe mich nun eine ganze Weile mit der Migration einer PHP Anwendung von MySQL auf Oracle beschäftigt. Ich möchte hier meine Erfahrung aufschreiben, damit jemand anderem evtl. geholfen wird. Einen Anspruch auf Vollständigkeit der Themen gibt es natürlich nicht.

Hier die wesentlichen Punkte:
---
Oracle kennt kein NOW(). Ein Ersatz mit CURRENT_TIMESTAMP hat hier geholfen.
---
Die Datumsangaben werden, im Gegensatz zu MySQL, nicht sehr frei interpretiert. Sie müssen
A) mit TO_DATE() übergeben werden. Dabei ist das komplette Format der Datumsangabe zu übergeben.
B) durch Anpassen von NLS_DATE_FORMAT umgestaltet werden. Voraussetzung ist, dass man in seiner Anwendung immer im selben Format übergibt. Dazu gehört auch die Uhrzeit, die man bei entsprechendem Format dann immer angeben muss.
Doch Achtung: Wenn man OCI verwendet, kann man die Oracle-Parameter verändern wie man möchte. Es zeigt keine Wirkung (also einfach lassen). Es hilft nur, bei jedem Query vorher die Session mit ALTER SYSTEM SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS' SCOPE = SPFILE; auf das gewünschte Format zu bringen. Dann klappt es. Performance-Einschränkung habe ich gemessen und kam auf 0,0005 Sekunden mehr für einen Query mit Anpassung der Session (10'000 Querys ausgeführt).
---
Eine ON DUPLICATE KEY Funtion gibt es in Oracle nicht. Das kann man nur mit komplexeren IF THEN Anweisungen oder einer MERGE WHEN NOT MATCHED Funktion erreichen. Diese ist aber recht komplex. In diesen Fällen habe ich mir lieber einen SELECT vorneweg gegönnt und entscheide dann im Code ob ich ein INSERT oder ein UPDATE mache.
---
Oracle kennt keine INSERTs im Stil von INSERT INTO table SET Field1=Value1, Field2=Value2 etc. Das geht nur mit INSERT INTO table(Field1, Field2) VALUES(Value1, Value2). Ich habe mir einen kleinen Parser gebaut, der die INSERTS zur Laufzeit umbaut. Ansonsten hätte ich bergeweise INSERTS umbauen müssen. Ausserdem hat mir die Code-Übersichtlichkeit in der SET Variante mehr zugesagt. Code ist weiter unten im Thread...
---
Einen vergleichbaren Ersatz für LIMIT gibt es unter Oracle nicht. Stattdessen muss man den Query in zwei übergeordnete Query's einschachteln um das zu simulieren. Auch hier habe ich mir einen Parser zur Laufzeit gebaut, der die bestehenden LIMIT-Angaben umwandelt (nicht in Sub-Selects). Code ist weiter unten im Thread...
---
Die TO_DAYS() Funktion aus MySQL kann man möglicherweise in Oracle einfach durch TRUNC() ersetzen. Das liefert auch die Tageszahl.
---
Die MONTH(Date) Funktion aus MySQL kann mit TO_NUMBER(TO_CHAR(Date,'mm')) übersetzt werden.
---
Die YEAR(Date) Funktion aus MySQL kann mit TO_NUMBER(TO_CHAR(Date,'yyyy')) übersetzt werden.
---
Vor allem die Oracle XE hat per Default nur 10 Prozesse eingestellt. Das führt bei schnellen Datenbank-Zugriffen zu Fehlermeldungen (TNS:listener). Dem kann man mit ALTER SYSTEM SET PROCESSES=300 SCOPE=SPFILE; abhelfen (danach DB restarten).
---
Statt CONCAT() fügt man in Oracle Strings übrigens mit dem || Operator zusammen.
---
AutoID Spalten kennt Oracle nicht. Dazu muss man mit Sequenzen und Triggern arbeiten. Das Internet ist voll mit Beispielen dazu.
---
LIKE-Suchen sind bei Oracle immer Case-Sensitiv! Bei MySQL ist das nicht der Fall. Nun hat man evtl. ein Problem zB bei Nutzer-Logins etc. Hier kann es helfen, die Abfrage so zu gestalten (Beispielsuche nach Usernamen):
$SQL = "SELECT * FROM tbluser WHERE UPPER(USERNAME) LIKE '%" . strtoupper($Username) . "%' ORDER BY USERID";
Leider benutzt Oracle nun nicht mehr einen auf USERNAME stehenden Index. Da gibt es aber Abhilfe, indem man den Index folgend anlegt:
CREATE INDEX idx_Userame ON tbluser(UPPER(USERNAME));
---
GROUP BY kann bei Oracle nicht mit Aliasen arbeiten. Man sollte dann den eigentlichen (im Query angegebenen) Ausdruck erneut zur Sortierung heranziehen.

Ich hoffe es hilft jemandem...

Grüße,

Donald

Geändert von Donald (13.04.2010 um 09:09 Uhr).
Donald ist offline   Mit Zitat antworten
Sponsor Mitteilung
PHP Code Flüsterer

Registriert seit: 21.08.2005
Beiträge: 4682
PHP-Kenntnisse:
Fortgeschritten

Alt 12.04.2010, 18:03  
moderatives Dielektrikum
 
Benutzerbild von nikosch
 
Registriert seit: 21.05.2008
Beiträge: 35.987
PHP-Kenntnisse:
Fortgeschritten
nikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunft
Standard

Danke für die Arbeit!

Kannst Du viell. hierzu noch ein paar erklärende Worte verlieren?

Zitat:
Einen vergleichbaren Ersatz für LIMIT gibt es unter Oracle nicht. Stattdessen muss man den Query in zwei übergeordnete Query's einschachteln um das zu simulieren. Auch hier habe ich mir einen Parser zur Laufzeit gebaut, der die bestehenden LIMIT-Angaben umwandelt (nicht in Sub-Selects).
__________________
--
One pixel is still too big. Please make it smaller. ASAP.

Initiative Mittelstand.
Die wichtigste Gestaltungsregel im Screendesign ist Pi mal Daumen des Arbeitgebers.
--
nikosch ist offline   Mit Zitat antworten
Alt 12.04.2010, 18:54  
thomas_w
Gast
 
Beiträge: n/a
Standard

Zitat:
Zitat von Donald Beitrag anzeigen
Oracle kennt keine INSERTs im Stil von INSERT INTO table SET Field1=Value1, Field2=Value2 etc. Das geht nur mit INSERT INTO table(Field1, Field2) VALUES(Value1, Value2).
In MySQL werden eine Menge "sinnvoller" Funktionen angeboten, die nicht im SQL-Standard sind (Beispielweise NOW() oder diese INSERT Technik. Das SET gehört eher zum UPDATE). Dann klemmt es beim Wechseln zu einer anderen Datenbank mal eben mehr oder weniger. Auch ORACLE baut da vieles am Standard vorbei. Die IBM DB2 ist meiner Meinung nach am nächsten am SQL-Standard, wobei man sofort definieren müsste, welchen SQL-Standard man denn meint. Nur der SQL-92 wird von den meisten Datenbanken nahezu vollständig unterstützt. Aber dies ist ein Thema für lange Winterabende...

Schön dass Du die Probleme gelöst hast!

Grüße
Thomas
  Mit Zitat antworten
Alt 12.04.2010, 21:05  
Moderator
 
Benutzerbild von Chriz
 
Registriert seit: 11.05.2008
Beiträge: 6.266
Chriz ist ein wunderbarer AnblickChriz ist ein wunderbarer AnblickChriz ist ein wunderbarer AnblickChriz ist ein wunderbarer AnblickChriz ist ein wunderbarer AnblickChriz ist ein wunderbarer AnblickChriz ist ein wunderbarer Anblick
Standard

Sehr schön.

Ich kann morgen vom Geschäft mal mein Skript posten, das ein CREATE TABLE Statement von MySQL in ORACLE transfomiert (Trigger, Fremdschlüssel, etc.), allerdings sehr rudimentär und ziemlich star.
__________________
"Nuschel ich?" - "Was?"
Chriz ist offline   Mit Zitat antworten
Alt 13.04.2010, 08:31  
Benutzer
 
Registriert seit: 03.04.2009
Beiträge: 66
Donald befindet sich auf einem aufstrebenden Ast
Standard

MySQL LIMIT -> ORACLE

Hier die Routine, welche eine MySQL LIMIT Funktion in das passende Oracle Konstrukt wandelt. Damit kann der Query so bleiben wie er für MySQL gemacht war. Also gut für eine Anwendung welche mit beiden Datenbanken funktionieren soll.
Einschränkung: Funktioniert nicht in Sub-Querys!

PHP-Code:
// converts a given MySQL LIMIT() clause to the oracle pendant! 
// Attention: this works only with values up to 999999!
function ConvertOracleLimit($SQL) {
    
// find LIMIT position
    
$Pos strripos($SQL"limit ");
    if (
$Pos === FALSE) { 
        return 
$SQL// no LIMIT clause found, no need to do something
    
}
    
    
// find a following comma position (max. 8 chars later)
    
$PosComma stripos($SQL","$Pos);
    if (
$PosComma $Pos 8) {
        
$PosComma FALSE// too far away
    
}
    
    
// get min and count values
    
if ($PosComma === FALSE) {
        
// using no offset
        
$MinRow 1;
        
$Count intval(substr($SQL$Pos 56));
        
        
$PosRestBlank stripos($SQL" "$Pos 7);
        if (
$PosRestBlank === FALSE) { $PosRestBlank strlen($SQL); }
        
$PosRestLF stripos($SQL" "$Pos 7);
        if (
$PosRestLF === FALSE) { $PosRestLF strlen($SQL); }

    } else {
        
// using ffset
        
$MinRow intval(substr($SQL$Pos 5$PosComma $Pos 5));
        
$Count intval(substr($SQL$PosComma 15));
        
        
$PosRestBlank stripos($SQL" "$PosComma 2);
        if (
$PosRestBlank === FALSE) { $PosRestBlank strlen($SQL); }
        
$PosRestLF stripos($SQL" "$PosComma 2);
        if (
$PosRestLF === FALSE) { $PosRestLF strlen($SQL); }

    }
    
    
// choose nearest end of limit (linefeed or a blank char)
    
if ($PosRestBlank $PosRestLF) {
        
$PosRest $PosRestBlank;
    } else {
        
$PosRest $PosRestLF;
    }

    
// remove original limit clause
    
$SQL substr($SQL0$Pos) . substr($SQL$PosRest);
    
    
// cover SQL by oracle specific limit variant
    
$limit_sql "SELECT z2.* FROM ( 
                        SELECT ROWNUM AS db_rownum, z1.* FROM ( 
                        $SQL
                        ) z1 
                  ) z2 
                  WHERE z2.db_rownum BETWEEN " 
. ($MinRow) . " AND " . ($MinRow+$Count); 
    return 
$limit_sql;

Beispiel:
Ein solcher Query:
Code:
SELECT * FROM tblTest 
WHERE ID > 10 
ORDER BY ID 
LIMIT 10, 8
wird umgewandelt zu
Code:
SELECT z2.* FROM ( 
  SELECT ROWNUM AS db_rownum, z1.* FROM ( 
    SELECT * FROM tblTest 
    WHERE ID > 10 
    ORDER BY ID
  ) z1 
) z2 
WHERE z2.db_rownum BETWEEN 10 AND 18
Grüße,

Donald
Donald ist offline   Mit Zitat antworten
Alt 13.04.2010, 08:36  
Benutzer
 
Registriert seit: 03.04.2009
Beiträge: 66
Donald befindet sich auf einem aufstrebenden Ast
Standard

MySQL INSERT mit SET -> ORACLE INSERT mit VALUES

[EDIT] Leider hatte die Routine ein Problem mit Kommas in Strings. Das ist jetzt behoben.

Da Oracle die Form INSERT INTO tabelle SET Spalte=Wert nicht versteht, habe ich mir diese Funktion zum Umbauen erstellt. Die Schreibweise der von MySQL unterstützen SET Methode gefällt mir im Code deutlich besser.

PHP-Code:
// converts a given mysql insert in the following format:
// INSERT INTO tablename SET Field=Value, Field=Value
// into the oracle preferred format:
// INSERT INTO tablename(Field, Field) VALUES(Value, Value)
function ConvertOracleInsert($SQL) {
    if (
substr($SQL,012) != "INSERT INTO ") {
        return 
$SQL// no insert query
    
}
    if (
stripos($SQL"VALUES(") > 12) {
        return 
$SQL// already INSERT INTO() VALUES() formated
    
}
    
    
$SetPos stripos($SQL"SET"12) + 3;
    if (
$SetPos 15) { return $SQL; }
    
$ValueString substr($SQL$SetPos);
    
$Assigns = array();
    for (
$i=0;$i<=strlen($ValueString);$i++){
        
$c substr($ValueString$i1);
        if (
$c == "'" AND $InString == TRUE) {
            
$InString FALSE;
        } else {
            if (
$c == "'" AND $InString == FALSE) {
                
$InString TRUE;
                
// try a faster way through the strings
                
$NextPos stripos($ValueString"'"$i 1); // get position of the next '
                
if ($NextPos $i) {
                    
$Part .= substr($ValueString$i$NextPos $i);
                    
$c "";
                    
$i $NextPos 1// to allow the last ' to get found
                
}
            }
        }
        if (
$c == "," AND $InString == FALSE) {
            
$Assigns[] = $Part;
            
$Part "";   
        } else {
            
$Part .= $c;
        }
    }
    if (
$Part != "") {
        
$Assigns[] = $Part// add the last part
    
}
    
    foreach(
$Assigns AS $Assign) {
        
$Row explode("="$Assign);
        
$Fields .= trim($Row[0]) . ", ";
        
$Values .= trim($Row[1]) . ", ";
    }
    if (
substr($Fields, -2) == ", ") { $Fields substr($Fields0, -2); }
    if (
substr($Values, -2) == ", ") { $Values substr($Values0, -2); }
    
    
$Result substr($SQL0$SetPos 4); // Beginning
    
$Result .= "($Fields) VALUES($Values)";
    return 
$Result;

Beispiel:
Ein Query wie dieser
Code:
INSERT INTO tblTest SET UserID=10, Username='Klaus, Meier'
wird umgewandelt zu:
Code:
INSERT INTO tblTest(UserID, Username) VALUES(10, 'Klaus, Meier')
Grüße,

Donald

Geändert von Donald (14.04.2010 um 17:39 Uhr).
Donald ist offline   Mit Zitat antworten
Alt 13.04.2010, 09:04  
Benutzer
 
Registriert seit: 03.04.2009
Beiträge: 66
Donald befindet sich auf einem aufstrebenden Ast
Standard

Spaltennamen in MYSQL Tabelle in Großbuchstaben wandeln

Wenn man eine Anwendung auf den Betrieb mit mehreren Datenbanken auslegt, dann merkt man schnell, dass Spaltennamen am besten immer in Großbuchstaben angelegt werden. Hat man das initial aber nicht (weil MySQL das kann), dann hat man bald ein Problem (Oracle kann das nämlich nicht so ohne weiteres).
Hier eine kleine Routine, welche mir alle bestehenden MySQL Tabellen auf Großschreibung umgebaut hat. Diese Routine verwendet allerdings ein paar Funktionen aus einem Include, die hier nicht abgebildet sind:
Klasse classOpenDB() -> erlaubt den gekapselten Zugriff. Kann man leicht ersetzen.
GetOneSQLValue() -> liefert mir die erste Zeile eines Query als Array.
ExecuteSQL() -> führt einen Query einfach nur aus.
Diese Routinen kann ich leider nicht veröffentlichen, aber sind sicher schnell nachprogrammiert oder ersetzt. Es geht eher um die Technik dahinter um die Spalten umzubenennen.

PHP-Code:
// rename all available MySQL columns to uppercase names!
// alrerady uppercase columns will get skipped and not changed!

// get all tables that are needed to convert
$SQL "SELECT TABLE_NAME FROM information_schema.tables 
        WHERE TABLE_NAME LIKE 'tbl%'
        AND TABLE_SCHEMA='mySchemaName'"
;

$db = new classOpenDB($SQL);
while(
$row $db->fetchArray()) {
    
// processing each table
    
$TableName $row["TABLE_NAME"];
    echo 
"<b><u>converting table $TableName...</u></b><br>";
    
$Result GetOneSQLValue("SHOW CREATE TABLE $TableName");
    
$Create $Result["Create Table"];
    
$Lines  explode(chr(10), $Create);
    foreach(
$Lines AS $Line) {
        
$Line trim($Line);
        if (
substr($Line01) == "`") {
            if (
substr($Line, -1) == ",") {
                
// remove last comma
                
$Line substr($Line0, -1);
            } 
            echo 
"<b>processing:</b> " $Line ". ";
            
$Elements explode("`"$Line);
            if (
$Elements[1] != strtoupper($Elements[1])) {
                
// need to process
                
$FieldName "`" $Elements[1] . "`";
                
$New strtoupper($Line);
                
$Alter "ALTER TABLE $TableName CHANGE COLUMN $FieldName $New";
                
$Result ExecuteSQL($Alter);
                if (
$Result) {
                    echo 
"<span style='color: green;'>-&gt; OK</span>";
                } else {
                    echo 
"<span style='color: red;'>-&gt; ERROR</span>";
                }
                
usleep(50000);
            } else {
                
// skip
                
echo "<span style='color: blue;'>-&gt; SKIP</span>";
            }
            echo 
"<br>";
        }
    }
    echo 
"<hr>";
    
flush();
}
echo 
"<b>FINISHED!</b>"
Wichtig: Im ersten Query oben ($SQL = "...") muss man den so anpassen, dass nur die Tabellen der eigenen Anwendung bearbeitet werden!

Grüße,

Donald
Donald ist offline   Mit Zitat antworten
Alt 13.04.2010, 13:43  
Erfahrener Benutzer
 
Benutzerbild von lstegelitz
 
Registriert seit: 07.09.2009
Beiträge: 4.005
PHP-Kenntnisse:
Fortgeschritten
lstegelitz ist einfach richtig nettlstegelitz ist einfach richtig nettlstegelitz ist einfach richtig nettlstegelitz ist einfach richtig nett
Standard

Früher (mein letzter Stand ist Oracle konnte Oracle keine "multiple inserts" der Form
Code:
INSERT INTO <table> (field1, field2, field3) VALUES (
    (1, 1, 1),
    (2, 2, 2)
)
Musste man in mehreren Einzel-INSERTs machen, das hat mich seinerzeit wahnsinnig gemacht... ist das immer noch so?
__________________
Über 90% aller Gewaltverbrechen passieren innerhalb von 24 Stunden nach dem Konsum von Brot.
lstegelitz ist offline   Mit Zitat antworten
Alt 13.04.2010, 14:02  
moderatives Dielektrikum
 
Benutzerbild von nikosch
 
Registriert seit: 21.05.2008
Beiträge: 35.987
PHP-Kenntnisse:
Fortgeschritten
nikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunft
Standard

Oracle 8 sollte das heißen (an alle Boardneulinge).
__________________
--
One pixel is still too big. Please make it smaller. ASAP.

Initiative Mittelstand.
Die wichtigste Gestaltungsregel im Screendesign ist Pi mal Daumen des Arbeitgebers.
--
nikosch ist offline   Mit Zitat antworten
Alt 13.04.2010, 14:24  
Benutzer
 
Registriert seit: 03.04.2009
Beiträge: 66
Donald befindet sich auf einem aufstrebenden Ast
Standard

Zitat:
Zitat von lstegelitz Beitrag anzeigen
Musste man in mehreren Einzel-INSERTs machen, das hat mich seinerzeit wahnsinnig gemacht... ist das immer noch so?
Ja, das ist bei 10G (Oracle XE) noch immer so. Meines Wissens auch bei 11G.

Donald
Donald ist offline   Mit Zitat antworten
Antwort


Themen-Optionen
Thema bewerten
Thema bewerten:

Forumregeln
Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are an
Gehe zu

Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
Suche Tipps für MySQL -> Oracle Donald Datenbanken 10 01.04.2010 14:59
[Erledigt] MySQL Link Resource in einer statischen Variablen speichern Lenki PHP-Fortgeschrittene 8 18.03.2010 16:37
Oracle kontra MySQL Chriz Off-Topic Diskussionen 8 05.01.2010 12:56
[Erledigt] Kann keine Umlaute im mysql client eingeben Oger Datenbanken 9 02.04.2009 11:54
MySQL Konsole und Umlaute unter Windows [LÖSUNG] f4ckm5 Datenbanken 8 30.03.2009 22:10
Zugriff auf eine ORACLE DB die Daten in eine MYSQL schreiben Cheesy PHP Tipps 2007 5 12.06.2007 15:36
Mysql Server Einstellunen Optimieren pchero Datenbanken 3 01.05.2007 19:50
Verbindung MySQL - Oracle tomson Datenbanken 0 15.09.2006 17:13
MySQL Server startet nicht mehr richtig... Datenbanken 16 03.03.2006 19:40
MySQL oder doch Oracle? phpbeginner Datenbanken 2 02.02.2006 21:16
Suche Tipps für Persormance-Steigerung (Geld für Nützliches) Beitragsarchiv 18 16.08.2005 10:57
[Erledigt] Oracle -&gt; MySql Datenbanken 1 11.08.2005 13:47
[Erledigt] PHP5 &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;a m p; MySQL Datenbanken 5 01.08.2004 05:47
Oracle, MS SQL = Die selbe sprache wie mysql b++ Datenbanken 7 29.06.2004 14:30

Besucher kamen über folgende Suchanfragen bei Google auf diese Seite
mysql oracle migration, mysql to_number, php date format wandeln nls_date_format ändern, mysql oracle no, migration mysql oracle, mysql to oracle migration, mysql to_char, oracle migration, mysql nls_date_format, http://www.php.de/datenbanken/66797-erkenntnisse-aus-der-mysql-oracle-migration.html, mysql migration oracle, mysql limit von unten, to_number mysql, mysql datenbank auf oracle migrieren, strlen oracle, limit mysql oracle, datenbank migration mysql oracle, oracle limit rows, php now() for oracle, mysql to oracle converter

Alle Zeitangaben in WEZ +2. Es ist jetzt 10:14 Uhr.




Powered by vBulletin® Version 3.7.2 (Deutsch)
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
Aprilia-Forum, Aquaristik-Forum, Liebeskummer-Forum, Zierfisch-Forum, Geizkragen-Forum