ALTER TABLE mit Hilfe von RegEx zerlegen, splitten

AMOKANDY

Mitglied
Hallo zusammen,

Vorweg, Regular Expresseion sind für mich total neu, aber ich habe die Möglichkeiten erkannt und möchte diese nun auch nutzen. Mein Problem, ich habe einen ALTER TABLE Anweisung, die ich zerlegen muss.

Folgendes Beispiel:

SQL:
ADD COLUMN [FIELD2] VARCHAR(20) NULL, 
ADD COLUMN [FIELD1] NUMERIC(8, 2) NOT NULL, 
ADD COLUMN [FIELD3] INTEGER DEFAULT(0) NOT NULL, 
DROP COLUMN [KILLME]

Meine RegEx:
Code:
^(ADD|DROP)[ ]+(COLUMN)[ ]([^,]+)[,](.*)$

Das ganze funktioniert leider nicht, wenn woanders ein "," (Komma) vorkommt wie bei NUMERIC(8, 0).
Wie muss ich nun meine RegEx erweitern?

Folgende Regeln fallen mir ein, weiß aber leider nicht wie ich diese umsetzen kann:

  • Also die RegEx müsste "Komma" innerhalb einer Klammer ignorieren (Mein Favorit!)
  • Nur am "Komma" trennen, wenn ein Wort (incl. SPACE) vor dem Komma steht

Bin mal gespannt was dabei raus kommen kann. Danke schon mal für jeden der Tipps gibt.

MfG
 
Leider noch keine Resonanz. Ich habe weiter probiert, und hier ist der JAVA Code der mir einen ALTER TABLE zerlegt:

Der SQL:
SQL:
ALTER TABLE [dbo].[CHGPROT] ADD COLUMN [Instanz] VARCHAR(20) NULL, 
DROP COLUMN [KILLME], 
ADD COLUMN [FIELD000] NUMERIC(8, 2) NOT NULL, 
ADD COLUMN [FIELD001] INTEGER NOT NULL


