diff --git a/jOOQ-website/frame.php b/jOOQ-website/frame.php index 682978da95..199222ef53 100644 --- a/jOOQ-website/frame.php +++ b/jOOQ-website/frame.php @@ -1,6 +1,7 @@ +
| The jOOQ User Manual : Advanced topics : The Oracle CONNECT BY clause for hierarchical queries | previous : next | +The jOOQ User Manual : Advanced topics : The Oracle CONNECT BY clause | previous : next |
If you are closely coupling your application to an Oracle database, + you can take advantage of some Oracle-specific features, such as the + CONNECT BY clause, used for hierarchical queries. The formal syntax + definition is as follows:
+ ++-- SELECT .. +-- FROM .. +-- WHERE .. + CONNECT BY [NOCYCLE] condition [AND condition, ...] [START WITH condition] +-- GROUP BY ..+
This can be done in jOOQ using the .connectBy(Condition) clauses in your SELECT statement:
++// Some Oracle-specific features are only available +// from the OracleFactory +OracleFactory create = new OracleFactory(connection); + +// Get a table with elements 1, 2, 3, 4, 5 +create.select(create.rownum()) + .connectBy(create.level().lessOrEqual(5)) + .fetch();+ +
Here's a more complex example where you can recursively fetch + directories in your database, and concatenate them to a path:
++ OracleFactory ora = new OracleFactory(connection); + + List<?> paths = + ora.select(ora.sysConnectByPath(Directory.NAME, "/").substring(2)) + .from(Directory) + .connectBy(ora.prior(Directory.ID).equal(Directory.PARENT_ID)) + .startWith(Directory.PARENT_ID.isNull()) + .orderBy(ora.literal(1)) + .fetch(0);+ +
The output might then look like this
+++------------------------------------------------+ +|substring | ++------------------------------------------------+ +|C: | +|C:/eclipse | +|C:/eclipse/configuration | +|C:/eclipse/dropins | +|C:/eclipse/eclipse.exe | ++------------------------------------------------+ +|...21 record(s) truncated... ++
| The jOOQ User Manual : Advanced topics : The Oracle CONNECT BY clause for hierarchical queries | previous : next | +The jOOQ User Manual : Advanced topics : The Oracle CONNECT BY clause | previous : next |
If you are using jOOQ for scripting purposes or in a slim, unlayered + application server, you might be interested in using jOOQ's exporting + functionality (see also importing functionality). You can export any + Result<Record> into any of these formats:
+ +Export your results as XML:
++// Fetch books and format them as XML +String xml = create.selectFrom(T_BOOK).fetch().formatXML();+ +
The above query will result in an XML document looking like the following one:
++<!-- Find the XSD definition on www.jooq.org: --> +<jooq-export:result xmlns:jooq-export="http://www.jooq.org/xsd/jooq-export-1.6.2.xsd"> + <fields> + <field name="ID"/> + <field name="AUTHOR_ID"/> + <field name="TITLE"/> + </fields> + <records> + <record> + <value field="ID">1</value> + <value field="AUTHOR_ID">1</value> + <value field="TITLE">1984</value> + </record> + <record> + <value field="ID">2</value> + <value field="AUTHOR_ID">1</value> + <value field="TITLE">Animal Farm</value> + </record> + </records> +</jooq-export:result>+ +
Export your results as CSV:
++// Fetch books and format them as CSV +String csv = create.selectFrom(T_BOOK).fetch().formatCSV();+ +
The above query will result in a CSV document looking like the following one:
++ID;AUTHOR_ID;TITLE +1;1;1984 +2;1;Animal Farm+ + +
Export your results as JSON:
+ ++// Fetch books and format them as JSON +String json = create.selectFrom(T_BOOK).fetch().formatJSON();+
The above query will result in a JSON document looking like the following one:
+
+{fields:["ID","AUTHOR_ID","TITLE"],
+ records:[[1,1,"1984"],[2,1,"Animal Farm"]]}
+
+ Export your results as HTML:
++// Fetch books and format them as HTML +String html = create.selectFrom(T_BOOK).fetch().formatHTML();+
The above query will result in an HTML document looking like the following one:
++<table> + <thead> + <tr> + <th>ID</th> + <th>AUTHOR_ID</th> + <th>TITLE</th> + </tr> + </thead> + <tbody> + <tr> + <td>1</td> + <td>1</td> + <td>1984</td> + </tr> + <tr> + <td>2</td> + <td>1</td> + <td>Animal Farm</td> + </tr> + </tbody> +</table>+ +
Export your results as text:
++// Fetch books and format them as text +String text = create.selectFrom(T_BOOK).fetch().format();+ +
The above query will result in a text document looking like the following one:
+++---+---------+-----------+ +| ID|AUTHOR_ID|TITLE | ++---+---------+-----------+ +| 1| 1|1984 | +| 2| 1|Animal Farm| ++---+---------+-----------++
| The jOOQ User Manual : Advanced topics : Exporting data to XML, CSV, JSON, HTML, Text | previous : next | +The jOOQ User Manual : Advanced topics : Exporting to XML, CSV, JSON, HTML, Text | previous : next |
| The jOOQ User Manual : Advanced topics : Importing data from XML, CSV | previous | +The jOOQ User Manual : Advanced topics : Importing data from XML, CSV | previous |
If you are using jOOQ for scripting purposes or in a slim, unlayered + application server, you might be interested in using jOOQ's importing + functionality (see also exporting functionality). You can import data + directly into a table from any of these formats:
+ +The below CSV data represents two author records that may have been + exported previously, by jOOQ's exporting functionality, and then + modified in Microsoft Excel or any other spreadsheet tool:
+ ++ID;AUTHOR_ID;TITLE +1;1;1984 +2;1;Animal Farm+ +
With jOOQ, you can load this data using various parameters from the + loader API. A simple load may look like this:
+ ++Factory create = new Factory(connection, SQLDialect.ORACLE); + +// Load data into the T_AUTHOR table from an input stream +// holding the CSV data. +create.loadInto(T_AUTHOR) + .loadCSV(inputstream) + .fields(ID, AUTHOR_ID, TITLE) + .execute();+ +
Here are various other examples:
++// Ignore the AUTHOR_ID column from the CSV file when inserting +create.loadInto(T_AUTHOR) + .loadCSV(inputstream) + .fields(ID, null, TITLE) + .execute(); + +// Specify behaviour for duplicate records. +create.loadInto(T_AUTHOR) + + // choose any of these methods + .onDuplicateKeyUpdate() + .onDuplicateKeyIgnore() + .onDuplicateKeyError() // the default + + .loadCSV(inputstream) + .fields(ID, null, TITLE) + .execute(); + +// Specify behaviour when errors occur. +create.loadInto(T_AUTHOR) + + // choose any of these methods + .onErrorIgnore() + .onErrorAbort() // the default + + .loadCSV(inputstream) + .fields(ID, null, TITLE) + .execute(); + +// Specify transactional behaviour where this is possible +// (e.g. not in container-managed transactions) +create.loadInto(T_AUTHOR) + + // choose any of these methods + .commitEach() + .commitAfter(10) + .commitAll() + .commitNone() // the default + + .loadCSV(inputstream) + .fields(ID, null, TITLE) + .execute();+ +
Any of the above configuration methods can be combined to achieve + the type of load you need. Please refer to the API's Javadoc to learn + about more details. Errors that occur during the load are reported by + the execute method's result:
+ ++Loader<TAuthor> loader = /* .. */ .execute(); + +// The number of processed rows +int processed = loader.processed(); + +// The number of stored rows (INSERT or UPDATE) +int stored = loader.stored(); + +// The number of ignored rows (due to errors, or duplicate rule) +int ignored = loader.ignored(); + +// The errors that may have occurred during loading +List<LoaderError> errors = loader.errors(); +LoaderError error = errors.get(0); + +// The exception that caused the error +SQLException exception = error.exception(); + +// The row that caused the error +int rowIndex = error.rowIndex(); +String[] row = error.row(); + +// The query that caused the error +Query query = error.query();+ +
This will be implemented soon...
+| The jOOQ User Manual : Advanced topics : Importing data from XML, CSV | previous | +The jOOQ User Manual : Advanced topics : Importing data from XML, CSV | previous |
| The jOOQ User Manual : Advanced topics : Master data generation | previous : next | +The jOOQ User Manual : Advanced topics : Master data generation. Enumeration tables | previous : next |
| The jOOQ User Manual : Advanced topics : Master data generation | previous : next | +The jOOQ User Manual : Advanced topics : Master data generation. Enumeration tables | previous : next |
| The jOOQ User Manual : Advanced topics : Adding Oracle hints to queries | previous : next | +The jOOQ User Manual : Advanced topics : Adding Oracle hints to queries | previous : next |
If you are closely coupling your application to an Oracle database, + you might need to be able to pass hints of the form /*+HINT*/ with + your SQL statements to the Oracle database. For example:
++SELECT /*+ALL_ROWS*/ FIRST_NAME, LAST_NAME + FROM T_AUTHOR+ +
This can be done in jOOQ using the .hint() clause in your SELECT statement:
+
+create.select(FIRST_NAME, LAST_NAME)
+ .hint("/*+ALL_ROWS*/")
+ .from(T_AUTHOR);
+
+ Note that you can pass any string in the .hint() clause. If you use + that clause, the passed string will always be put in between the + SELECT [DISTINCT] keywords and the actual projection list
+| The jOOQ User Manual : Advanced topics : Adding Oracle hints to queries | previous : next | +The jOOQ User Manual : Advanced topics : Adding Oracle hints to queries | previous : next |
You may wish to design your database in a way that you have several + instances of your schema. This is useful when you want to cleanly + separate data belonging to several customers / organisation units / + branches / users and put each of those entities' data in a separate + database or schema.
+In our T_AUTHOR example this would mean that you provide a book + reference database to several companies, such as My Book World and + Books R Us. In that case, you'll probably have a schema setup like + this:
+When a user from My Book World logs in, you want them to access the + MY_BOOK_WORLD schema using classes generated from DEV. This can be + achieved with the + org.jooq.SchemaMapping + class, that you can equip your Factory + with. Take the following example:
+ ++SchemaMapping mapping = new SchemaMapping(); +mapping.add(DEV, "MY_BOOK_WORLD"); + +// Add the mapping to the factory +Factory create = new Factory(connection, SQLDialect.ORACLE, mapping); + +// Run queries with the "mapped" factory +create.selectFrom(T_AUTHOR).fetch();+ +
The query executed with a Factory equipped with the above mapping + will in fact produce this SQL statement:
+SELECT * FROM MY_BOOK_WORLD.T_AUTHOR+
Even if T_AUTHOR was generated from DEV.
+ +Your development database may not be restricted to hold only one DEV + schema. You may also have a LOG schema and a MASTER schema. Let's say + the MASTER schema is shared among all customers, but each customer has + their own LOG schema instance. Then you can enhance your SchemaMapping + like this:
+ ++SchemaMapping mapping = new SchemaMapping(); +mapping.add(DEV, "MY_BOOK_WORLD"); +mapping.add(LOG, "MY_BOOK_WORLD_LOG");+ +
This will map generated classes from DEV to MY_BOOK_WORLD, from LOG + to MY_BOOK_WORLD_LOG, but leave the MASTER schema alone. Whenever you + want to change your mapping configuration, you will have to create a + new Factory
+ + +Another option to switch schema names is to use a default schema for + the Factory's underlying Connection. Many RDBMS support a USE or SET + SCHEMA command, which you can call like this:
+ ++// Set the default schema +Schema MY_BOOK_WORLD = ... +create.use(MY_BOOK_WORLD); + +// Run queries with factory having a default schema +create.selectFrom(T_AUTHOR).fetch();+
Queries generated from the above Factory will produce this kind of SQL statement:
+ ++-- the schema name is omitted from all SQL constructs. +SELECT * FROM T_AUTHOR+ + +
Not only schemata can be mapped, but also tables. If you are not the + owner of the database your application connects to, you might need to + install your schema with some sort of prefix to every table. In our + examples, this might mean that you will have to map DEV.T_AUTHOR to + something MY_BOOK_WORLD.MY_APP__T_AUTHOR, where MY_APP__ is a prefix + applied to all of your tables. This can be achieved by creating the + following mapping:
+ ++SchemaMapping mapping = new SchemaMapping(); +mapping.add(DEV, "MY_BOOK_WORLD"); +mapping.add(T_AUTHOR, "MY_APP__T_AUTHOR"); + +// Add the mapping to the factory +Factory create = new Factory(connection, SQLDialect.ORACLE, mapping); + +// Run queries with the "mapped" factory +create.selectFrom(T_AUTHOR).fetch();+ +
The query executed with a Factory equipped with the above mapping will in fact produce this SQL statement:
++SELECT * FROM MY_BOOK_WORLD.MY_APP__T_AUTHOR+
| The jOOQ User Manual : Advanced topics | previous : next | +The jOOQ User Manual : Advanced topics | previous : next |
This section covers some advanced topics and features that don't fit into any other section.
| The jOOQ User Manual : Advanced topics | previous : next | +The jOOQ User Manual : Advanced topics | previous : next |
+ A + org.jooq.Query + and all its contained objects is a + org.jooq.QueryPart. + QueryParts essentially provide this functionality: +
+Both of these methods are contained in jOOQ's internal API's + org.jooq.QueryPartInternal, which is + internally implemented by every QueryPart. QueryPart internals are best + illustrated with an example.
+ +A simple example can be provided by checking out jOOQ's internal + representation of a + org.jooq.impl.CompareCondition. + It is used for any condition + comparing two fields as for example the T_AUTHOR.ID = T_BOOK.AUTHOR_ID + condition here:
++-- [...] +FROM T_AUTHOR +JOIN T_BOOK ON T_AUTHOR.ID = T_BOOK.AUTHOR_ID +-- [...]+ +
This is how jOOQ implements such a condition:
+ +
+
+@Override
+public final void bind(BindContext context) throws SQLException {
+ // The CompareCondition itself does not bind any variables.
+ // But the two fields involved in the condition might do so...
+ context.bind(field1).bind(field2);
+}
+
+@Override
+public final void toSQL(RenderContext context) {
+ // The CompareCondition delegates rendering of the Fields to the Fields
+ // themselves and connects them using the Condition's comparator operator:
+ context.sql(field1)
+ .sql(" ");
+
+ // If the second field is null, some convenience behaviour can be
+ // implemented here
+ if (field2.isNullLiteral()) {
+ switch (comparator) {
+ case EQUALS:
+ context.sql("is null");
+ break;
+
+ case NOT_EQUALS:
+ context.sql("is not null");
+ break;
+
+ default:
+ throw new IllegalStateException("Cannot compare null with " + comparator);
+ }
+ }
+
+ // By default, also delegate the right hand side's SQL rendering to the
+ // underlying field
+ else {
+ context.sql(comparator.toSQL())
+ .sql(" ")
+ .sql(field2);
+ }
+}
+
+ For more complex examples, please refer to the codebase, directly
+| The jOOQ User Manual : jOOQ classes and their usage : QueryParts and the global architecture | previous : next |
| ID | +AUTHOR_ID | +TITLE | +||||||
|---|---|---|---|---|---|---|---|---|
| 1 | +1 | +1984 | +||||||
| 2 | +1 | +Animal Farm | +
Export your results as text:
+The above query will result in a text document looking like the following one:
+If you are using jOOQ for scripting purposes or in a slim, unlayered + application server, you might be interested in using jOOQ's importing + functionality (see also exporting functionality). You can import data + directly into a table from any of these formats:
+ +The below CSV data represents two author records that may have been + exported previously, by jOOQ's exporting functionality, and then + modified in Microsoft Excel or any other spreadsheet tool:
+ +With jOOQ, you can load this data using various parameters from the + loader API. A simple load may look like this:
+ +Here are various other examples:
+Any of the above configuration methods can be combined to achieve + the type of load you need. Please refer to the API's Javadoc to learn + about more details. Errors that occur during the load are reported by + the execute method's result:
+ +This will be implemented soon...
+