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 @@ + jOOQ diff --git a/jOOQ-website/manual/ADVANCED/CONNECTBY/index.php b/jOOQ-website/manual/ADVANCED/CONNECTBY/index.php index 8c746580a2..0e0f093cf4 100644 --- a/jOOQ-website/manual/ADVANCED/CONNECTBY/index.php +++ b/jOOQ-website/manual/ADVANCED/CONNECTBY/index.php @@ -4,24 +4,78 @@ // Please do not edit this content manually require '../../../frame.php'; function printH1() { - print "The Oracle CONNECT BY clause for hierarchical queries"; + print "The Oracle CONNECT BY clause"; } function getActiveMenu() { return "manual"; } function getSlogan() { - return ""; + return " + Hierarchical queries are supported by many RDBMS using the WITH clause. + Oracle has a very neat and much less verbose syntax for hierarchical + queries: CONNECT BY .. STARTS WITH + "; } function printContent() { global $root; ?> - + -
The jOOQ User Manual : Advanced topics : The Oracle CONNECT BY clause for hierarchical queriesprevious : nextThe jOOQ User Manual : Advanced topics : The Oracle CONNECT BY clauseprevious : next

+
+

CONNECT BY .. STARTS WITH

+

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 queriesprevious : nextThe jOOQ User Manual : Advanced topics : The Oracle CONNECT BY clauseprevious : next
- + -
The jOOQ User Manual : Advanced topics : Exporting data to XML, CSV, JSON, HTML, Textprevious : nextThe jOOQ User Manual : Advanced topics : Exporting to XML, CSV, JSON, HTML, Textprevious : next

+
+

Exporting with jOOQ

+

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:

+ +

XML

+

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>
+ +

CSV

+

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
+ + +

JSON

+

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"]]}
+ +

HTML

+

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>
+ +

Text

+

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, Textprevious : nextThe jOOQ User Manual : Advanced topics : Exporting to XML, CSV, JSON, HTML, Textprevious : next
- + -
The jOOQ User Manual : Advanced topics : Importing data from XML, CSVpreviousThe jOOQ User Manual : Advanced topics : Importing data from XML, CSVprevious

+
+

Importing with jOOQ

+

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:

+ +

CSV

+

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();
+ +

XML

+

This will be implemented soon...

+
- +
The jOOQ User Manual : Advanced topics : Importing data from XML, CSVpreviousThe jOOQ User Manual : Advanced topics : Importing data from XML, CSVprevious
- +
The jOOQ User Manual : Advanced topics : Master data generationprevious : nextThe jOOQ User Manual : Advanced topics : Master data generation. Enumeration tablesprevious : next

Enumeration tables

@@ -127,7 +127,7 @@ public class TBookRecord extends UpdatableRecordImpl<TBookRecord> { type is generated.


- +
The jOOQ User Manual : Advanced topics : Master data generationprevious : nextThe jOOQ User Manual : Advanced topics : Master data generation. Enumeration tablesprevious : next
- + -
The jOOQ User Manual : Advanced topics : Adding Oracle hints to queriesprevious : nextThe jOOQ User Manual : Advanced topics : Adding Oracle hints to queriesprevious : next

+
+

How to embed Oracle hints in SELECT

+

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 queriesprevious : nextThe jOOQ User Manual : Advanced topics : Adding Oracle hints to queriesprevious : next
- + -
The jOOQ User Manual : Advanced topics : Mapping generated schemata and tables to productive environmentsprevious : nextThe jOOQ User Manual : Advanced topics : Mapping generated schemata and tablesprevious : next

+
+

Mapping your DEV schema to a productive environment

+

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:

+ + + +

Mapping DEV to MY_BOOK_WORLD with jOOQ

+

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.

+ +

Mapping several schemata

+

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

+ + +

Using a default schema

+

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
+ + +

Mapping of tables

+

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 : Mapping generated schemata and tables to productive environmentsprevious : nextThe jOOQ User Manual : Advanced topics : Mapping generated schemata and tablesprevious : next
- +
The jOOQ User Manual : Advanced topicsprevious : nextThe jOOQ User Manual : Advanced topicsprevious : next

Overview

This section covers some advanced topics and features that don't fit into any other section.

Table of contents

  1. -Master data generation +Master data generation. Enumeration tables
  2. -Mapping generated schemata and tables to productive environments +Mapping generated schemata and tables
  3. Adding Oracle hints to queries
  4. -The Oracle CONNECT BY clause for hierarchical queries +The Oracle CONNECT BY clause
  5. -Exporting data to XML, CSV, JSON, HTML, Text +Exporting to XML, CSV, JSON, HTML, Text
  6. Importing data from XML, CSV

- +
The jOOQ User Manual : Advanced topicsprevious : nextThe jOOQ User Manual : Advanced topicsprevious : next
org.jooq.SchemaMapping : An optional mapping of schemata. Check out the - SchemaMapping + SchemaMapping page for details @@ -89,7 +89,7 @@ MySQLFactory create = new MySQLFactory(connection);