• About Us
  • Privacy Policy
  • Disclaimer
  • Contact Us
AimactGrow
  • Home
  • Technology
  • AI
  • SEO
  • Coding
  • Gaming
  • Cybersecurity
  • Digital marketing
No Result
View All Result
  • Home
  • Technology
  • AI
  • SEO
  • Coding
  • Gaming
  • Cybersecurity
  • Digital marketing
No Result
View All Result
AimactGrow
No Result
View All Result

Create Dynamic Views with jOOQ 3.17’s new Digital Shopper Facet Computed Columns – Java, SQL and jOOQ.

Admin by Admin
May 26, 2025
Home Coding
Share on FacebookShare on Twitter


One in all jOOQ 3.17‘s coolest new options are shopper aspect computed columns. jOOQ 3.16 already added help for server aspect computed columns, which lots of you recognize for numerous causes.

What’s a computed column?

A computed column is a column that’s derived (“computed”) from an expression. It can’t be written to. It really works like every column in a view. There are two sorts of computed columns:

  • VIRTUAL computed columns, that are computed “on learn”
  • STORED computed columns, that are computed “on write”

Some SQL dialects use these actual phrases to differentiate between the 2 options. Some dialects help each of them, some solely help certainly one of them.

Some typical use-cases for server aspect computed columns embrace:

CREATE TABLE buyer (
  id BIGINT NOT NULL PRIMARY KEY,
  first_name TEXT NOT NULL,
  last_name TEXT NOT NULL,
  full_name TEXT GENERATED ALWAYS AS 
    (first_name || ' ' || last_name) STORED
);

Now, attempt to insert some knowledge into this desk:

INSERT INTO buyer (id, first_name, last_name)
VALUES (1, 'John', 'Doe')
RETURNING *;

And you’re going to get:

|id |first_name|last_name|full_name|
|---|----------|---------|---------|
|1  |John      |Doe      |John Doe |

What are some limitations?

That’s an exquisite characteristic. Sadly, as all the time:

  • Not all dialects help it
  • Not all dialects help each VIRTUAL and/or STORED (each approaches have their advantages)
  • The characteristic itself is sort of restricted in SQL

Let’s have a look at the third bullet. What if we needed to “compute” a column through the use of joins or correlated subqueries? We can not, in SQL. E.g. PostgreSQL rejects this:

CREATE TABLE buyer (
  id BIGINT NOT NULL PRIMARY KEY,
  first_name TEXT NOT NULL,
  last_name TEXT NOT NULL,
  address_id BIGINT REFERENCES handle,
  full_address TEXT GENERATED ALWAYS AS ((
    SELECT a.handle 
    FROM handle AS a
    WHERE a.address_id = buyer.address_id
  )) VIRTUAL
);

Why?

  • It doesn’t help VIRTUAL, solely STORED
  • Even when it did help VIRTUAL, it at present throws SQL Error [0A000]: ERROR: can not use subquery in column technology expression

There isn’t actually any good purpose that I can see for this limitation. In spite of everything, you may simply create a view like this:

CREATE VIEW v_customer AS
SELECT 
  id, first_name, last_name, address_id,
  (
    SELECT a.handle 
    FROM handle AS a
    WHERE a.address_id = buyer.address_id
  ) AS full_address
FROM buyer

And now, you could have the specified behaviour. This strategy has its personal caveats, together with:

  • The view will not be the desk. Each dialect has limitations with respect to updatable views, i.e. it may be tough to write down to this view.
  • Views are saved objects, and as such should be versioned and put in. This isn’t an enormous downside per se, however there are people who attempt to keep away from this, due to… properly, the additional effort of doing database change administration accurately?
  • You all the time need to resolve whether or not to question the view or the desk.

Enter jOOQ’s shopper aspect computed columns

That is why jOOQ 3.17 now presents this excellent characteristic on the shopper aspect. Each variations are supported:

  • VIRTUAL computed columns are columns which might be changed by their respective expression when the column seems in any non-write place, e.g. SELECT, WHERE, but additionally RETURNING
  • STORED computed columns are columns which might be computed when written to, e.g. in INSERT, UPDATE, MERGE

Let’s first have a look at VIRTUAL computed columns. The above two use-cases will be configured as follows within the code generator, assuming a Maven config.


    
        

            
            
                
                    
                        buyer|workers|retailer
                        full_address
                        textual content
                    
                    
                        buyer|workers
                        full_name
                        textual content
                    
                
            

            
            
                
                    ctx -> DSL.concat(
                        FIRST_NAME, DSL.inline(" "), LAST_NAME)
                    
                    full_name
                
                
                    ctx -> DSL.concat(
                        handle().ADDRESS_, 
                        DSL.inline(", "), 
                        handle().POSTAL_CODE, 
                        DSL.inline(", "), 
                        handle().metropolis().CITY_, 
                        DSL.inline(", "), 
                        handle().metropolis().nation().COUNTRY_
                    )
                    full_address
                
            
        
    