Java:
    protected static ParsedSqlAlterTableStatement parseSqlStatementAlterTableMultiColumns(String aUnifiedSql) {

        ParsedSqlAlterTableStatement tSqlCreateTable = new ParsedSqlAlterTableStatement();

        // @formatter:off
        StringBuffer tRegEx = new StringBuffer();
        tRegEx.append("^");                          // Start of SQL statement
        tRegEx.append("(ALTER)[ ]+");                // Group 1: CREATE
        tRegEx.append("(TABLE)[ ]+");                // Group 2: TABLE
        tRegEx.append("(?:");
        tRegEx.append("(?:([^.\\s]*)(?:[.]))?");     // Group 3: database or schema name
        tRegEx.append("(?:([^.\\s]*)(?:[.]))?");     // Group 4: schema name
        tRegEx.append("([^\\s]*)[ ]*");              // Group 5: table name
        tRegEx.append(")");
        tRegEx.append("(.*)");                       // Group 6: fields
        tRegEx.append("$");
        // @formatter:on;

        Pattern tPattern = Pattern.compile(tRegEx.toString(), Pattern.CASE_INSENSITIVE);
        Matcher tMatcher = tPattern.matcher(aUnifiedSql.trim());
        if (tMatcher.find()) {
            if (tMatcher.group(1) == null) {
                throw new RuntimeException("Die übergebene SQL Anweisung ist keine ALTER TABLE Anweisung.");
            }

            if (tMatcher.group(4) == null) {
                tSqlCreateTable.setDatabaseName(null);
                tSqlCreateTable.setSchemaName(tMatcher.group(3)); // schema name
            } else {
                tSqlCreateTable.setDatabaseName(tMatcher.group(3)); // database
                tSqlCreateTable.setSchemaName(tMatcher.group(4)); // schema name
            }

            tSqlCreateTable.setTableName(tMatcher.group(5)); // Table name

            // @formatter:off
            tRegEx = new StringBuffer();
            tRegEx.append("^");                                   // Start of SQL statement
            tRegEx.append("(ADD|DROP)[ ]+");                      // Group 1: "ADD" or "DROP"
            tRegEx.append("(COLUMN)[ ]+");                        // Group 2: "COLUMN"
            tRegEx.append("([^,\\s]*)[ ]*");                      // Group 3: ColumnName
            tRegEx.append("([^,]*[,]|[^,]*[,]*)");                // Group 4: Column Attribute
            tRegEx.append("(.*)");                                // Group 5: Rest
            tRegEx.append("$");                                   // End of RegEx
            // @formatter:on

            System.out.println("RegEx # '" + tRegEx.toString() + "'!");

            String tColumns = tMatcher.group(tMatcher.groupCount());
            boolean tDoParse = false;

            do {

                tDoParse = false;

                System.out.println("x # '" + tColumns + "'!");
                String[] tArray = Pattern.compile(",", Pattern.CASE_INSENSITIVE).split(tColumns);
                tMatcher = Pattern.compile(tRegEx.toString(), Pattern.CASE_INSENSITIVE).matcher(tColumns);

                int tGroups = tMatcher.groupCount();
                if (tMatcher.find()) {

                    for (int i = 0; i <= tGroups; i++) {
                        System.out.println("\tGroup " + i + " # '" + tMatcher.group(i) + "'!");
                    }

                    String tAction = tMatcher.group(1);
                    String tObject = tMatcher.group(2);
                    String tColumnName = tMatcher.group(3);
                    String tColumnAttribute = tMatcher.group(4);

                    if (tColumnAttribute.lastIndexOf(",") == tColumnAttribute.length() - 1) {
                        tColumnAttribute = tColumnAttribute.substring(0, tColumnAttribute.length() - 1);
                    }

                    ParsedSqlAlterTableColumn tParsedSqlAlterTableColumn = new ParsedSqlAlterTableColumn(tColumnName, tColumnAttribute, tAction,
                        tObject);

                    tColumns = tMatcher.group(tGroups).trim();
                    if (tColumns != null) {
                        if (!tColumns.trim().equals("")) {
                            tDoParse = true;
                        }
                    }
                }

            } while (tDoParse == true);

        }

        return tSqlCreateTable;

    }

Der Output sieht wie folgt aus:

Code:
RegEx # '^(ADD|DROP)[ ]+(COLUMN)[ ]+([^,\s]*)[ ]*([^,]*[,]|[^,]*[,]*)(.*)$'!
x # 'ADD COLUMN [Instanz] VARCHAR(20) NULL, DROP COLUMN [KILLME], ADD COLUMN [FIELD000] NUMERIC(8, 2) NOT NULL, ADD COLUMN [FIELD001] INTEGER NOT NULL'!
	Group 0 # 'ADD COLUMN [Instanz] VARCHAR(20) NULL, DROP COLUMN [KILLME], ADD COLUMN [FIELD000] NUMERIC(8, 2) NOT NULL, ADD COLUMN [FIELD001] INTEGER NOT NULL'!
	Group 1 # 'ADD'!
	Group 2 # 'COLUMN'!
	Group 3 # '[Instanz]'!
	Group 4 # 'VARCHAR(20) NULL,'!
	Group 5 # ' DROP COLUMN [KILLME], ADD COLUMN [FIELD000] NUMERIC(8, 2) NOT NULL, ADD COLUMN [FIELD001] INTEGER NOT NULL'!
x # 'DROP COLUMN [KILLME], ADD COLUMN [FIELD000] NUMERIC(8, 2) NOT NULL, ADD COLUMN [FIELD001] INTEGER NOT NULL'!
	Group 0 # 'DROP COLUMN [KILLME], ADD COLUMN [FIELD000] NUMERIC(8, 2) NOT NULL, ADD COLUMN [FIELD001] INTEGER NOT NULL'!
	Group 1 # 'DROP'!
	Group 2 # 'COLUMN'!
	Group 3 # '[KILLME]'!
	Group 4 # ','!
	Group 5 # ' ADD COLUMN [FIELD000] NUMERIC(8, 2) NOT NULL, ADD COLUMN [FIELD001] INTEGER NOT NULL'!
