<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: SANDEEP KUMAR</title>
    <description>The latest articles on DEV Community by SANDEEP KUMAR (@sandeep-oracle).</description>
    <link>https://dev.to/sandeep-oracle</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4129746%2F638a068e-cb86-422d-aa19-06b8d225b6d0.jpg</url>
      <title>DEV Community: SANDEEP KUMAR</title>
      <link>https://dev.to/sandeep-oracle</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sandeep-oracle"/>
    <language>en</language>
    <item>
      <title>Oracle SQL: Pseudo-Columns</title>
      <dc:creator>SANDEEP KUMAR</dc:creator>
      <pubDate>Wed, 23 Sep 2026 03:03:55 +0000</pubDate>
      <link>https://dev.to/sandeep-oracle/oracle-sql-pseudo-columns-381o</link>
      <guid>https://dev.to/sandeep-oracle/oracle-sql-pseudo-columns-381o</guid>
      <description>&lt;h2&gt;
  
  
  1. Overview &amp;amp; Core Concepts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Definition:&lt;/strong&gt; A pseudo-column behaves like a table column, but it is &lt;strong&gt;not actually stored on disk&lt;/strong&gt; in the table.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Capabilities &amp;amp; Restrictions:&lt;/strong&gt; You can &lt;code&gt;SELECT&lt;/code&gt; from pseudo-columns, but you &lt;strong&gt;cannot&lt;/strong&gt; perform &lt;code&gt;INSERT&lt;/code&gt;, &lt;code&gt;UPDATE&lt;/code&gt;, or &lt;code&gt;DELETE&lt;/code&gt; operations on their values.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Common Oracle Pseudo-Columns
&lt;/h3&gt;

&lt;p&gt;Oracle provides several built-in pseudo-columns for administrative, navigational, and sequence-based queries:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ROWID&lt;/code&gt;&lt;/strong&gt;: Returns the unique physical address of a row within a database table.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ROWNUM&lt;/code&gt;&lt;/strong&gt;: Assigns a sequential integer (starting from 1) to each row returned by a query result set.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;NEXTVAL&lt;/code&gt;&lt;/strong&gt;: Retrieves the next available value from a sequence object.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;CURRVAL&lt;/code&gt;&lt;/strong&gt;: Retrieves the current value of a sequence in the current session.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;COLUMN_VALUE&lt;/code&gt;&lt;/strong&gt;: Used primarily when querying collection types or table functions like &lt;code&gt;XMLTABLE&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;*Example:*SQL&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT column_value
FROM (XMLTABLE('&amp;lt;a&amp;gt;123&amp;lt;/a&amp;gt;'));
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;ORA_ROWSCN&lt;/code&gt;&lt;/strong&gt;: Returns the conservative upper bound System Change Number (SCN) of the most recent change made to the row. Useful for tracking data staleness or building flashback implementations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;UID&lt;/code&gt; &amp;amp; &lt;code&gt;USER&lt;/code&gt;&lt;/strong&gt;: Returns the unique integer user ID and the username of the current user session.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;*Example Output from Dual Table:*SQL&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT uid, user FROM dual;
&lt;/code&gt;&lt;/pre&gt;