The above instance makes use of two new code technology options:

That’s it. With these two issues, you may register a single jOOQ Area expression that computes the worth of your required columns. Discover how the FULL_ADDRESS makes use of implicit joins to simplify entry to different tables. In fact, you possibly can have additionally written a correlated subquery, which is one approach to implement these implicit joins. It might have simply been a bit extra laborious.

You may question these columns like every other in jOOQ:

Outcome> outcome =
ctx.choose(CUSTOMER.FULL_NAME, CUSTOMER.FULL_ADDRESS)
   .from(CUSTOMER)
   .fetch();

The generated question does all of the becoming a member of for you, transparently:

choose
  buyer.first_name || ' ' || buyer.last_name 
    as full_name,
  alias_114975355.handle || ', ' || 
  alias_114975355.postal_code || ', ' || 
  alias_57882359.metropolis || ', ' || 
  alias_1060004.nation
    as full_address
from (
  buyer
    be a part of (
      handle as alias_114975355
        be a part of (
          metropolis as alias_57882359
            be a part of nation as alias_1060004
              on alias_57882359.country_id = alias_1060004.country_id
        )
          on alias_114975355.city_id = alias_57882359.city_id
    )
      on buyer.address_id = alias_114975355.address_id
  )

The outcome being:

+----------------+------------------------------------------------+
|full_name       |full_address                                    |
+----------------+------------------------------------------------+
|ANDREA HENDERSON|320 Baiyin Parkway, 37307, Mahajanga, Madagascar|
|CLARA SHAW      |1027 Songkhla Manor, 30861, Molodetno, Belarus  |
|SHANE MILLARD   |184 Mandaluyong Avenue, 94239, La Paz, Mexico   |
|DANNY ISOM      |734 Bchar Place, 30586, Okara, Pakistan         |
|VALERIE BLACK   |782 Mosul Avenue, 25545, Brockton, United States|
|...             |...                                             |
+----------------+------------------------------------------------+

Be aware that as you’d anticipate, in the event you omit certainly one of these columns, the related components of the question aren’t generated, together with implicit joins. So, for instance, in the event you question this:

Outcome> outcome =
ctx.choose(CUSTOMER.FULL_NAME)
   .from(CUSTOMER)
   .fetch();

The generated SQL is far easier:

choose buyer.first_name || ' ' || buyer.last_name as full_name
from buyer

A extra advanced instance

SQL JOINs will be fairly boring and repetitive at occasions. Think about this schema:

CREATE TABLE foreign money (
  code CHAR(3) NOT NULL,
  
  PRIMARY KEY (code)
);

CREATE TABLE conversion (
  from_currency CHAR(3) NOT NULL,
  to_currency CHAR(3) NOT NULL,
  fee NUMERIC(18, 2) NOT NULL,
  
  PRIMARY KEY (from_currency, to_currency),
  FOREIGN KEY (from_currency) REFERENCES foreign money,
  FOREIGN KEY (to_currency) REFERENCES foreign money
);

CREATE TABLE transaction (
  id BIGINT NOT NULL,
  quantity NUMERIC(18, 2) NOT NULL,
  foreign money CHAR(3) NOT NULL,
  
  PRIMARY KEY (id),
  FOREIGN KEY (foreign money) REFERENCES foreign money
);

A typical (however simplified) finance software that has transactions with quantities and a foreign money related to the quantity. Think about the CONVERSION desk may have bitemporal versioning to ensure we will calculate the proper conversion fee at any given date, if wanted.

Now, any time we need to sum up transactions, we’ve to transform the quantity to some person foreign money, regardless of the transaction foreign money. Isn’t that boring? We shouldn’t need to repeat this logic in every single place.

You may in fact write views like this:

CREATE VIEW v_transaction AS
SELECT
  id, quantity, foreign money,
  quantity * (
    SELECT c.fee
    FROM conversion AS c
    WHERE c.from_currency = t.foreign money
    AND c.to_currency = 'USD'
  ) AS amount_usd
FROM transaction AS t

That may assist summing up all transactions in USD. If we wanted a unique foreign money, we will both create completely different views, create saved (desk valued, even?) capabilities, or generate the SQL with jOOQ.

