{"id":14289,"date":"2026-01-02T22:05:10","date_gmt":"2026-01-02T21:05:10","guid":{"rendered":"https:\/\/www.salvis.com\/blog\/?p=14289"},"modified":"2026-02-18T09:23:36","modified_gmt":"2026-02-18T08:23:36","slug":"fighting-bad-pl-sql-sql-with-vs-code","status":"publish","type":"post","link":"https:\/\/www.salvis.com\/blog\/2026\/01\/02\/fighting-bad-pl-sql-sql-with-vs-code\/","title":{"rendered":"Fighting Bad PL\/SQL &amp; SQL with VS Code"},"content":{"rendered":"\n<p>The success of a project or product depends largely on the quality of the code. But how can I improve security, maintainability or performance? More importantly, how can I prevent code with quality defects from entering production? In addition to testing, code analysis plays a central role. These days, code can be checked not only in CI\/CD pipelines, but also during development. Modern IDEs, such as Visual Studio Code, can automatically detect quality issues and offer quick fixes. The goal is a fast feedback loop.<\/p>\n\n\n\n<p>This blog post is based on my German article with the same title, published in issue 1\/2026 of the\u00a0<a href=\"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/02\/01_2026-Red_Stack_Magazin-DTk-WEB-Philipp_Salvisberg_Fighting_Bad_PLSQL__SQL_with_VS_Code.pdf\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">Red Stack Magazin<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"measuring-software-quality\">Measuring Software Quality<\/h2>\n\n\n\n<p>Imagine you are part of a team where code changes to a feature or bug fix branch are only merged into the develop or main branch following a review. Sometimes you are the author and sometimes one of the reviewers. I am currently part of a team that works in this way. In addition to quality assurance, knowledge sharing is also an important aspect. But how can we assess code quality?<\/p>\n\n\n\n<figure class=\"wp-block-image is-style-default\"><a href=\"https:\/\/www.osnews.com\/story\/19266\/wtfsm\/\" target=\"_blank\" rel=\" noreferrer noopener\"><img loading=\"lazy\" decoding=\"async\" width=\"500\" height=\"471\" src=\"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-1-wtfm.jpg\" alt=\"\" class=\"wp-image-14292\" srcset=\"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-1-wtfm.jpg 500w, https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-1-wtfm-300x283.jpg 300w, https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-1-wtfm-80x75.jpg 80w, https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-1-wtfm-480x452.jpg 480w\" sizes=\"auto, (max-width:767px) 480px, 500px\" \/><\/a><figcaption class=\"wp-element-caption\">Figure 1: WTFs\/m<\/figcaption><\/figure>\n\n\n\n<p>This well-known meme by Thom Holwerda says, &#8220;The only valid measurement of code quality is WTFs per minute.&#8221; This seems to be a good metric. However, this metric does have some flaws.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>It is subjective.<\/li>\n\n\n\n<li>It does not provide any information about what is being assessed.<\/li>\n\n\n\n<li>It does not help new team members to adapt quickly.<\/li>\n\n\n\n<li>And it cannot be automated in a meaningful way.<\/li>\n<\/ul>\n\n\n\n<p>Sooner or later, a team has no choice but to agree on a set of rules. They can be informal or formal. Typical coding guidelines cover topics such as naming conventions, formatting, code complexity, and language usage rules. The aim is to define and comply with quality standards relating to maintainability, reliability, performance and security. Written coding guidelines also simplify the onboarding of new team members.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"automation\">Automation<\/h2>\n\n\n\n<p>Manually checking compliance with coding guidelines as part of a review is so time-consuming that no one can afford to do it properly. Therefore, we have to automate as many checks as possible. This is possible for many aspects. The rest still have to be checked manually.<\/p>\n\n\n\n<p>In other words, we need a tool suite for automatic rule checking. <a href=\"https:\/\/grisselbav.github.io\/dbLinter\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">dbLinter<\/a> is such a tool suite. It is a new product developed and continuously improved by <a href=\"https:\/\/www.grisselbav.com\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">Grisselbav<\/a> and <a href=\"https:\/\/www.united-codes.com\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">United Codes<\/a>. dbLinter uses the <a href=\"https:\/\/github.com\/IslandSQL\/IslandSQL\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">IslandSQL<\/a> parser, which is updated quarterly with every release update of the Oracle AI Database for SQL, PL\/SQL, SQL*Plus and SQLcl.<\/p>\n\n\n\n<p>dbLinter is the successor to the decommissioned db* CODECOP suite. dbLinter consists of a central repository, a web GUI and client tools. These include a CLI, a SonarQube plugin and a VS Code extension.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"visual-studio-code-extension\">Visual Studio Code Extension<\/h2>\n\n\n\n<p>The VS Code extension is compatible with all IDEs that implement the <a href=\"https:\/\/code.visualstudio.com\/api\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">Visual Studio Code Extension API<\/a>. Specifically: Visual Studio Code, Theia IDE, VSCodium, Cursor, Windsurf, Void, Kiro and Antigravity.<\/p>\n\n\n\n<p>dbLinter for VS Code is available in both the <a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=Grisselbav.dblinter\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">Visual Studio Marketplace<\/a> and the <a href=\"https:\/\/open-vsx.org\/extension\/Grisselbav\/dblinter\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">Open VSX Registry<\/a>. Therefore, it can be conveniently installed directly from the IDE. The extension is free to use as part of the Anonymous and Starter plans (see <a href=\"https:\/\/www.united-codes.com\/products\/dblinter\/#pricing\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">dbLinter Pricing Plans<\/a>).<\/p>\n\n\n\n<p>It is important to note that your code is always analysed locally, meaning that it never leaves your network. The configuration is read from the central repository, enabling the client to identify the active rules and parameters. These configurations, along with others, are managed using the <a href=\"https:\/\/dblinter.app\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">Web GUI<\/a>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-2-dblinter-regel-konfiguration-im-web-gui.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1228\" height=\"1088\" src=\"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-2-dblinter-regel-konfiguration-im-web-gui.png\" alt=\"\" class=\"wp-image-14313\" srcset=\"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-2-dblinter-regel-konfiguration-im-web-gui.png 1228w, https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-2-dblinter-regel-konfiguration-im-web-gui-300x266.png 300w, https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-2-dblinter-regel-konfiguration-im-web-gui-1024x907.png 1024w, https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-2-dblinter-regel-konfiguration-im-web-gui-768x680.png 768w, https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-2-dblinter-regel-konfiguration-im-web-gui-85x75.png 85w, https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-2-dblinter-regel-konfiguration-im-web-gui-480x425.png 480w\" sizes=\"auto, (max-width:767px) 480px, (max-width:1228px) 100vw, 1228px\" \/><\/a><figcaption class=\"wp-element-caption\">Figure 2: dbLinter rule configuration in the Web GUI<\/figcaption><\/figure>\n\n\n\n<p>dbLinter currently offers 187 rules. This includes all the rules from the decommissioned Trivadis PL\/SQL &amp; SQL Coding Guidelines. Figure 2 shows the configuration of my 14 favourite rules. A violation of one of these rules is a bug. There is almost no room for interpretation here. The following chapters provide two examples.<\/p>\n\n\n\n<h2 class=\"wp-block-heading top-n-queries-with-rownum\">Top-N Queries with ROWNUM<\/h2>\n\n\n\n<p>The query in Listing 1 is based on the well-known <code>EMP<\/code> table owned by the database user <code>SCOTT<\/code>. It returns two rows.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" 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-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);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\">Listing 1: Defective pre-12c-style top-n query<\/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 ename,\n       sal,\n       hiredate,\n       rownum as rank\n  from emp\n where rownum &lt;= 2\n order by sal desc;<\/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\"> ename,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">       sal,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">       hiredate,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">       <\/span><span style=\"color: #569CD6\">rownum<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">as<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">rank<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #569CD6\">from<\/span><span style=\"color: #D4D4D4\"> emp<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">where<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">rownum<\/span><span style=\"color: #D4D4D4\"> &lt;= <\/span><span style=\"color: #B5CEA8\">2<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">order by<\/span><span style=\"color: #D4D4D4\"> sal <\/span><span style=\"color: #569CD6\">desc<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\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-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><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>ENAME             SAL HIREDATE         RANK\n---------- ---------- ---------- ----------\nALLEN            1600 20.02.1981          2\nSMITH             800 17.12.1980          1<\/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: #D4D4D4\">ENAME             SAL HIREDATE         RANK<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">---------- ---------- ---------- ----------<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">ALLEN            1600 20.02.1981          2<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">SMITH             800 17.12.1980          1<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>However, the result barely meets the requirements. I would have expected the two employees with the highest salaries to be returned. Why is this not the case? The query is formulated in such a way that two rows are randomly selected and then sorted in descending order by salary. The result depends on the execution plan and the physical storage of the data.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-3-g-3185-regelverletzung-in-vs-code.png\"><img loading=\"lazy\" decoding=\"async\" width=\"913\" height=\"448\" src=\"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-3-g-3185-regelverletzung-in-vs-code.png\" alt=\"\" class=\"wp-image-14323\" srcset=\"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-3-g-3185-regelverletzung-in-vs-code.png 913w, https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-3-g-3185-regelverletzung-in-vs-code-300x147.png 300w, https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-3-g-3185-regelverletzung-in-vs-code-768x377.png 768w, https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-3-g-3185-regelverletzung-in-vs-code-150x75.png 150w, https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-3-g-3185-regelverletzung-in-vs-code-480x236.png 480w\" sizes=\"auto, (max-width:767px) 480px, (max-width:913px) 100vw, 913px\" \/><\/a><figcaption class=\"wp-element-caption\">Figure 3: Violation of rule G-3185 in VS Code<\/figcaption><\/figure>\n\n\n\n<p>In VS Code, rule violations are displayed under <code>Problems<\/code> (see Figure 3). There is also a <a href=\"https:\/\/dblinter.app\/ords\/r\/dblinter\/dblinter-console\/rules#P1000_SHOW_RULE=core%20g-3185\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">Core G-3185<\/a> link that opens the rule details in the Web GUI.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-4-g-3185-im-dblinter-web-gui-2.png\"><img loading=\"lazy\" decoding=\"async\" width=\"982\" height=\"1490\" src=\"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-4-g-3185-im-dblinter-web-gui-2.png\" alt=\"\" class=\"wp-image-14330\" srcset=\"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-4-g-3185-im-dblinter-web-gui-2.png 982w, https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-4-g-3185-im-dblinter-web-gui-2-198x300.png 198w, https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-4-g-3185-im-dblinter-web-gui-2-675x1024.png 675w, https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-4-g-3185-im-dblinter-web-gui-2-768x1165.png 768w, https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-4-g-3185-im-dblinter-web-gui-2-49x75.png 49w, https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-4-g-3185-im-dblinter-web-gui-2-480x728.png 480w\" sizes=\"auto, (max-width:767px) 480px, (max-width:982px) 100vw, 982px\" \/><\/a><figcaption class=\"wp-element-caption\">Figure 4: Rule G-3185 in the dbLinter Web GUI<\/figcaption><\/figure>\n\n\n\n<p>Rule G-3185 in the web GUI is explained based on a similar case in the HR schema (see Figure 4). There are two solutions here. One that can be applied in all Oracle Database versions and one that works from version 12c onwards. Listing 2 shows the traditional solution, which uses an inline view. Of course, nowadays I would always prefer a solution using the <a href=\"https:\/\/docs.oracle.com\/en\/database\/oracle\/oracle-database\/26\/sqlrf\/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6__BABBADDD\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">row_limiting_clause<\/a>.<\/p>\n\n\n\n<p>We can also see that the rule is used in six configurations. Clicking on &#8220;(details)&#8221; opens a pop-up window in which changes can be made. This allows you to configure the rules directly from the IDE.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" 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-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);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\">Listing 2: Fixed pre-12c-style top-n query<\/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 e.*,\n       rownum as rank\n  from (\n          select ename,\n                 sal,\n                 hiredate\n            from emp\n           order by sal desc\n       ) e\n where rownum &lt;= 2;<\/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\"> e.*,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">       <\/span><span style=\"color: #569CD6\">rownum<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">as<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">rank<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #569CD6\">from<\/span><span style=\"color: #D4D4D4\"> (<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">          <\/span><span style=\"color: #569CD6\">select<\/span><span style=\"color: #D4D4D4\"> ename,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                 sal,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                 hiredate<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #569CD6\">from<\/span><span style=\"color: #D4D4D4\"> emp<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">           <\/span><span style=\"color: #569CD6\">order by<\/span><span style=\"color: #D4D4D4\"> sal <\/span><span style=\"color: #569CD6\">desc<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">       ) e<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">where<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">rownum<\/span><span style=\"color: #D4D4D4\"> &lt;= <\/span><span style=\"color: #B5CEA8\">2<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\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-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><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>ENAME             SAL HIREDATE         RANK\n---------- ---------- ---------- ----------\nKING             5000 17.11.1981          1\nSCOTT            3000 19.04.1987          2<\/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: #D4D4D4\">ENAME             SAL HIREDATE         RANK<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">---------- ---------- ---------- ----------<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">KING             5000 17.11.1981          1<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">SCOTT            3000 19.04.1987          2<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading nvl-vs-coalesce\">NVL vs. COALESCE<\/h2>\n\n\n\n<p>One often underestimated rule is &#8220;<a href=\"https:\/\/dblinter.app\/ords\/r\/dblinter\/dblinter-console\/rules#P1000_SHOW_RULE=core%20g-4230\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">G-4230<\/a>: Always use a COALESCE instead of a NVL command, if parameter 2 of the NVL function is a function call or a SELECT statement&#8221;. This rule is about performance, which is relevant to all of us, especially when it is poor. This is why this rule is important.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" 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-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);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\">Listing 3: Bad performance with NVL<\/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>with\n   function slow_function return integer is\n   begin\n      sys.dbms_session.sleep(0.2);\n      return null;\n   end slow_function;\nselect ename, nvl(mgr, slow_function()) as mgr\n  from emp;<\/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\">with<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">   <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">slow_function<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #C586C0\">return<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">integer<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">is<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">   <\/span><span style=\"color: #569CD6\">begin<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      sys.<\/span><span style=\"color: #DCDCAA\">dbms_session.<\/span><span style=\"color: #4EC9B0\">sleep<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #B5CEA8\">0.2<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #C586C0\">return<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">null<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">   <\/span><span style=\"color: #569CD6\">end<\/span><span style=\"color: #D4D4D4\"> slow_function;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">select<\/span><span style=\"color: #D4D4D4\"> ename, <\/span><span style=\"color: #DCDCAA\">nvl<\/span><span style=\"color: #D4D4D4\">(mgr, slow_function()) <\/span><span style=\"color: #569CD6\">as<\/span><span style=\"color: #D4D4D4\"> mgr<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #569CD6\">from<\/span><span style=\"color: #D4D4D4\"> emp;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Listing 3 demonstrates a case in which the use of <code>NVL<\/code> results in an execution time of approximately 2.8 seconds. If <code>COALESCE<\/code> is used instead of <code>NVL<\/code>, the execution time is only about 0.2 seconds. The reason is that <code>NVL<\/code> always evaluates the second parameter, even if the first parameter is not null. <code>COALESCE<\/code> works differently: the second parameter is only evaluated if the first parameter is null. This performance difference originates from the fact that the <code>EMP<\/code> table contains 14 rows, but only one of these returns an empty <code>MGR<\/code>.<\/p>\n\n\n\n<p>In this case, using <code>COALESCE<\/code> is definitely the better solution. So, should <code>NVL<\/code> always be replaced by <code>COALESCE<\/code>? No. There are two special cases:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>NVL supports implicit data type conversion.<br \/><code>select nvl(mgr, '1') from emp<\/code> works, but <code>select coalesce(mgr, '1') from emp<\/code> causes an <a href=\"https:\/\/docs.oracle.com\/en\/error-help\/db\/ora-00932\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">ORA-00932<\/a> error. However, implicit type conversions should be avoided anyway. The code should be adjusted accordingly.<br \/><\/li>\n\n\n\n<li>Optimisations of <code>NVL<\/code> can lead to better execution plans.<br \/>Such optimisations currently only exist for <code>NVL<\/code> and not for <code>COALESCE<\/code>. Therefore, it is better to continue using <code>NVL<\/code> in these cases. See <a href=\"https:\/\/how2ora-en.blogspot.com\/2025\/09\/the-magical-nvl-function.html\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">The Magical NVL Function<\/a> by Monika Lewandowska for an example. <\/li>\n<\/ol>\n\n\n\n<h5 class=\"wp-block-heading\">Quick Fixes<\/h5>\n\n\n\n<p>dbLinter knows these special cases. It offers appropriate alternative solutions. See Figure 5.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-5-g-4230-quick-fixes-in-vscode.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1121\" height=\"717\" src=\"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-5-g-4230-quick-fixes-in-vscode.png\" alt=\"\" class=\"wp-image-14346\" srcset=\"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-5-g-4230-quick-fixes-in-vscode.png 1121w, https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-5-g-4230-quick-fixes-in-vscode-300x192.png 300w, https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-5-g-4230-quick-fixes-in-vscode-1024x655.png 1024w, https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-5-g-4230-quick-fixes-in-vscode-768x491.png 768w, https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-5-g-4230-quick-fixes-in-vscode-117x75.png 117w, https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/abbildung-5-g-4230-quick-fixes-in-vscode-480x307.png 480w\" sizes=\"auto, (max-width:767px) 480px, (max-width:1121px) 100vw, 1121px\" \/><\/a><figcaption class=\"wp-element-caption\">Figure 5: Quick fixes for G-4230 violation in VS Code.<\/figcaption><\/figure>\n\n\n\n<p>dbLinter can apply quick fixes to different sections. For example, for a single violation of a rule, for all violations of a rule, or for all violations of all rules in the editor window.<\/p>\n\n\n\n<p>The &#8220;@dbLinter ignore markers&#8221; are special comments used to ignore rule violations. There are various legitimate reasons for doing this. For example, in the case of false positives (dbLinter bugs) or exceptions to the rule. A comment such as <code>-- @dbLinter ignore(G-4230): NVL forever<\/code> can have the following scopes: line, statement or file, depending on where the comment is positioned.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"code-analysis-and-ai\">Code Analysis and AI<\/h2>\n\n\n\n<p>The solution proposals in Figure 5, indicated by the yellow lamp symbol, are quick fixes from dbLinter. However, the last two menu options come from GitHub Copilot.<\/p>\n\n\n\n<p>When Copilot suggests a solution to a rule violation, dbLinter provides the necessary context, including the file and the exact location of the violation, as well as the name of the violated rule. This gives Copilot access to the rule definition online, enabling it to suggest a reasonable solution in many cases. In other words, dbLinter enhances the support offered by tools such as Copilot, Cline and Windsurf.<\/p>\n\n\n\n<p>Rules are useful for AI tools. They provide a framework that leads to better results. However, there is no guarantee that all rules will be followed. Ultimately, code generated or expanded by AI becomes part of our code base. This is why it is important to check AI-generated code according to the same rules as manually created code.<\/p>\n\n\n\n<p>In other words, AI does not enforce standards. But dbLinter can do that.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"conclusion\">Conclusion<\/h2>\n\n\n\n<p>Software quality is a matter of definition. dbLinter offers many rules. Not all of them are useful and applicable to every project. The dbLinter rules can therefore be seen as a large buffet. You choose what you like and what is healthy. But not too much at once. Nevertheless, there are some rules that, in my opinion, should be followed in every project. I have presented two of them in this blog post.<\/p>\n\n\n\n<p>Install dbLinter for VS Code to identify the rules that will be most helpful for your projects. The rules in Figure 2 are certainly a good starting point.<\/p>\n\n\n\n<p>If you have any questions, please feel free to contact me. Alternatively, you can create issues directly in the <a href=\"https:\/\/github.com\/Grisselbav\/dbLinter\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">dbLinter GitHub repository<\/a>.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The success of a project or product depends largely on the quality of the code. But how can I improve security, maintainability or performance? More importantly, how can I prevent code with quality defects from entering production? In addition to testing, code analysis plays a central role. These days, code can be<span class=\"excerpt-hellip\"> [\u2026]<\/span><\/p>\n","protected":false},"author":1,"featured_media":14362,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[86,151,13,85,138],"class_list":["post-14289","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oracle","tag-code-analysis","tag-dblinter","tag-plsql","tag-sql","tag-vscode"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.3 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Fighting Bad PL\/SQL &amp; SQL with VS Code - Philipp Salvisberg&#039;s Blog<\/title>\n<meta name=\"description\" content=\"Modern IDEs can automatically detect quality issues and offer quick fixes. The aim is to minimise the feedback loop.\" \/>\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\/01\/02\/fighting-bad-pl-sql-sql-with-vs-code\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Fighting Bad PL\/SQL &amp; SQL with VS Code - Philipp Salvisberg&#039;s Blog\" \/>\n<meta property=\"og:description\" content=\"Modern IDEs can automatically detect quality issues and offer quick fixes. The aim is to minimise the feedback loop.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.salvis.com\/blog\/2026\/01\/02\/fighting-bad-pl-sql-sql-with-vs-code\/\" \/>\n<meta property=\"og:site_name\" content=\"Philipp Salvisberg&#039;s Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-01-02T21:05:10+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-02-18T08:23:36+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/fighting-bad-plsql-and-sql-with-vscode-knight-1024x683.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1024\" \/>\n\t<meta property=\"og:image:height\" content=\"683\" \/>\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=\"8 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\\\/01\\\/02\\\/fighting-bad-pl-sql-sql-with-vs-code\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2026\\\/01\\\/02\\\/fighting-bad-pl-sql-sql-with-vs-code\\\/\"},\"author\":{\"name\":\"Philipp Salvisberg\",\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/#\\\/schema\\\/person\\\/34352245c48678b1a5a05d4bc1339515\"},\"headline\":\"Fighting Bad PL\\\/SQL &amp; SQL with VS Code\",\"datePublished\":\"2026-01-02T21:05:10+00:00\",\"dateModified\":\"2026-02-18T08:23:36+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2026\\\/01\\\/02\\\/fighting-bad-pl-sql-sql-with-vs-code\\\/\"},\"wordCount\":1522,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/#\\\/schema\\\/person\\\/34352245c48678b1a5a05d4bc1339515\"},\"image\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2026\\\/01\\\/02\\\/fighting-bad-pl-sql-sql-with-vs-code\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/01\\\/fighting-bad-plsql-and-sql-with-vscode-knight.png\",\"keywords\":[\"Code Analysis\",\"dbLinter\",\"PL\\\/SQL\",\"SQL\",\"VSCode\"],\"articleSection\":[\"Oracle\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2026\\\/01\\\/02\\\/fighting-bad-pl-sql-sql-with-vs-code\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2026\\\/01\\\/02\\\/fighting-bad-pl-sql-sql-with-vs-code\\\/\",\"url\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2026\\\/01\\\/02\\\/fighting-bad-pl-sql-sql-with-vs-code\\\/\",\"name\":\"Fighting Bad PL\\\/SQL &amp; SQL with VS Code - Philipp Salvisberg&#039;s Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2026\\\/01\\\/02\\\/fighting-bad-pl-sql-sql-with-vs-code\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2026\\\/01\\\/02\\\/fighting-bad-pl-sql-sql-with-vs-code\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/01\\\/fighting-bad-plsql-and-sql-with-vscode-knight.png\",\"datePublished\":\"2026-01-02T21:05:10+00:00\",\"dateModified\":\"2026-02-18T08:23:36+00:00\",\"description\":\"Modern IDEs can automatically detect quality issues and offer quick fixes. The aim is to minimise the feedback loop.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2026\\\/01\\\/02\\\/fighting-bad-pl-sql-sql-with-vs-code\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2026\\\/01\\\/02\\\/fighting-bad-pl-sql-sql-with-vs-code\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2026\\\/01\\\/02\\\/fighting-bad-pl-sql-sql-with-vs-code\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/01\\\/fighting-bad-plsql-and-sql-with-vscode-knight.png\",\"contentUrl\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/01\\\/fighting-bad-plsql-and-sql-with-vscode-knight.png\",\"width\":1536,\"height\":1024},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/2026\\\/01\\\/02\\\/fighting-bad-pl-sql-sql-with-vs-code\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.salvis.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Fighting Bad PL\\\/SQL &amp; SQL with VS Code\"}]},{\"@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":"Fighting Bad PL\/SQL &amp; SQL with VS Code - Philipp Salvisberg&#039;s Blog","description":"Modern IDEs can automatically detect quality issues and offer quick fixes. The aim is to minimise the feedback loop.","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\/01\/02\/fighting-bad-pl-sql-sql-with-vs-code\/","og_locale":"en_US","og_type":"article","og_title":"Fighting Bad PL\/SQL &amp; SQL with VS Code - Philipp Salvisberg&#039;s Blog","og_description":"Modern IDEs can automatically detect quality issues and offer quick fixes. The aim is to minimise the feedback loop.","og_url":"https:\/\/www.salvis.com\/blog\/2026\/01\/02\/fighting-bad-pl-sql-sql-with-vs-code\/","og_site_name":"Philipp Salvisberg&#039;s Blog","article_published_time":"2026-01-02T21:05:10+00:00","article_modified_time":"2026-02-18T08:23:36+00:00","og_image":[{"width":1024,"height":683,"url":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/fighting-bad-plsql-and-sql-with-vscode-knight-1024x683.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":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.salvis.com\/blog\/2026\/01\/02\/fighting-bad-pl-sql-sql-with-vs-code\/#article","isPartOf":{"@id":"https:\/\/www.salvis.com\/blog\/2026\/01\/02\/fighting-bad-pl-sql-sql-with-vs-code\/"},"author":{"name":"Philipp Salvisberg","@id":"https:\/\/www.salvis.com\/blog\/#\/schema\/person\/34352245c48678b1a5a05d4bc1339515"},"headline":"Fighting Bad PL\/SQL &amp; SQL with VS Code","datePublished":"2026-01-02T21:05:10+00:00","dateModified":"2026-02-18T08:23:36+00:00","mainEntityOfPage":{"@id":"https:\/\/www.salvis.com\/blog\/2026\/01\/02\/fighting-bad-pl-sql-sql-with-vs-code\/"},"wordCount":1522,"commentCount":0,"publisher":{"@id":"https:\/\/www.salvis.com\/blog\/#\/schema\/person\/34352245c48678b1a5a05d4bc1339515"},"image":{"@id":"https:\/\/www.salvis.com\/blog\/2026\/01\/02\/fighting-bad-pl-sql-sql-with-vs-code\/#primaryimage"},"thumbnailUrl":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/fighting-bad-plsql-and-sql-with-vscode-knight.png","keywords":["Code Analysis","dbLinter","PL\/SQL","SQL","VSCode"],"articleSection":["Oracle"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.salvis.com\/blog\/2026\/01\/02\/fighting-bad-pl-sql-sql-with-vs-code\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.salvis.com\/blog\/2026\/01\/02\/fighting-bad-pl-sql-sql-with-vs-code\/","url":"https:\/\/www.salvis.com\/blog\/2026\/01\/02\/fighting-bad-pl-sql-sql-with-vs-code\/","name":"Fighting Bad PL\/SQL &amp; SQL with VS Code - Philipp Salvisberg&#039;s Blog","isPartOf":{"@id":"https:\/\/www.salvis.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.salvis.com\/blog\/2026\/01\/02\/fighting-bad-pl-sql-sql-with-vs-code\/#primaryimage"},"image":{"@id":"https:\/\/www.salvis.com\/blog\/2026\/01\/02\/fighting-bad-pl-sql-sql-with-vs-code\/#primaryimage"},"thumbnailUrl":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/fighting-bad-plsql-and-sql-with-vscode-knight.png","datePublished":"2026-01-02T21:05:10+00:00","dateModified":"2026-02-18T08:23:36+00:00","description":"Modern IDEs can automatically detect quality issues and offer quick fixes. The aim is to minimise the feedback loop.","breadcrumb":{"@id":"https:\/\/www.salvis.com\/blog\/2026\/01\/02\/fighting-bad-pl-sql-sql-with-vs-code\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.salvis.com\/blog\/2026\/01\/02\/fighting-bad-pl-sql-sql-with-vs-code\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.salvis.com\/blog\/2026\/01\/02\/fighting-bad-pl-sql-sql-with-vs-code\/#primaryimage","url":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/fighting-bad-plsql-and-sql-with-vscode-knight.png","contentUrl":"https:\/\/www.salvis.com\/blog\/wp-content\/uploads\/2026\/01\/fighting-bad-plsql-and-sql-with-vscode-knight.png","width":1536,"height":1024},{"@type":"BreadcrumbList","@id":"https:\/\/www.salvis.com\/blog\/2026\/01\/02\/fighting-bad-pl-sql-sql-with-vs-code\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.salvis.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Fighting Bad PL\/SQL &amp; SQL with VS Code"}]},{"@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\/14289","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=14289"}],"version-history":[{"count":67,"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/posts\/14289\/revisions"}],"predecessor-version":[{"id":15843,"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/posts\/14289\/revisions\/15843"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/media\/14362"}],"wp:attachment":[{"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/media?parent=14289"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/categories?post=14289"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.salvis.com\/blog\/wp-json\/wp\/v2\/tags?post=14289"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}