{"id":23948,"date":"2026-08-29T09:52:40","date_gmt":"2026-08-29T07:52:40","guid":{"rendered":"https:\/\/www.salvis.com\/blog\/?p=23948"},"modified":"2026-08-29T09:52:43","modified_gmt":"2026-08-29T07:52:43","slug":"implicit-outer-joins-in-join-to-one-feature-or-flaw","status":"publish","type":"post","link":"https:\/\/www.salvis.com\/blog\/2026\/08\/29\/implicit-outer-joins-in-join-to-one-feature-or-flaw\/","title":{"rendered":"Implicit Outer Joins in Join-to-One: Feature or Flaw?"},"content":{"rendered":"\n<h2 id=\"background\" class=\"wp-block-heading\">Background<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">As you probably know, I&#8217;m maintaining a parser for grammars used in SQL files for Oracle AI Database and PostgreSQL. As a result, I check for new statements and clauses in every version of those DBMSs. PostgreSQL typically adds new features only in major versions; this means yearly. Oracle, on the other hand, documents new features in every new RU; this means quarterly. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The RU for 26.2 was a bit delayed. So, on 1 May 2026, I went through the new features in 26.2 and discovered the <a href=\"https:\/\/docs.oracle.com\/en\/database\/oracle\/oracle-database\/26\/adfns\/building-queries-correct-joins-more-easily.html#GUID-FEB8218C-8FD5-47BC-BB14-4E43DDD32F35\" target=\"_blank\" rel=\"noreferrer noopener\">join-to-one clause<\/a> while documenting the changes required for IslandSQL in a <a href=\"https:\/\/github.com\/IslandSQL\/IslandSQL\/issues\/315\" data-type=\"link\" data-id=\"https:\/\/github.com\/IslandSQL\/IslandSQL\/issues\/315\" target=\"_blank\" rel=\"noreferrer noopener\">GitHub issue<\/a>. I tried the feature in an OCI instance and posted about it on Bluesky.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/bsky.app\/profile\/salvis.com\/post\/3mkt4dj3ofc2c\" target=\"_blank\" rel=\" noopener\"><img loading=\"lazy\" decoding=\"async\" width=\"592\" height=\"511\" src=\"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/08\/join-to-one-post-on-bsky.png\" alt=\"Join to one post on Bluesky\" class=\"wp-image-23950\" srcset=\"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/08\/join-to-one-post-on-bsky.png 592w, https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/08\/join-to-one-post-on-bsky-300x259.png 300w, https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/08\/join-to-one-post-on-bsky-87x75.png 87w, https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/08\/join-to-one-post-on-bsky-480x414.png 480w\" sizes=\"auto, (max-width:767px) 480px, 592px\" \/><\/a><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">This led to some discussions in private channels. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Back then, I hadn&#8217;t made up my mind regarding the usefulness of this feature, but the fact that a join uses outer-join semantics by default irritated me from the very first moment.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In the meantime, I believe that this feature is useful for various use cases. I&#8217;m not going to talk about that in this blog post. However, the longer I thought about the implicit outer join in join-to-one, the more it irritated me.<\/p>\n\n\n\n<h2 id=\"join-to-one-will-make-it-into-the-sql-standard\" class=\"wp-block-heading\">Join-To-One Will Make It Into the SQL Standard<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">According to <a href=\"https:\/\/peter.eisentraut.org\/blog\/2026\/06\/30\/waiting-for-sql-202y-stockholm-meeting-report#join-to-one\" target=\"_blank\" rel=\"noreferrer noopener\">Peter Eisentraut&#8217;s blog post<\/a>, this feature has been accepted into the next SQL standard and is now part of its working draft. I wonder whether they also discussed the default join behaviour of a join-to-one and what the consensus was. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Anyway, since version 26.2, this feature is part of Oracle AI Database. Changing the behaviour at that stage is only feasible with a database parameter similar to <a href=\"https:\/\/docs.oracle.com\/en\/database\/oracle\/oracle-database\/26\/refrn\/GROUP_BY_POSITION_ENABLED.html\" data-type=\"link\" data-id=\"https:\/\/docs.oracle.com\/en\/database\/oracle\/oracle-database\/26\/refrn\/GROUP_BY_POSITION_ENABLED.html\" target=\"_blank\" rel=\"noreferrer noopener\">group_by_position_enabled<\/a> to keep backward compatibility. I doubt that something like this will happen.<\/p>\n\n\n\n<h2 id=\"what-is-the-problem\" class=\"wp-block-heading\">What Is the Problem?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">It is the first time an outer join has become the default. For every other join variant since ANSI SQL-86, an inner join has been the default. We are used to that.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Changing such a long-established convention is not necessarily a bad thing. However, there should be a convincing reason for doing so.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The <a href=\"https:\/\/docs.oracle.com\/en\/database\/oracle\/oracle-database\/26\/sqlrf\/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6__GUID-9388EBCC-9ADE-4668-AAF4-D6193B8395F2\" data-type=\"link\" data-id=\"https:\/\/docs.oracle.com\/en\/database\/oracle\/oracle-database\/26\/sqlrf\/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6__GUID-9388EBCC-9ADE-4668-AAF4-D6193B8395F2\" target=\"_blank\" rel=\"noreferrer noopener\">SQL Language Reference<\/a> provides this reason:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">&#8220;The database chose this default because <code>INNER JOIN<\/code>s often filter rows unintentionally.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">So, the intention is to avoid accidental filtering. That sounds reasonable. But is silently preserving rows really better than silently filtering them?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In both cases, the omitted join type affects the result. An implicit inner join may remove rows. An implicit outer join may introduce null values that have to be considered in subsequent expressions and predicates.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In any case, the join-to-one clause relies on integrity constraints. These constraints are already used to derive the join condition. So why not consider them fully and choose an inner join for mandatory foreign keys and an outer join for optional foreign keys?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Of course, this would make the join type depend on the schema definition. A change to the optionality of a foreign key could then change the semantics of an existing query. That would have been a very good reason not to choose a fixed default join type, right?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">However, while the optimiser could deal with a dynamically determined join type, the query would be more challenging to read and understand. We would need to check the current optionality of each foreign key involved to determine whether nulls need to be handled.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ouch. This would be cumbersome without implementing an additional concept that forces us to handle null values in SQL expressions and predicates (something similar to <a href=\"https:\/\/jspecify.dev\/docs\/user-guide\/\" data-type=\"link\" data-id=\"https:\/\/jspecify.dev\/docs\/user-guide\/\" target=\"_blank\" rel=\"noreferrer noopener\">JSpecify<\/a>). Therefore, it&#8217;s probably better not to derive the join type automatically from a foreign key&#8217;s optionality. Being explicit has its value.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Furthermore, an outer join limits the optimiser&#8217;s solution space and can affect performance, as Andrej Pashchenko demonstrated for join-to-one in <a href=\"https:\/\/blog.sqlora.com\/en\/oracle-26ai-an-even-closer-look-at-join-to-one\/\" data-type=\"link\" data-id=\"https:\/\/blog.sqlora.com\/en\/oracle-26ai-an-even-closer-look-at-join-to-one\/\" target=\"_blank\" rel=\"noreferrer noopener\">this blog post<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">These performance aspects may be addressed in upcoming versions. But the unfamiliar implicit default join strategy remains.<\/p>\n\n\n\n<h2 id=\"an-example\" class=\"wp-block-heading\">An Example<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s compare the following two queries:<\/p>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">1) Implicit outer joins<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>select count(*)\n  from employees e\n  join to one (\n          departments d,\n          jobs j,\n          employees mgr on e.manager_id \n                       = mgr.employee_id\n       )\n where e.salary > mgr.salary;<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #569CD6\">select<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">count<\/span><span style=\"color: #D4D4D4\">(*)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #569CD6\">from<\/span><span style=\"color: #D4D4D4\"> employees e<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #569CD6\">join<\/span><span style=\"color: #D4D4D4\"> to one (<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">          departments d,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">          jobs j,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">          employees mgr <\/span><span style=\"color: #569CD6\">on<\/span><span style=\"color: #D4D4D4\"> e.manager_id <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                       = mgr.employee_id<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">       )<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">where<\/span><span style=\"color: #D4D4D4\"> e.salary &gt; mgr.salary;<\/span><\/span><\/code><\/pre><\/div>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">2) Explict inner and outer joins<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>select count(*)\n  from employees e\n  join to one (\n          outer join departments d\n          inner join jobs j\n          outer join employees mgr on e.manager_id \n                                  = mgr.employee_id\n       )\n where e.salary > mgr.salary;<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #569CD6\">select<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">count<\/span><span style=\"color: #D4D4D4\">(*)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #569CD6\">from<\/span><span style=\"color: #D4D4D4\"> employees e<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #569CD6\">join<\/span><span style=\"color: #D4D4D4\"> to one (<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">          outer <\/span><span style=\"color: #569CD6\">join<\/span><span style=\"color: #D4D4D4\"> departments d<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">          inner <\/span><span style=\"color: #569CD6\">join<\/span><span style=\"color: #D4D4D4\"> jobs j<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">          outer <\/span><span style=\"color: #569CD6\">join<\/span><span style=\"color: #D4D4D4\"> employees mgr <\/span><span style=\"color: #569CD6\">on<\/span><span style=\"color: #D4D4D4\"> e.manager_id <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                                  = mgr.employee_id<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">       )<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">where<\/span><span style=\"color: #D4D4D4\"> e.salary &gt; mgr.salary;<\/span><\/span><\/code><\/pre><\/div>\n<\/div>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The queries are based on the HR example schema and produce the same result.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Which one is easier to read and understand?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Which one reveals information that might be helpful when crafting or reviewing the WHERE clause?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">IMO, the second example. For both questions.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The second example shows that: <\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Employees do not necessarily belong to a department. Yes, the <code>department_id<\/code> column in the <code>employees<\/code> table is optional.<\/li>\n\n\n\n<li>Not every employee has a manager.<\/li>\n\n\n\n<li>Every employee has a job.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">This information helps us filter data using the department or manager columns. We have to handle null values there.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Based on that, we can see a flaw in the query. We can either use an inner join for managers because we are not interested in counting employees without a manager, or we have to address employees without a manager in the WHERE clause.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So, we should change the query to something like the following:<\/p>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">2a) Excluding emps without mgr<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>select count(*)\n  from employees e\n  join to one (\n          outer join departments d\n          inner join jobs j\n          inner join employees mgr on e.manager_id \n                                  = mgr.employee_id\n       )\n where e.salary > mgr.salary;<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #569CD6\">select<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">count<\/span><span style=\"color: #D4D4D4\">(*)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #569CD6\">from<\/span><span style=\"color: #D4D4D4\"> employees e<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #569CD6\">join<\/span><span style=\"color: #D4D4D4\"> to one (<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">          outer <\/span><span style=\"color: #569CD6\">join<\/span><span style=\"color: #D4D4D4\"> departments d<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">          inner <\/span><span style=\"color: #569CD6\">join<\/span><span style=\"color: #D4D4D4\"> jobs j<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">          inner <\/span><span style=\"color: #569CD6\">join<\/span><span style=\"color: #D4D4D4\"> employees mgr <\/span><span style=\"color: #569CD6\">on<\/span><span style=\"color: #D4D4D4\"> e.manager_id <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                                  = mgr.employee_id<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">       )<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">where<\/span><span style=\"color: #D4D4D4\"> e.salary &gt; mgr.salary;<\/span><\/span><\/code><\/pre><\/div>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-highlight-color:rgba(234, 191, 191, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">2b) Including emps without mgr<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>select count(*)\n  from employees e\n  join to one (\n          outer join departments d\n          inner join jobs j\n          outer join employees mgr on e.manager_id \n                                  = mgr.employee_id\n       )\n where e.salary > mgr.salary\n    or mgr.employee_id is null;<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #569CD6\">select<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">count<\/span><span style=\"color: #D4D4D4\">(*)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #569CD6\">from<\/span><span style=\"color: #D4D4D4\"> employees e<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #569CD6\">join<\/span><span style=\"color: #D4D4D4\"> to one (<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">          outer <\/span><span style=\"color: #569CD6\">join<\/span><span style=\"color: #D4D4D4\"> departments d<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">          inner <\/span><span style=\"color: #569CD6\">join<\/span><span style=\"color: #D4D4D4\"> jobs j<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">          outer <\/span><span style=\"color: #569CD6\">join<\/span><span style=\"color: #D4D4D4\"> employees mgr <\/span><span style=\"color: #569CD6\">on<\/span><span style=\"color: #D4D4D4\"> e.manager_id <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                                  = mgr.employee_id<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">       )<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">where<\/span><span style=\"color: #D4D4D4\"> e.salary &gt; mgr.salary<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">or<\/span><span style=\"color: #D4D4D4\"> mgr.employee_id <\/span><span style=\"color: #569CD6\">is null<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span><\/code><\/pre><\/div>\n<\/div>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Query 2a produces the same result as queries 1 and 2, but the inner join on employees makes it clear that excluding employees without a manager was intended.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Query 2b produces additional results for employees without a manager. The outer join on employees and the null handling in the WHERE clause make it clear that this was intentional.<\/p>\n\n\n\n<h2 id=\"summary\" class=\"wp-block-heading\">Summary<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">IMO, the implicit outer joins in the new join-to-one clause are clearly a flaw. You should always specify inner or outer joins explicitly in a join-to-one clause. This communicates the intended semantics and highlights where downstream null handling may be required.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you are using <a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=Grisselbav.dblinter\" target=\"_blank\" rel=\"noreferrer noopener\">dbLinter<\/a> &#8211; which you should &#8211; then you can enable the rule <a href=\"https:\/\/dblinter.app\/ords\/r\/dblinter\/dblinter-console\/rules#P1000_SHOW_RULE=core%20g-3194\" target=\"_blank\" rel=\"noreferrer noopener\">G-3194<\/a> to improve the maintainability of your join-to-one clauses.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Background As you probably know, I&#8217;m maintaining a parser for grammars used in SQL files for Oracle AI Database and PostgreSQL. As a result, I check for new statements and clauses in every version of those DBMSs. PostgreSQL typically adds new features only in major versions; this means yearly. Oracle, on the<span class=\"excerpt-hellip\"> [\u2026]<\/span><\/p>\n","protected":false},"author":1,"featured_media":24027,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[140,85],"class_list":["post-23948","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oracle","tag-oracle-26ai","tag-sql"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.3 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Implicit Outer Joins in Join-to-One: Feature or Flaw? - Philipp Salvisberg&#039;s Blog<\/title>\n<meta name=\"description\" content=\"JOIN TO ONE uses implicit outer joins by default. Is this helpful protection against filtering, or a flaw that makes SQL harder to maintain?\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.salvis.com\/blog\/2026\/08\/29\/implicit-outer-joins-in-join-to-one-feature-or-flaw\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Implicit Outer Joins in Join-to-One: Feature or Flaw? - Philipp Salvisberg&#039;s Blog\" \/>\n<meta property=\"og:description\" content=\"JOIN TO ONE uses implicit outer joins by default. Is this helpful protection against filtering, or a flaw that makes SQL harder to maintain?\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.salvis.com\/blog\/2026\/08\/29\/implicit-outer-joins-in-join-to-one-feature-or-flaw\/\" \/>\n<meta property=\"og:site_name\" content=\"Philipp Salvisberg&#039;s Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-08-29T07:52:40+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-08-29T07:52:43+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/08\/join-to-one-fork-labelled.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1672\" \/>\n\t<meta property=\"og:image:height\" content=\"941\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Philipp Salvisberg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@phsalvisberg\" \/>\n<meta name=\"twitter:site\" content=\"@phsalvisberg\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Philipp Salvisberg\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2026\\\/08\\\/29\\\/implicit-outer-joins-in-join-to-one-feature-or-flaw\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2026\\\/08\\\/29\\\/implicit-outer-joins-in-join-to-one-feature-or-flaw\\\/\"},\"author\":{\"name\":\"Philipp Salvisberg\",\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/#\\\/schema\\\/person\\\/34352245c48678b1a5a05d4bc1339515\"},\"headline\":\"Implicit Outer Joins in Join-to-One: Feature or Flaw?\",\"datePublished\":\"2026-08-29T07:52:40+00:00\",\"dateModified\":\"2026-08-29T07:52:43+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2026\\\/08\\\/29\\\/implicit-outer-joins-in-join-to-one-feature-or-flaw\\\/\"},\"wordCount\":953,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/#\\\/schema\\\/person\\\/34352245c48678b1a5a05d4bc1339515\"},\"image\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2026\\\/08\\\/29\\\/implicit-outer-joins-in-join-to-one-feature-or-flaw\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/08\\\/join-to-one-fork-labelled.png\",\"keywords\":[\"Oracle 26ai\",\"SQL\"],\"articleSection\":[\"Oracle\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2026\\\/08\\\/29\\\/implicit-outer-joins-in-join-to-one-feature-or-flaw\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2026\\\/08\\\/29\\\/implicit-outer-joins-in-join-to-one-feature-or-flaw\\\/\",\"url\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2026\\\/08\\\/29\\\/implicit-outer-joins-in-join-to-one-feature-or-flaw\\\/\",\"name\":\"Implicit Outer Joins in Join-to-One: Feature or Flaw? - Philipp Salvisberg&#039;s Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2026\\\/08\\\/29\\\/implicit-outer-joins-in-join-to-one-feature-or-flaw\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2026\\\/08\\\/29\\\/implicit-outer-joins-in-join-to-one-feature-or-flaw\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/08\\\/join-to-one-fork-labelled.png\",\"datePublished\":\"2026-08-29T07:52:40+00:00\",\"dateModified\":\"2026-08-29T07:52:43+00:00\",\"description\":\"JOIN TO ONE uses implicit outer joins by default. Is this helpful protection against filtering, or a flaw that makes SQL harder to maintain?\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2026\\\/08\\\/29\\\/implicit-outer-joins-in-join-to-one-feature-or-flaw\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2026\\\/08\\\/29\\\/implicit-outer-joins-in-join-to-one-feature-or-flaw\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2026\\\/08\\\/29\\\/implicit-outer-joins-in-join-to-one-feature-or-flaw\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/08\\\/join-to-one-fork-labelled.png\",\"contentUrl\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/08\\\/join-to-one-fork-labelled.png\",\"width\":1672,\"height\":941},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2026\\\/08\\\/29\\\/implicit-outer-joins-in-join-to-one-feature-or-flaw\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Implicit Outer Joins in Join-to-One: Feature or Flaw?\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/\",\"name\":\"Philipp Salvisberg&#039;s Blog\",\"description\":\"Database-centric development\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/#\\\/schema\\\/person\\\/34352245c48678b1a5a05d4bc1339515\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/#\\\/schema\\\/person\\\/34352245c48678b1a5a05d4bc1339515\",\"name\":\"Philipp Salvisberg\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/wp-content\\\/uploads\\\/2010\\\/11\\\/phs_trivadis4.jpg\",\"url\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/wp-content\\\/uploads\\\/2010\\\/11\\\/phs_trivadis4.jpg\",\"contentUrl\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/wp-content\\\/uploads\\\/2010\\\/11\\\/phs_trivadis4.jpg\",\"width\":400,\"height\":400,\"caption\":\"Philipp Salvisberg\"},\"logo\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/wp-content\\\/uploads\\\/2010\\\/11\\\/phs_trivadis4.jpg\"},\"sameAs\":[\"http:\\\/\\\/www.salvis.com\\\/\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Implicit Outer Joins in Join-to-One: Feature or Flaw? - Philipp Salvisberg&#039;s Blog","description":"JOIN TO ONE uses implicit outer joins by default. Is this helpful protection against filtering, or a flaw that makes SQL harder to maintain?","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.salvis.com\/blog\/2026\/08\/29\/implicit-outer-joins-in-join-to-one-feature-or-flaw\/","og_locale":"en_US","og_type":"article","og_title":"Implicit Outer Joins in Join-to-One: Feature or Flaw? - Philipp Salvisberg&#039;s Blog","og_description":"JOIN TO ONE uses implicit outer joins by default. Is this helpful protection against filtering, or a flaw that makes SQL harder to maintain?","og_url":"https:\/\/www.salvis.com\/blog\/2026\/08\/29\/implicit-outer-joins-in-join-to-one-feature-or-flaw\/","og_site_name":"Philipp Salvisberg&#039;s Blog","article_published_time":"2026-08-29T07:52:40+00:00","article_modified_time":"2026-08-29T07:52:43+00:00","og_image":[{"width":1672,"height":941,"url":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/08\/join-to-one-fork-labelled.png","type":"image\/png"}],"author":"Philipp Salvisberg","twitter_card":"summary_large_image","twitter_creator":"@phsalvisberg","twitter_site":"@phsalvisberg","twitter_misc":{"Written by":"Philipp Salvisberg","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.salvis.com\/blog\/2026\/08\/29\/implicit-outer-joins-in-join-to-one-feature-or-flaw\/#article","isPartOf":{"@id":"https:\/\/www.salvis.com\/blog\/2026\/08\/29\/implicit-outer-joins-in-join-to-one-feature-or-flaw\/"},"author":{"name":"Philipp Salvisberg","@id":"https:\/\/www.salvis.com\/blog\/#\/schema\/person\/34352245c48678b1a5a05d4bc1339515"},"headline":"Implicit Outer Joins in Join-to-One: Feature or Flaw?","datePublished":"2026-08-29T07:52:40+00:00","dateModified":"2026-08-29T07:52:43+00:00","mainEntityOfPage":{"@id":"https:\/\/www.salvis.com\/blog\/2026\/08\/29\/implicit-outer-joins-in-join-to-one-feature-or-flaw\/"},"wordCount":953,"commentCount":0,"publisher":{"@id":"https:\/\/www.salvis.com\/blog\/#\/schema\/person\/34352245c48678b1a5a05d4bc1339515"},"image":{"@id":"https:\/\/www.salvis.com\/blog\/2026\/08\/29\/implicit-outer-joins-in-join-to-one-feature-or-flaw\/#primaryimage"},"thumbnailUrl":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/08\/join-to-one-fork-labelled.png","keywords":["Oracle 26ai","SQL"],"articleSection":["Oracle"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.salvis.com\/blog\/2026\/08\/29\/implicit-outer-joins-in-join-to-one-feature-or-flaw\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.salvis.com\/blog\/2026\/08\/29\/implicit-outer-joins-in-join-to-one-feature-or-flaw\/","url":"https:\/\/www.salvis.com\/blog\/2026\/08\/29\/implicit-outer-joins-in-join-to-one-feature-or-flaw\/","name":"Implicit Outer Joins in Join-to-One: Feature or Flaw? - Philipp Salvisberg&#039;s Blog","isPartOf":{"@id":"https:\/\/www.salvis.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.salvis.com\/blog\/2026\/08\/29\/implicit-outer-joins-in-join-to-one-feature-or-flaw\/#primaryimage"},"image":{"@id":"https:\/\/www.salvis.com\/blog\/2026\/08\/29\/implicit-outer-joins-in-join-to-one-feature-or-flaw\/#primaryimage"},"thumbnailUrl":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/08\/join-to-one-fork-labelled.png","datePublished":"2026-08-29T07:52:40+00:00","dateModified":"2026-08-29T07:52:43+00:00","description":"JOIN TO ONE uses implicit outer joins by default. Is this helpful protection against filtering, or a flaw that makes SQL harder to maintain?","breadcrumb":{"@id":"https:\/\/www.salvis.com\/blog\/2026\/08\/29\/implicit-outer-joins-in-join-to-one-feature-or-flaw\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.salvis.com\/blog\/2026\/08\/29\/implicit-outer-joins-in-join-to-one-feature-or-flaw\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.salvis.com\/blog\/2026\/08\/29\/implicit-outer-joins-in-join-to-one-feature-or-flaw\/#primaryimage","url":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/08\/join-to-one-fork-labelled.png","contentUrl":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/08\/join-to-one-fork-labelled.png","width":1672,"height":941},{"@type":"BreadcrumbList","@id":"https:\/\/www.salvis.com\/blog\/2026\/08\/29\/implicit-outer-joins-in-join-to-one-feature-or-flaw\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.salvis.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Implicit Outer Joins in Join-to-One: Feature or Flaw?"}]},{"@type":"WebSite","@id":"https:\/\/www.salvis.com\/blog\/#website","url":"https:\/\/www.salvis.com\/blog\/","name":"Philipp Salvisberg&#039;s Blog","description":"Database-centric development","publisher":{"@id":"https:\/\/www.salvis.com\/blog\/#\/schema\/person\/34352245c48678b1a5a05d4bc1339515"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.salvis.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.salvis.com\/blog\/#\/schema\/person\/34352245c48678b1a5a05d4bc1339515","name":"Philipp Salvisberg","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2010\/11\/phs_trivadis4.jpg","url":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2010\/11\/phs_trivadis4.jpg","contentUrl":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2010\/11\/phs_trivadis4.jpg","width":400,"height":400,"caption":"Philipp Salvisberg"},"logo":{"@id":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2010\/11\/phs_trivadis4.jpg"},"sameAs":["http:\/\/www.salvis.com\/"]}]}},"_links":{"self":[{"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/posts\/23948","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/comments?post=23948"}],"version-history":[{"count":27,"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/posts\/23948\/revisions"}],"predecessor-version":[{"id":24029,"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/posts\/23948\/revisions\/24029"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/media\/24027"}],"wp:attachment":[{"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/media?parent=23948"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/categories?post=23948"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/tags?post=23948"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}