However why not simply retailer the computation with the jOOQ generated desk immediately?


    
        

            
            
                
                    
                        TRANSACTION
                        AMOUNT_USD
                        NUMERIC
                    
                    
                        TRANSACTION
                        AMOUNT_USER_CURRENCY
                        NUMERIC
                    
                
            

            
            
                
                    ctx -> AMOUNT.occasions(DSL.area(
   DSL.choose(Conversion.CONVERSION.RATE)
      .from(Conversion.CONVERSION)
      .the place(Conversion.CONVERSION.FROM_CURRENCY.eq(CURRENCY))
      .and(Conversion.CONVERSION.TO_CURRENCY.eq(
           DSL.inline("USD")))))
                    
                    
                        TRANSACTION.AMOUNT_USD
                    
                
                
                    ctx -> AMOUNT.occasions(DSL.area(
    DSL.choose(Conversion.CONVERSION.RATE)
       .from(Conversion.CONVERSION)
       .the place(Conversion.CONVERSION.FROM_CURRENCY.eq(CURRENCY))
       .and(Conversion.CONVERSION.TO_CURRENCY.eq(
           (String) ctx.configuration().knowledge("USER_CURRENCY")))))
                    
                    
                        TRANSACTION.AMOUNT_USER_CURRENCY
                    
                
            
        
    

It does what you’d anticipate it does. Connect a correlated subquery to the 2 columns. The fascinating bit, nevertheless is the AMOUNT_USER_CURRENCY column. It accesses ctx.configuration().knowledge("USER_CURRENCY"). That’s simply arbitrary user-defined knowledge, which you’ll be able to move round jOOQ and entry from wherever.

If you run this question with out setting that "USER_CURRENCY" info like this:

ctx.choose(
        TRANSACTION.ID,
        TRANSACTION.AMOUNT,
        TRANSACTION.CURRENCY,
        TRANSACTION.AMOUNT_USD,
        TRANSACTION.AMOUNT_USER_CURRENCY,
        sum(TRANSACTION.AMOUNT_USD).over().as("total_usd"),
        sum(TRANSACTION.AMOUNT_USER_CURRENCY).over()
            .as("total_user_currency"))
   .from(TRANSACTION)
   .orderBy(TRANSACTION.ID))
   .fetch()

The generated SQL is that this:

choose
  TRANSACTION.ID,
  TRANSACTION.AMOUNT,
  TRANSACTION.CURRENCY,
  (TRANSACTION.AMOUNT * (
    choose CONVERSION.RATE
    from CONVERSION
    the place (
      CONVERSION.FROM_CURRENCY = TRANSACTION.CURRENCY
      and CONVERSION.TO_CURRENCY = 'USD'
    )
  )) AMOUNT_USD,
  (TRANSACTION.AMOUNT * (
    choose CONVERSION.RATE
    from CONVERSION
    the place (
      CONVERSION.FROM_CURRENCY = TRANSACTION.CURRENCY
      and CONVERSION.TO_CURRENCY = null
    )
  )) AMOUNT_USER_CURRENCY,
  sum((TRANSACTION.AMOUNT * (
    choose CONVERSION.RATE
    from CONVERSION
    the place (
      CONVERSION.FROM_CURRENCY = TRANSACTION.CURRENCY
      and CONVERSION.TO_CURRENCY = 'USD'
    )
  ))) over () total_usd,
  sum((TRANSACTION.AMOUNT * (
    choose CONVERSION.RATE
    from CONVERSION
    the place (
      CONVERSION.FROM_CURRENCY = TRANSACTION.CURRENCY
      and CONVERSION.TO_CURRENCY = null
    )
  ))) over () total_user_currency
from TRANSACTION
order by TRANSACTION.ID

The person foreign money is undefined (i.e. NULL), so we don’t get something for it:

+----+------+--------+----------+--------------------+---------+-------------------+
|  ID|AMOUNT|CURRENCY|AMOUNT_USD|AMOUNT_USER_CURRENCY|total_usd|total_user_currency|
+----+------+--------+----------+--------------------+---------+-------------------+
|   1| 12.25|EUR     |   12.7400|              {null}| 150.0978|             {null}|
|   2| 15.37|USD     |   15.3700|              {null}| 150.0978|             {null}|
|   3| 99.99|GBP     |  121.9878|              {null}| 150.0978|             {null}|
+----+------+--------+----------+--------------------+---------+-------------------+

Now, let’s run the question once more after setting the configuration().knowledge() worth like this:

// This mutates the configuration.
// To make a replica, use configuration().derive()
ctx.configuration().knowledge("USER_CURRENCY", "CHF");