x # 'ADD COLUMN [FIELD000] NUMERIC(8, 2) NOT NULL, ADD COLUMN [FIELD001] INTEGER NOT NULL'!
	Group 0 # 'ADD COLUMN [FIELD000] NUMERIC(8, 2) NOT NULL, ADD COLUMN [FIELD001] INTEGER NOT NULL'!
	Group 1 # 'ADD'!
	Group 2 # 'COLUMN'!
	Group 3 # '[FIELD000]'!
	Group 4 # 'NUMERIC(8,'!
	Group 5 # ' 2) NOT NULL, ADD COLUMN [FIELD001] INTEGER NOT NULL'!   
x # '2) NOT NULL, ADD COLUMN [FIELD001] INTEGER NOT NULL'!

Leider trennt die RegEx den Text zu früh, bei dem Komma in der Klammer, nicht erst nach dem "NULL".
SQL:
ADD COLUMN [FIELD000] NUMERIC(8,
 2) NOT NULL,

Wenn ich die Zeile
Code:
ADD COLUMN [FIELD000] NUMERIC(8, 2) NOT NULL,
herausnehme ist alles gut.

Hat jemand eine Idee wie ich es jetzt hinbekomme, dass ich das Komma in der Klammer ignoriere / überlese? Alternativ Vorschläge? Bin für jeden Tipp dankbar!

MfG
 
tja, das sind böse Spezialfälle,
nicht umsonst sind richtige Programme in dem Umfeld eher Parser als RegEx,
jedes Zeichen einlesen, verstehen, Regeln prüfen

hiermit geht es vielleicht vorerst noch
[c] tRegEx.append("([^,(]*(\\(\\d*, *\\d*\\))?[^,(]*[,])"); // Group 4: Column Attribute [/c]
auch die öffnende Klammer im allgemeinen [] verbieten, dann die Klammer mit Zahlen darin einzeln bauen,
das Fragezeichen macht es hoffentlich optional,
für weiteren Text dahinter nochmal ein [] ohne Klammer, schließlich das Komma wofür [] eigentlich nicht nötig sind
 
tja, das sind böse Spezialfälle,
nicht umsonst sind richtige Programme in dem Umfeld eher Parser als RegEx,
jedes Zeichen einlesen, verstehen, Regeln prüfen

hiermit geht es vielleicht vorerst noch
[c] tRegEx.append("([^,(]*(\\(\\d*, *\\d*\\))?[^,(]*[,])"); // Group 4: Column Attribute [/c]
auch die öffnende Klammer im allgemeinen [] verbieten, dann die Klammer mit Zahlen darin einzeln bauen,
das Fragezeichen macht es hoffentlich optional,
für weiteren Text dahinter nochmal ein [] ohne Klammer, schließlich das Komma wofür [] eigentlich nicht nötig sind

Habe die Zeile noch ein wenig modifizieren müssen, aber jetzt gehts!!! :applaus:

Java:
tRegEx.append("([^,(]*\\(\\d*, *\\d*\\)?[^,]*[,]|[^,]*[,]*)");

HERZLICHEN DANK!!!
 