&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;UID&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;USER&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;102&lt;/td&gt;
&lt;td&gt;HR&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;LEVEL&lt;/code&gt;&lt;/strong&gt;: Used with the &lt;code&gt;SELECT ... CONNECT BY&lt;/code&gt; hierarchical query clause to organize flat rows into a tree structure. It returns the current depth level of a node within the hierarchy.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  3. Hierarchical Queries &amp;amp; Tree Pseudo-Columns (&lt;code&gt;CONNECT BY&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;When working with hierarchical data (such as an employee-manager reporting line), Oracle provides specialized pseudo-columns to inspect tree structures:&lt;/p&gt;

&lt;h4&gt;
  
  
  Example: Hierarchical Query Structure
&lt;/h4&gt;

&lt;p&gt;SQL&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;ename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;empno&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;CONNECT_BY_ISLEAF&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;CONNECT_BY_ISCYCLE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;LEVEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;SYS_CONNECT_BY_PATH&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'-&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;
    &lt;span class="n"&gt;emp&lt;/span&gt;
&lt;span class="k"&gt;CONNECT&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;NOCYCLE&lt;/span&gt;
    &lt;span class="k"&gt;PRIOR&lt;/span&gt; &lt;span class="n"&gt;empno&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mgr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Explanation of Hierarchical Pseudo-Columns used in Example:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;CONNECT_BY_ISLEAF&lt;/code&gt;&lt;/strong&gt;: Returns &lt;code&gt;1&lt;/code&gt; if the current row is a leaf node (has no children in the tree structure), and &lt;code&gt;0&lt;/code&gt; otherwise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;CONNECT_BY_ISCYCLE&lt;/code&gt;&lt;/strong&gt;: Returns &lt;code&gt;1&lt;/code&gt; if the current row has a child that is an ancestor of itself (a loop in the hierarchy), and &lt;code&gt;0&lt;/code&gt; otherwise. (Requires the &lt;code&gt;NOCYCLE&lt;/code&gt; keyword in the &lt;code&gt;CONNECT BY&lt;/code&gt; clause to avoid infinite loops).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;SYS_CONNECT_BY_PATH(column, char)&lt;/code&gt;&lt;/strong&gt;: Returns the path of column values from the root to the current node, separated by the specified character string.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Advanced Interview Insights &amp;amp; Frequently Asked Questions
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Interviewers heavily test pseudo-columns, especially regarding execution order and limitations.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What is the evaluation order of &lt;code&gt;ROWNUM&lt;/code&gt; in a query?&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ROWNUM&lt;/code&gt; is assigned &lt;strong&gt;after&lt;/strong&gt; the &lt;code&gt;WHERE&lt;/code&gt; clause is evaluated, but &lt;strong&gt;before&lt;/strong&gt; &lt;code&gt;ORDER BY&lt;/code&gt; and &lt;code&gt;GROUP BY&lt;/code&gt; clauses. This is why filtering with &lt;code&gt;ROWNUM &amp;gt; 1&lt;/code&gt; directly will always return zero rows (since row 1 fails the condition, it is discarded, and the next row becomes row 1). To handle pagination safely with &lt;code&gt;ROWNUM&lt;/code&gt;, you must use an inline view or subquery that encapsulates the &lt;code&gt;ORDER BY&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Can you create your own custom pseudo-columns?&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;No, pseudo-columns are system-defined by Oracle. However, virtual columns (introduced in Oracle 11g) allow you to define custom expression-based columns that are stored logically or physically as metadata.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What is the difference between &lt;code&gt;ROWID&lt;/code&gt; and &lt;code&gt;ROWNUM&lt;/code&gt;?&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ROWID&lt;/code&gt; is a permanent, unique physical address of a row on disk (stable across transactions until the row is deleted or moved). &lt;code&gt;ROWNUM&lt;/code&gt; is temporary, dynamic, and assigned on-the-fly to rows as they are fetched into the result set during statement execution.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Can you create an index on a &lt;code&gt;ROWNUM&lt;/code&gt; or &lt;code&gt;ROWID&lt;/code&gt; pseudocolumn?&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Answer:&lt;/strong&gt; You cannot index &lt;code&gt;ROWNUM&lt;/code&gt;, but &lt;code&gt;ROWID&lt;/code&gt; acts as the implicit physical primary address of every row and is inherently indexed via the rowid access path. You can, however, create indexes on &lt;strong&gt;Virtual Columns&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What is the purpose of &lt;code&gt;CONNECT_BY_ISCYCLE&lt;/code&gt;?&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Answer:&lt;/strong&gt; When performing hierarchical queries with loops in the data, &lt;code&gt;CONNECT_BY_ISCYCLE&lt;/code&gt; returns &lt;code&gt;1&lt;/code&gt; if the current row has a child that is also its ancestor (a loop), preventing infinite loops when paired with the &lt;code&gt;NOCYCLE&lt;/code&gt; clause.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;IMPORTANT NOTES FOR INTERVIEW:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Virtual columns do not consume storage space for data (unlike regular columns), but metadata is stored in the dictionary, and they can be indexed to improve query performance.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ROWNUM&lt;/code&gt; is assigned &lt;em&gt;before&lt;/em&gt; any sorting or aggregation happens in a query. If you use &lt;code&gt;ORDER BY&lt;/code&gt; with &lt;code&gt;ROWNUM&lt;/code&gt;, rows are numbered arbitrarily unless wrapped in a subquery.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  💡 Practical Code Example: Hierarchical Queries with Pseudocolumns
&lt;/h2&gt;

&lt;p&gt;SQL&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;ename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;empno&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;CONNECT_BY_ISLEAF&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;CONNECT_BY_ISCYCLE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;LEVEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;SYS_CONNECT_BY_PATH&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'-&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;hierarchy_path&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;emp&lt;/span&gt;
&lt;span class="k"&gt;CONNECT&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;NOCYCLE&lt;/span&gt; &lt;span class="k"&gt;PRIOR&lt;/span&gt; &lt;span class="n"&gt;empno&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mgr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ⚖️ Difference: Pseudocolumn vs. Virtual Column
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Feature&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Pseudocolumn&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Virtual Column&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Table Storage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not part of the table definition/storage.&lt;/td&gt;
&lt;td&gt;Physically part of the table metadata structure, though values are derived on-the-fly.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Value Derivation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Generated dynamically by the query engine (e.g., &lt;code&gt;ROWNUM&lt;/code&gt;, &lt;code&gt;LEVEL&lt;/code&gt;).&lt;/td&gt;
&lt;td&gt;Derived from expressions/other columns of the same table.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Indexing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cannot be indexed directly.&lt;/td&gt;
&lt;td&gt;Can be indexed (including B-tree and function-based indexes).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DML Operations&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Selection only (No INSERT/UPDATE/DELETE).&lt;/td&gt;
&lt;td&gt;Selection only; values are managed automatically by the database via expressions (No direct DML on the virtual column).&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  🏗️ Table Structure Example: Virtual Columns
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;Test&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt;   &lt;span class="n"&gt;NUMBER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;b&lt;/span&gt;   &lt;span class="n"&gt;NUMBER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;SUM&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="c1"&gt;-- Virtual Column&lt;/span&gt;
    &lt;span class="n"&gt;Sub&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="c1"&gt;-- Virtual Column&lt;/span&gt;
    &lt;span class="n"&gt;Mul&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="c1"&gt;-- Virtual Column&lt;/span&gt;
    &lt;span class="n"&gt;Div&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;-- Virtual Column&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>oracle</category>
      <category>oraclesql</category>
      <category>sql</category>
      <category>plsql</category>
    </item>
    <item>
      <title>Oracle SQL: Read-Only Tables</title>
      <dc:creator>SANDEEP KUMAR</dc:creator>
      <pubDate>Wed, 23 Sep 2026 02:52:55 +0000</pubDate>
      <link>https://dev.to/sandeep-oracle/oracle-sql-read-only-tables-4ha6</link>
      <guid>https://dev.to/sandeep-oracle/oracle-sql-read-only-tables-4ha6</guid>
      <description>&lt;h3&gt;
  
  
  1. Overview &amp;amp; Core Concepts
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Definition:&lt;/strong&gt; Oracle allows you to restrict tables to read-only mode, blocking all Data Modification Language (DML) operations (such as &lt;code&gt;INSERT&lt;/code&gt;, &lt;code&gt;UPDATE&lt;/code&gt;, &lt;code&gt;DELETE&lt;/code&gt;) and certain Data Definition Language (DDL) modifications while permitting &lt;code&gt;SELECT&lt;/code&gt; queries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Primary Use Cases:&lt;/strong&gt; Protecting reference data, historical archives, compliance data retention, and locking master tables during maintenance or migration windows.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Methods to Make a Table Read-Only or Restrict Data Modifications
&lt;/h3&gt;

&lt;p&gt;There are multiple approaches in Oracle to enforce read-only behavior on table data, ranging from native table states to permissions, views, and triggers.&lt;/p&gt;

&lt;h4&gt;
  
  
  Method 1: Using Native Table Read-Only State (&lt;code&gt;ALTER TABLE ... READ ONLY&lt;/code&gt;)
&lt;/h4&gt;

&lt;p&gt;This is the cleanest, built-in feature introduced in Oracle to directly set a table's state to read-only.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Syntax:&lt;/strong&gt;SQL&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ALTER TABLE emp READ ONLY;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Reverting to Read-Write:&lt;/strong&gt;SQL&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ALTER TABLE emp READ WRITE;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Behavior &amp;amp; Error Handling:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you attempt to insert or update records on a read-only table, Oracle throws a direct error:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SQL Error:&lt;/strong&gt; &lt;code&gt;ORA-12081: update operation not allowed on table "EMP"&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Method 2: Granting Restricted Privileges Across Schemas
&lt;/h4&gt;

&lt;p&gt;You can isolate the master table in a dedicated schema (&lt;code&gt;Schema1&lt;/code&gt; / &lt;code&gt;User-A&lt;/code&gt;) and grant only &lt;code&gt;SELECT&lt;/code&gt; privileges to other users (&lt;code&gt;Schema2&lt;/code&gt; / &lt;code&gt;User-B&lt;/code&gt;).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Setup &amp;amp; Granting Privilege:&lt;/strong&gt;SQL&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Connected as Schema1 (User-A)
GRANT SELECT ON emp TO user_b;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Behavior from User-B's Schema:&lt;/strong&gt;SQL&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Connected as Schema2 (User-B)
INSERT INTO user_a.emp VALUES (..., ...);
&lt;/code&gt;&lt;/pre&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Error Output:&lt;/strong&gt; &lt;code&gt;ORA-01031: insufficient privileges&lt;/code&gt; (or general insufficient privileges error).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Method 3 &amp;amp; 4: Creating Views (Standard or Read-Only Views)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;You can revoke direct DML access to the base table and expose data strictly via a view.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Starting in Oracle, you can explicitly create a &lt;strong&gt;read-only view&lt;/strong&gt; to block DML directly through the view&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE OR REPLACE VIEW emp_ro_view AS
SELECT * FROM emp
WITH READ ONLY;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Method 5: Using Statement-Level Triggers
&lt;/h4&gt;

&lt;p&gt;You can implement a database trigger to intercept and block any DML transactions at the statement level.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Syntax &amp;amp; Example:&lt;/strong&gt;SQL&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE OR REPLACE TRIGGER tr_block_dml
BEFORE INSERT OR UPDATE OR DELETE ON emp
BEGIN
    RAISE_APPLICATION_ERROR(-20001, 'Table is read-only. DML operations are not allowed.');
END;
/
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Summary Comparison of Read-Only Approaches
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Method&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Cons / Limitations&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;ALTER TABLE READ ONLY&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Native, high-performance, dictionary-enforced, prevents accidental DML by table owners/admins without switching mode.&lt;/td&gt;
&lt;td&gt;Requires exclusive table access lock to change state.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Schema Privileges&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Clean separation of duties; non-owners cannot write.&lt;/td&gt;
&lt;td&gt;Owner of the schema can still perform DML.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Read-Only Views (&lt;code&gt;WITH READ ONLY&lt;/code&gt;)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Granular column/row filtering while keeping base table secured.&lt;/td&gt;
&lt;td&gt;Users with direct table access can still modify the base table.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Triggers&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Highly customizable; can include conditional logic (e.g., allow specific users).&lt;/td&gt;
&lt;td&gt;Overhead on every DML statement; can be disabled by users with &lt;code&gt;ALTER TRIGGER&lt;/code&gt; privileges.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  4. Advanced Interview Insights &amp;amp; Frequently Asked Questions
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Interviewers frequently probe into the metadata behavior and edge cases of read-only tables.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Can you drop or truncate a read-only table?&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No.&lt;/strong&gt; DDL operations that modify the table structure or contents (like &lt;code&gt;DROP TABLE&lt;/code&gt; or &lt;code&gt;TRUNCATE TABLE&lt;/code&gt;) are blocked when a table is in &lt;code&gt;READ ONLY&lt;/code&gt; mode. You must first alter the table back to &lt;code&gt;READ WRITE&lt;/code&gt; (&lt;code&gt;ALTER TABLE tab_name READ WRITE;&lt;/code&gt;) before dropping or truncating.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Can indexes be created or rebuilt on a read-only table?&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Dropping or creating indexes is generally restricted while the table is read-only because it modifies the table's segment metadata.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How can you verify if a table is currently in read-only mode?&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;You can query the &lt;code&gt;READ_ONLY&lt;/code&gt; column from data dictionary views like &lt;code&gt;USER_TABLES&lt;/code&gt;, &lt;code&gt;ALL_TABLES&lt;/code&gt;, or &lt;code&gt;DBA_TABLES&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    ```
    SELECT table_name, read_only
    FROM user_tables
    WHERE table_name = 'EMP';
    ```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>oracle</category>
      <category>oraclesql</category>
      <category>sql</category>
      <category>plsql</category>
    </item>
    <item>
      <title>Oracle SQL: Unused Columns &amp; Virtual Columns</title>
      <dc:creator>SANDEEP KUMAR</dc:creator>
      <pubDate>Wed, 23 Sep 2026 02:50:36 +0000</pubDate>
      <link>https://dev.to/sandeep-oracle/oracle-sql-unused-columns-virtual-columns-5b23</link>
      <guid>https://dev.to/sandeep-oracle/oracle-sql-unused-columns-virtual-columns-5b23</guid>
      <description>&lt;h2&gt;
  
  
  1. Unused Columns (&lt;code&gt;SET UNUSED&lt;/code&gt;)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Overview &amp;amp; Concept
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Definition:&lt;/strong&gt; Marking a column as &lt;strong&gt;&lt;code&gt;UNUSED&lt;/code&gt;&lt;/strong&gt; is a form of &lt;strong&gt;logical deletion&lt;/strong&gt;. The column metadata is hidden, but the physical data remains untouched in the table blocks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance Benefit:&lt;/strong&gt; Unlike a traditional &lt;strong&gt;&lt;code&gt;DROP COLUMN&lt;/code&gt;&lt;/strong&gt; (which locks the table and rewrites every data block to reclaim space immediately), &lt;code&gt;SET UNUSED&lt;/code&gt; is an &lt;strong&gt;instant metadata-only operation&lt;/strong&gt;. This prevents long locks and heavy I/O overhead on large production tables.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Key Characteristics
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Metadata Hiding:&lt;/strong&gt; Once a column is marked as unused, it cannot be viewed via the &lt;code&gt;DESC&lt;/code&gt; command or standard &lt;code&gt;SELECT *&lt;/code&gt; queries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reusing Column Names:&lt;/strong&gt; Because Oracle internally renames unused columns in the data dictionary with system-generated names (e.g., &lt;code&gt;SYS_00001_...&lt;/code&gt;), you can immediately create a &lt;strong&gt;new column with the same name&lt;/strong&gt; on the table.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reversibility:&lt;/strong&gt; You cannot directly "un-set" an unused column using a simple undo command. To reclaim space permanently, the column must eventually be dropped.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Core SQL Operations &amp;amp; Examples
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;1. Mark a Column as Unused:&lt;/strong&gt;SQL&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ALTER TABLE cust_details
SET UNUSED (cust_account_number
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;2. View Unused Columns:&lt;/strong&gt;SQL&lt;/p&gt;

&lt;p&gt;To inspect unused columns in a table, query data dictionary views such as &lt;code&gt;DBA_UNUSED_COL_TABS&lt;/code&gt;, &lt;code&gt;USER_UNUSED_COLS&lt;/code&gt;, or use session settings:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SET COLINVISIBLE ON;
DESC cust_details;
*(Alternatively, query `USER_UNUSED_COLS` to see table names and counts of unused columns).*
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;3. Drop All Unused Columns Permanently:&lt;/strong&gt;SQL&lt;/p&gt;

&lt;p&gt;This command physically removes the data and reclaims disk space. It can be resource-intensive on large tables:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ALTER TABLE cust_details
DROP UNUSED COLUMNS;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Virtual Columns
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Overview &amp;amp; Concept
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Definition:&lt;/strong&gt; A virtual column is a &lt;strong&gt;derived column&lt;/strong&gt; defined in a table with an underlying expression that computes values from other physical columns in the same row.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage Behavior:&lt;/strong&gt; Virtual columns &lt;strong&gt;do not store data physically on disk&lt;/strong&gt; by default. Instead, the database evaluates the expression dynamically at runtime. &lt;em&gt;(Note: Oracle also supports &lt;code&gt;STORED&lt;/code&gt; virtual columns if persistence is required for indexing or performance).&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Rules, Limitations, and Restrictions
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DML Restrictions:&lt;/strong&gt; You &lt;strong&gt;cannot&lt;/strong&gt; perform direct DML operations (&lt;code&gt;INSERT&lt;/code&gt;, &lt;code&gt;UPDATE&lt;/code&gt;, &lt;code&gt;DELETE&lt;/code&gt;) on virtual columns. Their values are managed entirely by the underlying expression.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Table Type Support:&lt;/strong&gt; Virtual columns can only be defined on &lt;strong&gt;Heap-organized tables&lt;/strong&gt;. They are &lt;strong&gt;not supported&lt;/strong&gt; for external tables, Index-Organized Tables (IOT), clustered tables, or temporary tables.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependencies:&lt;/strong&gt; A virtual column cannot reference another virtual column; it must reference physical columns within the &lt;strong&gt;same table&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Type:&lt;/strong&gt; The expression for a virtual column must evaluate to a &lt;strong&gt;scalar data type&lt;/strong&gt; only.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Partitioning:&lt;/strong&gt; Virtual columns can be used as &lt;strong&gt;partition keys&lt;/strong&gt; (e.g., partitioning a table by a year extracted from a date column).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Indexing Virtual Columns
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You can define indexes on virtual columns.&lt;/li&gt;
&lt;li&gt;These indexes behave identically to &lt;strong&gt;Function-Based Indexes&lt;/strong&gt;, allowing the optimizer to pre-calculate and index the results of the virtual column expression for faster retrieval.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  SQL Syntax &amp;amp; Example
&lt;/h3&gt;

&lt;p&gt;SQL&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;t1&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt;   &lt;span class="n"&gt;NUMBER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;col1&lt;/span&gt; &lt;span class="n"&gt;NUMBER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;col2&lt;/span&gt; &lt;span class="n"&gt;NUMBER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;col3&lt;/span&gt; &lt;span class="n"&gt;NUMBER&lt;/span&gt; &lt;span class="k"&gt;GENERATED&lt;/span&gt; &lt;span class="n"&gt;ALWAYS&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;col1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;col2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;VIRTUAL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;3. Senior Architect &amp;amp; Interview Masterclass&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What is the difference between &lt;code&gt;DROP COLUMN&lt;/code&gt; and &lt;code&gt;SET UNUSED&lt;/code&gt;?&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;DROP COLUMN&lt;/code&gt; immediately removes the column definition and physically purges the data from all blocks, which can cause severe locking and performance degradation on large tables.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SET UNUSED&lt;/code&gt; instantly updates the data dictionary metadata, marking the column as dead without touching the physical blocks. Space reclamation is deferred until &lt;code&gt;ALTER TABLE ... DROP UNUSED COLUMNS&lt;/code&gt; is executed manually (often scheduled during maintenance windows)[cite: 5].&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Can you add a primary key constraint or unique constraint on a Virtual Column?&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Yes! If the underlying expression guarantees uniqueness or non-null behavior, you can add constraints (like &lt;code&gt;NOT NULL&lt;/code&gt; or &lt;code&gt;UNIQUE&lt;/code&gt;) and create indexes on virtual columns, making them extremely powerful for enforcing business rules without duplicating storage.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What happens to indexes when you mark a column as &lt;code&gt;UNUSED&lt;/code&gt;?&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;If the column was part of any indexes, those indexes become unusable/invalid and must be dropped or rebuilt after dropping the unused columns permanently.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>oracle</category>
      <category>oraclesql</category>
      <category>sql</category>
      <category>plsql</category>
    </item>
  </channel>
</rss>