And all of the sudden, we get a unique outcome:

+----+------+--------+----------+--------------------+---------+-------------------+
|  ID|AMOUNT|CURRENCY|AMOUNT_USD|AMOUNT_USER_CURRENCY|total_usd|total_user_currency|
+----+------+--------+----------+--------------------+---------+-------------------+
|   1| 12.25|EUR     |   12.7400|             12.2500| 150.0978|           142.9936|
|   2| 15.37|USD     |   15.3700|             14.7552| 150.0978|           142.9936|
|   3| 99.99|GBP     |  121.9878|            115.9884| 150.0978|           142.9936|
+----+------+--------+----------+--------------------+---------+-------------------+

That is extraordinarily highly effective! Think about an software the place you:

  • Get a connection from the connection pool
  • Initialise just a few context variables, such because the person, and their settings
  • Mechanically have arbitrary “views” (i.e. jOOQ expressions, each from dynamic SQL or from this characteristic) replace their contents

A real jOOQ and SQL energy person dream.

Extra prospects

The above examples had been simply displaying easy instances of scalar subqueries. However nothing retains you from utilizing:

In spite of everything, a shopper aspect computed column is only a “variable” referencing an expression that’s expanded while you run the question utilizing that column.

Caveats

Not like server aspect digital computed columns, you can’t put an index on these, as a result of the server doesn’t know something concerning the column, or the expression. Which means the characteristic is principally helpful for projections and aggregations / computations, much less for queries. For instance, possibly don’t run filters on such columns.

Saved shopper aspect computed columns

A future weblog publish will speak concerning the STORED model of shopper aspect computed columns, which additionally consists of the brand new audit column characteristic. As a teaser, simply implement a Generator just like the above on a non-synthetic column (i.e. an precise column out of your schema), and voilà, the behaviour is now fully completely different.

Extra details about this:

Like this:

Like Loading…

Tags: 3.17sClientcolumnsComputedCreateDynamicJavajOOQSideSQLViewsVirtual
Admin

Admin

Next Post
Menace Actor Sells Burger King Backup System RCE Vulnerability for $4,000

Menace Actor Sells Burger King Backup System RCE Vulnerability for $4,000

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Recommended.

Star Wars and The Mandalorian Invade Monopoly Go

Star Wars and The Mandalorian Invade Monopoly Go

April 18, 2025
Easy and painless productiveness | Seth’s Weblog

Easy and painless productiveness | Seth’s Weblog

April 23, 2025

Trending.

Industrial-strength April Patch Tuesday covers 135 CVEs – Sophos Information

Industrial-strength April Patch Tuesday covers 135 CVEs – Sophos Information

April 10, 2025
Expedition 33 Guides, Codex, and Construct Planner

Expedition 33 Guides, Codex, and Construct Planner

April 26, 2025
How you can open the Antechamber and all lever places in Blue Prince

How you can open the Antechamber and all lever places in Blue Prince

April 14, 2025
Important SAP Exploit, AI-Powered Phishing, Main Breaches, New CVEs & Extra

Important SAP Exploit, AI-Powered Phishing, Main Breaches, New CVEs & Extra

April 28, 2025
Wormable AirPlay Flaws Allow Zero-Click on RCE on Apple Units by way of Public Wi-Fi

Wormable AirPlay Flaws Allow Zero-Click on RCE on Apple Units by way of Public Wi-Fi

May 5, 2025

AimactGrow

Welcome to AimactGrow, your ultimate source for all things technology! Our mission is to provide insightful, up-to-date content on the latest advancements in technology, coding, gaming, digital marketing, SEO, cybersecurity, and artificial intelligence (AI).

Categories

  • AI
  • Coding
  • Cybersecurity
  • Digital marketing
  • Gaming
  • SEO
  • Technology

Recent News

What’s going to influencer advertising and marketing appear to be in 2025? Knowledgeable predictions + new knowledge

What’s going to influencer advertising and marketing appear to be in 2025? Knowledgeable predictions + new knowledge

June 18, 2025
Yoast AI Optimize now out there for Basic Editor • Yoast

Replace on Yoast AI Optimize for Traditional Editor  • Yoast

June 18, 2025
  • About Us
  • Privacy Policy
  • Disclaimer
  • Contact Us

© 2025 https://blog.aimactgrow.com/ - All Rights Reserved

No Result
View All Result
  • Home
  • Technology
  • AI
  • SEO
  • Coding
  • Gaming
  • Cybersecurity
  • Digital marketing

© 2025 https://blog.aimactgrow.com/ - All Rights Reserved