bei | solltest du immer Klammern setzen,
ich frage mich wozu du das brauchst, der (\\d-Teil war mit dem ? eh optional
aber wenn es funktioniert braucht man sich ja vorerst nicht beschweren
 
So zur Vollständigkeit nachmal die komplette Lösung. Mit dem RegEx Lösungsansatz wurde die komplette RegEx nochmal überarbeitet, somit wurde der JavaCode reduziert.

SQL der zerlegt werden soll:
SQL:
ALTER TABLE [dbo].[CHGPROT] ADD COLUMN [FIELD000] NUMERIC(8,2) DEFAULT(0) NOT NULL, 
ADD COLUMN [Instanz] VARCHAR(20) NULL, DROP COLUMN [KILLME], 
ADD COLUMN [UUID] CHAR(36) NULL,DROP COLUMN [KILLME_AGAIN],
ADD COLUMN [FIELD000] DECIMAL(1, 4) NOT NULL,
ADD COLUMN [FIELD001] INTEGER NOT NULL

Die Methode die das Zerlegt:
Java:
    protected static ParsedSqlAlterTableStatement parseSqlStatementAlterTableMultiColumns(String aUnifiedSql) {

        ParsedSqlAlterTableStatement tSqlCreateTable = new ParsedSqlAlterTableStatement();

        // @formatter:off
        StringBuffer tRegEx = new StringBuffer();
        tRegEx.append("^");                          // Start of SQL statement
        tRegEx.append("(ALTER)[ ]+");                // Group 1: CREATE
        tRegEx.append("(TABLE)[ ]+");                // Group 2: TABLE
        tRegEx.append("(?:");
        tRegEx.append("(?:([^.\\s]*)(?:[.]))?");     // Group 3: database or schema name
        tRegEx.append("(?:([^.\\s]*)(?:[.]))?");     // Group 4: schema name
        tRegEx.append("([^\\s]*)[ ]*");              // Group 5: table name
        tRegEx.append(")");
        tRegEx.append("(.*)");                       // Group 6: fields
        tRegEx.append("$");
        // @formatter:on;

        Pattern tPattern = Pattern.compile(tRegEx.toString(), Pattern.CASE_INSENSITIVE);
        Matcher tMatcher = tPattern.matcher(aUnifiedSql.trim());
        if (tMatcher.find()) {
            if (tMatcher.group(1) == null) {
                throw new RuntimeException("Die übergebene SQL Anweisung ist keine ALTER TABLE Anweisung.");
            }

            if (tMatcher.group(4) == null) {
                tSqlCreateTable.setDatabaseName(null);
                tSqlCreateTable.setSchemaName(tMatcher.group(3)); // schema name
            } else {
                tSqlCreateTable.setDatabaseName(tMatcher.group(3)); // database
                tSqlCreateTable.setSchemaName(tMatcher.group(4)); // schema name
            }

            tSqlCreateTable.setTableName(tMatcher.group(5)); // Table name

            // @formatter:off
            tRegEx = new StringBuffer();
            tRegEx.append("(?:");
            tRegEx.append("(?:");
            tRegEx.append("[ ]*");
            tRegEx.append("(ADD|DROP)[ ]+");                      // Group 1: "ADD" or "DROP"
            tRegEx.append("(COLUMN)[ ]+");                        // Group 2: "COLUMN"
            tRegEx.append("([^,\\s]*)[ ]*");                      // Group 3: ColumnName
            tRegEx.append("(");                                   // Group 4: ColumnAttribute
            tRegEx.append("(?:");
            tRegEx.append("[^,(]*\\(\\d*,[ ]*\\d*\\)|");          //   Feldlänge mit Dezimalstellen
            tRegEx.append("[^,(]*\\(\\d*[ ]*\\)|");               //   Feldlänge ohne Dezimalstellen
            tRegEx.append(")?");
            tRegEx.append("[ ]*[^,]*");                           //   Erweiterung für ADD COLUMN
            tRegEx.append(")?");
            tRegEx.append(")");
            tRegEx.append("[ ]*[,]?");
            tRegEx.append(")");
            tRegEx.append("");            
            // @formatter:on

            System.out.println("RegEx # '" + tRegEx.toString() + "'!");

            String tColumns = tMatcher.group(tMatcher.groupCount());
            System.out.println("x # '" + tColumns + "'!");
            tMatcher = Pattern.compile(tRegEx.toString(), Pattern.CASE_INSENSITIVE).matcher(tColumns);

            int n = 1;
            int tGroups = tMatcher.groupCount();
            while (tMatcher.find()) {

                System.out.println("\tMATCH: " + (n++) + "'!");
                for (int i = 0; i <= tGroups; i++) {
                    System.out.println("\t\tGroup " + i + " # '" + tMatcher.group(i) + "'!");
                }

                String tAction = tMatcher.group(1);
                String tObject = tMatcher.group(2);
                String tColumnName = tMatcher.group(3);
                String tColumnAttribute = tMatcher.group(4);

                ParsedSqlAlterTableColumn tParsedSqlAlterTableColumn = new ParsedSqlAlterTableColumn(tColumnName, tColumnAttribute, tAction, tObject);
                tSqlCreateTable.addAlterTableColumn(tParsedSqlAlterTableColumn);

            }

            System.out.println("END OF PARSING!\n\n");

        }

        return tSqlCreateTable;

    }

So sieht das dann auf der Console aus:
Code:
RegEx # '(?:(?:[ ]*(ADD|DROP)[ ]+(COLUMN)[ ]+([^,\s]*)[ ]*((?:[^,(]*\(\d*,[ ]*\d*\)|[^,(]*\(\d*[ ]*\)|)?[ ]*[^,]*)?)[ ]*[,]?)'!
x # 'ADD COLUMN [FIELD000] NUMERIC(8,2) DEFAULT(0) NOT NULL, ADD COLUMN [Instanz] VARCHAR(20) NULL, DROP COLUMN [KILLME], ADD COLUMN [UUID] CHAR(36) NULL,DROP COLUMN [KILLME_AGAIN],ADD COLUMN [FIELD000] DECIMAL(1, 4) NOT NULL,ADD COLUMN [FIELD001] INTEGER NOT NULL'!
	MATCH: 1'!
		Group 0 # 'ADD COLUMN [FIELD000] NUMERIC(8,2) DEFAULT(0) NOT NULL,'!
		Group 1 # 'ADD'!
		Group 2 # 'COLUMN'!
		Group 3 # '[FIELD000]'!
		Group 4 # 'NUMERIC(8,2) DEFAULT(0) NOT NULL'!
	MATCH: 2'!
		Group 0 # ' ADD COLUMN [Instanz] VARCHAR(20) NULL,'!
		Group 1 # 'ADD'!
		Group 2 # 'COLUMN'!
		Group 3 # '[Instanz]'!
		Group 4 # 'VARCHAR(20) NULL'!
	MATCH: 3'!
		Group 0 # ' DROP COLUMN [KILLME],'!
		Group 1 # 'DROP'!
		Group 2 # 'COLUMN'!
		Group 3 # '[KILLME]'!
		Group 4 # ''!
	MATCH: 4'!
		Group 0 # ' ADD COLUMN [UUID] CHAR(36) NULL,'!
		Group 1 # 'ADD'!
		Group 2 # 'COLUMN'!
		Group 3 # '[UUID]'!
		Group 4 # 'CHAR(36) NULL'!
	MATCH: 5'!
		Group 0 # 'DROP COLUMN [KILLME_AGAIN],'!
		Group 1 # 'DROP'!
		Group 2 # 'COLUMN'!
		Group 3 # '[KILLME_AGAIN]'!
		Group 4 # ''!
	MATCH: 6'!
		Group 0 # 'ADD COLUMN [FIELD000] DECIMAL(1, 4) NOT NULL,'!
		Group 1 # 'ADD'!
		Group 2 # 'COLUMN'!
		Group 3 # '[FIELD000]'!
		Group 4 # 'DECIMAL(1, 4) NOT NULL'!
	MATCH: 7'!
		Group 0 # 'ADD COLUMN [FIELD001] INTEGER NOT NULL'!
		Group 1 # 'ADD'!
		Group 2 # 'COLUMN'!
		Group 3 # '[FIELD001]'!
		Group 4 # 'INTEGER NOT NULL'!
END OF PARSING!

MfG
 

Zurück
Oben