<?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: Sandhya Steffy M</title>
    <description>The latest articles on DEV Community by Sandhya Steffy M (@sandhya_steffym_4872a8be).</description>
    <link>https://dev.to/sandhya_steffym_4872a8be</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3834531%2Fc15bb61e-d65a-4764-8c0b-4497d50d8cee.png</url>
      <title>DEV Community: Sandhya Steffy M</title>
      <link>https://dev.to/sandhya_steffym_4872a8be</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sandhya_steffym_4872a8be"/>
    <language>en</language>
    <item>
      <title>ALTER TABLE</title>
      <dc:creator>Sandhya Steffy M</dc:creator>
      <pubDate>Thu, 26 Mar 2026 16:36:20 +0000</pubDate>
      <link>https://dev.to/sandhya_steffym_4872a8be/alter-table-47g6</link>
      <guid>https://dev.to/sandhya_steffym_4872a8be/alter-table-47g6</guid>
      <description>&lt;p&gt;Today I learned that creating a table is only the first step in SQL. Sometimes, after creating a table, we may realize that we need to change some rules. For example, maybe a column should not allow empty values, or maybe we want to add a new constraint later.&lt;br&gt;
For this, SQL gives us an important command called ALTER TABLE.&lt;/p&gt;

&lt;p&gt;ALTER TABLE is used when we want to change the structure of an existing table without deleting it and creating it again.&lt;/p&gt;

&lt;p&gt;In this blog, I am going to explain different ALTER TABLE tasks in a simple way.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Making email compulsory in the customers table
Suppose we already have a table called customers, and its email column currently allows NULL values. But now we want all future records to обязательно have an email value.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For that, we can modify the column using:&lt;/p&gt;

&lt;p&gt;ALTER TABLE customers&lt;br&gt;
ALTER COLUMN email SET NOT NULL;&lt;br&gt;
What this does:&lt;br&gt;
This command makes the email field compulsory from now on.&lt;br&gt;
So, while inserting new records, we cannot leave the email empty.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Making username unique in the users table
In many applications, usernames should be unique. Two users should not have the same username.
If the table is already created, we can add this rule later using ALTER TABLE.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ALTER TABLE users&lt;br&gt;
ADD CONSTRAINT unique_username UNIQUE (username);&lt;br&gt;
What this does:&lt;br&gt;
This adds a UNIQUE constraint on the username column.&lt;br&gt;
That means duplicate usernames are not allowed.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ensuring product price is always greater than 0
In the products table, price should never be zero or negative.
This can be enforced using a CHECK constraint.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ALTER TABLE products&lt;br&gt;
ADD CONSTRAINT check_price_positive CHECK (price &amp;gt; 0);&lt;br&gt;
What this does:&lt;br&gt;
This makes sure the price value is always greater than 0.&lt;br&gt;
So invalid prices cannot be inserted.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Setting default status in orders table
Sometimes when we insert a new order, we may forget to mention the order status.
In such cases, it is useful to automatically set a default value like 'pending'.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ALTER TABLE orders&lt;br&gt;
ALTER COLUMN status SET DEFAULT 'pending';&lt;br&gt;
What this does:&lt;br&gt;
If no status is given during insertion, SQL will automatically store 'pending'.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Adding a salary column in employees table
Now let us say we want to add a new column called salary in the employees table.
The condition is:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;salary should not be NULL&lt;/li&gt;
&lt;li&gt;salary should always be greater than 10,000
This can be done like this:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ALTER TABLE employees&lt;br&gt;
ADD COLUMN salary DECIMAL(10,2) NOT NULL CHECK (salary &amp;gt; 10000);&lt;br&gt;
What this does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This creates a new column called salary and applies two rules:&lt;/li&gt;
&lt;li&gt;it must have a value&lt;/li&gt;
&lt;li&gt;the value must be above 10,000&lt;/li&gt;
&lt;li&gt;Changing foreign key so deleting a department also deletes employees
Suppose the employees table is connected to the departments table using a foreign key.
Now we want this behavior:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a department is deleted, all employees belonging to that department should also be deleted automatically.&lt;/p&gt;

&lt;p&gt;Usually, first we remove the old foreign key constraint, then add a new one with ON DELETE CASCADE.&lt;/p&gt;

&lt;p&gt;ALTER TABLE employees&lt;br&gt;
DROP CONSTRAINT employees_department_id_fkey;&lt;/p&gt;

&lt;p&gt;ALTER TABLE employees&lt;br&gt;
ADD CONSTRAINT employees_department_id_fkey&lt;br&gt;
FOREIGN KEY (department_id)&lt;br&gt;
REFERENCES departments(id)&lt;br&gt;
ON DELETE CASCADE;&lt;br&gt;
What this does:&lt;br&gt;
If a department row is deleted, all matching employee rows are also deleted automatically.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Removing an existing CHECK constraint from accounts table
In the accounts table, assume there is already a CHECK constraint that ensures balance &amp;gt;= 0.
If we want to remove that rule, we need to drop the constraint.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;p&gt;ALTER TABLE accounts&lt;br&gt;
DROP CONSTRAINT accounts_balance_check;&lt;br&gt;
What this does:&lt;br&gt;
This removes the check condition from the balance column.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Making combination of user_id and transaction_id unique in payments table
In the payments table, one user_id and transaction_id combination should not repeat.
This means the pair together must be unique.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ALTER TABLE payments&lt;br&gt;
ADD CONSTRAINT unique_user_transaction UNIQUE (user_id, transaction_id);&lt;/p&gt;

&lt;p&gt;What this does:&lt;br&gt;
This prevents duplicate entries with the same user_id and transaction_id combination.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>database</category>
      <category>sql</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Create Tables</title>
      <dc:creator>Sandhya Steffy M</dc:creator>
      <pubDate>Thu, 26 Mar 2026 16:32:48 +0000</pubDate>
      <link>https://dev.to/sandhya_steffym_4872a8be/create-tables-3gc9</link>
      <guid>https://dev.to/sandhya_steffym_4872a8be/create-tables-3gc9</guid>
      <description>&lt;p&gt;Today I learned how to create tables in SQL and how to apply different constraints. At first, it felt confusing, but when I understood the purpose behind each rule, it became much easier.&lt;/p&gt;

&lt;p&gt;Let me explain each task in a simple way.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Creating a Students Table
First, I created a table called students. Each student should have an id, name, and age. The important thing here is that id must be unique, so we use a PRIMARY KEY.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;CREATE TABLE students (&lt;br&gt;
    id SERIAL PRIMARY KEY,&lt;br&gt;
    name VARCHAR(100),&lt;br&gt;
    age INT&lt;br&gt;
);&lt;br&gt;
Here, PRIMARY KEY ensures that no two students will have the same id.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Employees Table with Required Fields
Next, I created an employees table. In this case, name and email should not be empty, but phone number is optional.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;CREATE TABLE employees (&lt;br&gt;
    id SERIAL PRIMARY KEY,&lt;br&gt;
    name VARCHAR(100) NOT NULL,&lt;br&gt;
    email VARCHAR(100) NOT NULL,&lt;br&gt;
    phone_number VARCHAR(15)&lt;br&gt;
);&lt;br&gt;
NOT NULL means the user must provide a value.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Users Table with Unique Values
In this task, both username and email must be unique. This is useful in real systems like login systems.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;CREATE TABLE users (&lt;br&gt;
    id SERIAL PRIMARY KEY,&lt;br&gt;
    username VARCHAR(50) UNIQUE,&lt;br&gt;
    email VARCHAR(100) UNIQUE&lt;br&gt;
);&lt;br&gt;
Here, UNIQUE prevents duplicate entries.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Products Table with Conditions
For products, I learned how to restrict values using CHECK constraints.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;CREATE TABLE products (&lt;br&gt;
    id SERIAL PRIMARY KEY,&lt;br&gt;
    name VARCHAR(100),&lt;br&gt;
    price DECIMAL(10,2) CHECK (price &amp;gt; 0),&lt;br&gt;
    stock INT CHECK (stock &amp;gt;= 0)&lt;br&gt;
);&lt;br&gt;
This ensures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Price is always positive&lt;/li&gt;
&lt;li&gt;Stock is never negative&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Orders Table with Default Values
Sometimes, we want default values. For example, if no status is given, it should be pending.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;CREATE TABLE orders (&lt;br&gt;
    id SERIAL PRIMARY KEY,&lt;br&gt;
    status VARCHAR(20) DEFAULT 'pending',&lt;br&gt;
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP&lt;br&gt;
);&lt;br&gt;
This automatically sets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;status → pending&lt;/li&gt;
&lt;li&gt;created_at → current time&lt;/li&gt;
&lt;li&gt;Accounts Table with Rules
In banking-like systems, we must be very careful with data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CREATE TABLE accounts (&lt;br&gt;
    id SERIAL PRIMARY KEY,&lt;br&gt;
    account_number VARCHAR(20) UNIQUE NOT NULL,&lt;br&gt;
    balance DECIMAL(10,2) CHECK (balance &amp;gt;= 0)&lt;br&gt;
);&lt;br&gt;
This ensures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;account number is always unique&lt;/li&gt;
&lt;li&gt;balance never goes below zero&lt;/li&gt;
&lt;li&gt;Enrollments Table (Combination Unique)
Here I learned something interesting. A student can take many courses, but the same student cannot enroll in the same course twice.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CREATE TABLE enrollments (&lt;br&gt;
    student_id INT,&lt;br&gt;
    course_id INT,&lt;br&gt;
    PRIMARY KEY (student_id, course_id)&lt;br&gt;
);&lt;br&gt;
This is called a composite key.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Foreign Key Relationship (Departments &amp;amp; Employees)
Now I created two tables where one depends on another.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;CREATE TABLE departments (&lt;br&gt;
    id SERIAL PRIMARY KEY,&lt;br&gt;
    name VARCHAR(100)&lt;br&gt;
);&lt;/p&gt;

&lt;p&gt;CREATE TABLE employees (&lt;br&gt;
    id SERIAL PRIMARY KEY,&lt;br&gt;
    name VARCHAR(100),&lt;br&gt;
    department_id INT,&lt;br&gt;
    FOREIGN KEY (department_id) REFERENCES departments(id)&lt;br&gt;
);&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This ensures that an employee can only belong to an existing department.&lt;/li&gt;
&lt;li&gt;Cascade Delete and Update
Finally, I improved the previous example by adding automatic updates.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CREATE TABLE employees (&lt;br&gt;
    id SERIAL PRIMARY KEY,&lt;br&gt;
    name VARCHAR(100),&lt;br&gt;
    department_id INT,&lt;br&gt;
    FOREIGN KEY (department_id)&lt;br&gt;
    REFERENCES departments(id)&lt;br&gt;
    ON DELETE CASCADE&lt;br&gt;
    ON UPDATE CASCADE&lt;br&gt;
);&lt;br&gt;
This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If a department is deleted → its employees are also deleted&lt;/li&gt;
&lt;li&gt;If department id changes → it updates automatically&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>beginners</category>
      <category>database</category>
      <category>postgres</category>
      <category>sql</category>
    </item>
    <item>
      <title>Idempotency Situation</title>
      <dc:creator>Sandhya Steffy M</dc:creator>
      <pubDate>Wed, 25 Mar 2026 13:39:30 +0000</pubDate>
      <link>https://dev.to/sandhya_steffym_4872a8be/idempotency-situation-1483</link>
      <guid>https://dev.to/sandhya_steffym_4872a8be/idempotency-situation-1483</guid>
      <description>&lt;p&gt;In this task, I understood the concept of idempotency in a wallet system. In real applications like GPay or PhonePe, sometimes the same request may be sent multiple times due to network issues or retries. The system should ensure that the same transaction is not executed more than once.&lt;/p&gt;

&lt;p&gt;First, I created the accounts table.&lt;/p&gt;

&lt;p&gt;CREATE TABLE accounts (&lt;br&gt;
    id SERIAL PRIMARY KEY,&lt;br&gt;
    name TEXT NOT NULL,&lt;br&gt;
    balance INT NOT NULL CHECK (balance &amp;gt;= 0),&lt;br&gt;
    last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP&lt;br&gt;
);&lt;/p&gt;

&lt;p&gt;Then I inserted sample data.&lt;/p&gt;

&lt;p&gt;INSERT INTO accounts (name, balance)&lt;br&gt;
VALUES&lt;br&gt;
('Alice', 1000),&lt;br&gt;
('Bob', 500);&lt;/p&gt;

&lt;p&gt;To check initial balances:&lt;/p&gt;

&lt;p&gt;SELECT * FROM accounts;&lt;/p&gt;

&lt;p&gt;Alice had 1000 and Bob had 500.&lt;/p&gt;

&lt;p&gt;Next, I performed a transfer of 200 from Alice to Bob.&lt;/p&gt;

&lt;p&gt;BEGIN;&lt;/p&gt;

&lt;p&gt;UPDATE accounts&lt;br&gt;
SET balance = balance - 200&lt;br&gt;
WHERE id = 1;&lt;/p&gt;

&lt;p&gt;UPDATE accounts&lt;br&gt;
SET balance = balance + 200&lt;br&gt;
WHERE id = 2;&lt;/p&gt;

&lt;p&gt;COMMIT;&lt;br&gt;
After this, Alice had 800 and Bob had 700.&lt;/p&gt;

&lt;p&gt;Then I executed the same transaction again.&lt;/p&gt;

&lt;p&gt;BEGIN;&lt;/p&gt;

&lt;p&gt;UPDATE accounts&lt;br&gt;
SET balance = balance - 200&lt;br&gt;
WHERE id = 1;&lt;/p&gt;

&lt;p&gt;UPDATE accounts&lt;br&gt;
SET balance = balance + 200&lt;br&gt;
WHERE id = 2;&lt;/p&gt;

&lt;p&gt;COMMIT;&lt;/p&gt;

&lt;p&gt;Now Alice had 600 and Bob had 900.&lt;/p&gt;

&lt;p&gt;This shows that the same transaction was applied again, which means the system is not idempotent. The database does not automatically prevent duplicate execution.&lt;/p&gt;

&lt;p&gt;To solve this, real systems use a unique transaction ID.&lt;/p&gt;

&lt;p&gt;CREATE TABLE wallet_transactions (&lt;br&gt;
    txn_id TEXT PRIMARY KEY,&lt;br&gt;
    sender_id INT,&lt;br&gt;
    receiver_id INT,&lt;br&gt;
    amount INT,&lt;br&gt;
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP&lt;br&gt;
);&lt;/p&gt;

&lt;p&gt;Insert a transaction:&lt;/p&gt;

&lt;p&gt;INSERT INTO wallet_transactions (txn_id, sender_id, receiver_id, amount)&lt;br&gt;
VALUES ('TXN1001', 1, 2, 200);&lt;/p&gt;

&lt;p&gt;If the same request is sent again:&lt;/p&gt;

&lt;p&gt;INSERT INTO wallet_transactions (txn_id, sender_id, receiver_id, amount)&lt;br&gt;
VALUES ('TXN1001', 1, 2, 200);&lt;br&gt;
PostgreSQL will give an error because the transaction ID already exists. This prevents duplicate processing.&lt;/p&gt;

</description>
      <category>database</category>
      <category>postgres</category>
      <category>sql</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Durability in Wallet Transfer System</title>
      <dc:creator>Sandhya Steffy M</dc:creator>
      <pubDate>Wed, 25 Mar 2026 13:29:34 +0000</pubDate>
      <link>https://dev.to/sandhya_steffym_4872a8be/durability-in-wallet-transfer-system-1m46</link>
      <guid>https://dev.to/sandhya_steffym_4872a8be/durability-in-wallet-transfer-system-1m46</guid>
      <description>&lt;p&gt;In this task, I understood the Durability property of ACID using a wallet system. Durability means that once a transaction is committed, the data will be permanently stored in the database and will not be lost even if the system crashes or restarts.&lt;/p&gt;

&lt;p&gt;First, I created the accounts table.&lt;/p&gt;

&lt;p&gt;CREATE TABLE accounts (&lt;br&gt;
    id SERIAL PRIMARY KEY,&lt;br&gt;
    name TEXT NOT NULL,&lt;br&gt;
    balance INT NOT NULL CHECK (balance &amp;gt;= 0),&lt;br&gt;
    last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP&lt;br&gt;
);&lt;br&gt;
Then I inserted sample data.&lt;/p&gt;

&lt;p&gt;INSERT INTO accounts (name, balance)&lt;br&gt;
VALUES&lt;br&gt;
('Alice', 1000),&lt;br&gt;
('Bob', 500);&lt;br&gt;
To check the initial data:&lt;/p&gt;

&lt;p&gt;SELECT * FROM accounts;&lt;br&gt;
Alice had 1000 and Bob had 500.&lt;/p&gt;

&lt;p&gt;Next, I performed a successful transaction to transfer 300 from Alice to Bob.&lt;/p&gt;

&lt;p&gt;BEGIN;&lt;/p&gt;

&lt;p&gt;UPDATE accounts&lt;br&gt;
SET balance = balance - 300&lt;br&gt;
WHERE id = 1;&lt;/p&gt;

&lt;p&gt;UPDATE accounts&lt;br&gt;
SET balance = balance + 300&lt;br&gt;
WHERE id = 2;&lt;/p&gt;

&lt;p&gt;COMMIT;&lt;br&gt;
After committing, I checked the data again.&lt;/p&gt;

&lt;p&gt;SELECT * FROM accounts;&lt;br&gt;
Now Alice had 700 and Bob had 800.&lt;/p&gt;

&lt;p&gt;Then I simulated a system restart by reconnecting to the database and checked the data again.&lt;/p&gt;

&lt;p&gt;SELECT * FROM accounts;&lt;br&gt;
The values remained the same, which shows that the committed transaction was permanently saved.&lt;/p&gt;

&lt;p&gt;If a failure happens before COMMIT, the changes are not saved.&lt;/p&gt;

&lt;p&gt;BEGIN;&lt;/p&gt;

&lt;p&gt;UPDATE accounts&lt;br&gt;
SET balance = balance - 200&lt;br&gt;
WHERE id = 1;&lt;/p&gt;

&lt;p&gt;-- crash before COMMIT&lt;br&gt;
After restart, the balance remains unchanged.&lt;/p&gt;

&lt;p&gt;If a failure happens after COMMIT, the data is already stored and will not be lost.&lt;/p&gt;

&lt;p&gt;This happens because PostgreSQL uses Write-Ahead Logging (WAL), which ensures that committed data can be recovered even after a crash.&lt;/p&gt;

&lt;p&gt;From this task, I understood that Durability ensures that once a transaction is completed, the data remains safe and permanent. This is very important in wallet systems to prevent loss of money or incorrect balances.&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>database</category>
      <category>postgres</category>
      <category>sql</category>
    </item>
    <item>
      <title>ISOLATION</title>
      <dc:creator>Sandhya Steffy M</dc:creator>
      <pubDate>Wed, 25 Mar 2026 13:25:30 +0000</pubDate>
      <link>https://dev.to/sandhya_steffym_4872a8be/isolation-35k6</link>
      <guid>https://dev.to/sandhya_steffym_4872a8be/isolation-35k6</guid>
      <description>&lt;p&gt;Isolation in Wallet Transfer System&lt;/p&gt;

&lt;p&gt;In this task, I understood the Isolation property of ACID using a simple wallet system. In applications like GPay or PhonePe, many users perform transactions at the same time. Isolation ensures that one transaction does not affect another transaction in a wrong way.&lt;/p&gt;

&lt;p&gt;I created a table called accounts to store user balances.&lt;/p&gt;

&lt;p&gt;CREATE TABLE accounts (&lt;br&gt;
    id SERIAL PRIMARY KEY,&lt;br&gt;
    name TEXT NOT NULL,&lt;br&gt;
    balance INT NOT NULL CHECK (balance &amp;gt;= 0),&lt;br&gt;
    last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP&lt;br&gt;
);&lt;/p&gt;

&lt;p&gt;Then I inserted sample data.&lt;/p&gt;

&lt;p&gt;INSERT INTO accounts (name, balance)&lt;br&gt;
VALUES&lt;br&gt;
('Alice', 1000),&lt;br&gt;
('Bob', 500);&lt;/p&gt;

&lt;p&gt;To check initial data:&lt;/p&gt;

&lt;p&gt;SELECT * FROM accounts;&lt;/p&gt;

&lt;p&gt;At this stage, Alice had 1000 and Bob had 500.&lt;/p&gt;

&lt;p&gt;Testing Isolation using two sessions&lt;br&gt;
To understand isolation, I opened two query windows (Session 1 and Session 2).&lt;/p&gt;

&lt;p&gt;Session 1&lt;br&gt;
In the first session, I started a transaction and deducted money from Alice, but I did not commit.&lt;/p&gt;

&lt;p&gt;BEGIN;&lt;/p&gt;

&lt;p&gt;UPDATE accounts&lt;br&gt;
SET balance = balance - 700&lt;br&gt;
WHERE id = 1;&lt;/p&gt;

&lt;p&gt;SELECT * FROM accounts WHERE id = 1;&lt;br&gt;
Here, Session 1 shows Alice’s balance as 300.&lt;/p&gt;

&lt;p&gt;Session 2&lt;br&gt;
In another session, I checked Alice’s balance.&lt;/p&gt;

&lt;p&gt;SELECT * FROM accounts WHERE id = 1;&lt;br&gt;
It still showed 1000, not 300.&lt;/p&gt;

&lt;p&gt;This means Session 2 cannot see the uncommitted changes of Session 1. This prevents dirty reads.&lt;/p&gt;

&lt;p&gt;Trying concurrent update&lt;br&gt;
In Session 2, I tried to update the same row.&lt;/p&gt;

&lt;p&gt;BEGIN;&lt;/p&gt;

&lt;p&gt;UPDATE accounts&lt;br&gt;
SET balance = balance - 500&lt;br&gt;
WHERE id = 1;&lt;br&gt;
This query did not execute immediately. It waited because Session 1 was already using that row.&lt;/p&gt;

&lt;p&gt;Commit in Session 1&lt;br&gt;
Now I committed the first transaction.&lt;/p&gt;

&lt;p&gt;COMMIT;&lt;br&gt;
After this, Session 2 continued execution. This shows that PostgreSQL uses locking to avoid conflicts.&lt;/p&gt;

&lt;p&gt;Testing Isolation Levels&lt;br&gt;
By default, PostgreSQL uses Read Committed isolation level.&lt;/p&gt;

&lt;p&gt;BEGIN;&lt;br&gt;
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;&lt;/p&gt;

&lt;p&gt;SELECT * FROM accounts WHERE id = 1;&lt;br&gt;
This level only shows committed data.&lt;/p&gt;

&lt;p&gt;Repeatable Read&lt;br&gt;
BEGIN;&lt;br&gt;
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;&lt;/p&gt;

&lt;p&gt;SELECT * FROM accounts WHERE id = 1;&lt;br&gt;
In this level, the same query will give the same result within the transaction, even if another transaction changes the data.&lt;/p&gt;

&lt;p&gt;Serializable&lt;br&gt;
BEGIN;&lt;br&gt;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;&lt;br&gt;
This is the highest level. It ensures transactions behave like they are executed one after another.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>database</category>
      <category>postgres</category>
      <category>sql</category>
    </item>
    <item>
      <title>Consistency</title>
      <dc:creator>Sandhya Steffy M</dc:creator>
      <pubDate>Wed, 25 Mar 2026 12:13:00 +0000</pubDate>
      <link>https://dev.to/sandhya_steffym_4872a8be/consistency-18h0</link>
      <guid>https://dev.to/sandhya_steffym_4872a8be/consistency-18h0</guid>
      <description>&lt;p&gt;In this task, I explored the Consistency property of ACID using a simple wallet system. In payment applications like PhonePe, GPay, or Paytm, the data must always remain correct and valid. If consistency is not maintained, it may lead to negative balances, money loss, or incorrect account details.&lt;/p&gt;

&lt;p&gt;Consistency means that the database should always move from one valid state to another valid state. It should never allow invalid data to be stored.&lt;/p&gt;

&lt;p&gt;To understand this, I used the following accounts table:&lt;/p&gt;

&lt;p&gt;CREATE TABLE accounts (&lt;br&gt;
    id SERIAL PRIMARY KEY,&lt;br&gt;
    name TEXT NOT NULL,&lt;br&gt;
    balance INT NOT NULL CHECK (balance &amp;gt;= 0),&lt;br&gt;
    last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP&lt;br&gt;
);&lt;br&gt;
Here, the important part is:&lt;/p&gt;

&lt;p&gt;CHECK (balance &amp;gt;= 0)&lt;br&gt;
This rule ensures that no account balance can become negative.&lt;/p&gt;

&lt;p&gt;Then I inserted sample data into the table.&lt;/p&gt;

&lt;p&gt;INSERT INTO accounts (name, balance)&lt;br&gt;
VALUES&lt;br&gt;
('Alice', 1000),&lt;br&gt;
('Bob', 500);&lt;br&gt;
To see the current data, I ran:&lt;/p&gt;

&lt;p&gt;SELECT * FROM accounts;&lt;br&gt;
At this stage, Alice had 1000 and Bob had 500.&lt;/p&gt;

&lt;p&gt;Testing Consistency by violating the rule&lt;br&gt;
First, I tried to directly make Alice’s balance negative.&lt;/p&gt;

&lt;p&gt;UPDATE accounts&lt;br&gt;
SET balance = -200&lt;br&gt;
WHERE id = 1;&lt;br&gt;
PostgreSQL did not allow this update. It gave an error because the CHECK (balance &amp;gt;= 0) constraint was violated.&lt;/p&gt;

&lt;p&gt;This shows that the database itself is protecting the data and not allowing an invalid state.&lt;/p&gt;

&lt;p&gt;Trying to deduct more money than available&lt;br&gt;
Next, I tried to deduct more money than Alice actually had.&lt;/p&gt;

&lt;p&gt;UPDATE accounts&lt;br&gt;
SET balance = balance - 2000&lt;br&gt;
WHERE id = 1;&lt;br&gt;
Since Alice had only 1000, this operation would make her balance negative. Again, PostgreSQL rejected the update because of the check constraint.&lt;/p&gt;

&lt;p&gt;Testing inside a transaction&lt;br&gt;
I also tested the same case inside a transaction block.&lt;/p&gt;

&lt;p&gt;BEGIN;&lt;/p&gt;

&lt;p&gt;UPDATE accounts&lt;br&gt;
SET balance = balance - 2000,&lt;br&gt;
    last_updated = CURRENT_TIMESTAMP&lt;br&gt;
WHERE id = 1;&lt;/p&gt;

&lt;p&gt;UPDATE accounts&lt;br&gt;
SET balance = balance + 2000,&lt;br&gt;
    last_updated = CURRENT_TIMESTAMP&lt;br&gt;
WHERE id = 2;&lt;/p&gt;

&lt;p&gt;COMMIT;&lt;br&gt;
In this case, the first update itself failed because it would make Alice’s balance negative. Since the transaction failed, the database did not move to an invalid state.&lt;/p&gt;

&lt;p&gt;When I checked the table again:&lt;/p&gt;

&lt;p&gt;SELECT * FROM accounts;&lt;br&gt;
the balances remained unchanged.&lt;/p&gt;

&lt;p&gt;Handling consistency at application level&lt;br&gt;
Even though the check constraint prevents negative balances, some rules should still be handled in the transaction logic or application code.&lt;/p&gt;

&lt;p&gt;For example, before deducting money, we should verify that the sender has enough balance.&lt;/p&gt;

&lt;p&gt;BEGIN;&lt;/p&gt;

&lt;p&gt;UPDATE accounts&lt;br&gt;
SET balance = balance - 200,&lt;br&gt;
    last_updated = CURRENT_TIMESTAMP&lt;br&gt;
WHERE id = 1&lt;br&gt;
  AND balance &amp;gt;= 200;&lt;/p&gt;

&lt;p&gt;UPDATE accounts&lt;br&gt;
SET balance = balance + 200,&lt;br&gt;
    last_updated = CURRENT_TIMESTAMP&lt;br&gt;
WHERE id = 2;&lt;/p&gt;

&lt;p&gt;COMMIT;&lt;br&gt;
Here, the condition:&lt;/p&gt;

&lt;p&gt;AND balance &amp;gt;= 200&lt;br&gt;
acts as a logical check before updating the account. &lt;/p&gt;

</description>
      <category>backend</category>
      <category>database</category>
      <category>postgres</category>
      <category>sql</category>
    </item>
    <item>
      <title>Atomicity - Design a Reliable Wallet Transfer System with ACID Guarantees</title>
      <dc:creator>Sandhya Steffy M</dc:creator>
      <pubDate>Wed, 25 Mar 2026 12:05:27 +0000</pubDate>
      <link>https://dev.to/sandhya_steffym_4872a8be/atomicity-design-a-reliable-wallet-transfer-system-with-acid-guarantees-1dhf</link>
      <guid>https://dev.to/sandhya_steffym_4872a8be/atomicity-design-a-reliable-wallet-transfer-system-with-acid-guarantees-1dhf</guid>
      <description>&lt;p&gt;In this task, I implemented a simple wallet transfer system to understand the Atomicity property of ACID. Atomicity means that a transaction should either complete fully or not happen at all. There should be no partial updates.&lt;/p&gt;

&lt;p&gt;First, I created a table called accounts to store user details and balance.&lt;/p&gt;

&lt;p&gt;CREATE TABLE accounts (&lt;br&gt;
    id SERIAL PRIMARY KEY,&lt;br&gt;
    name TEXT NOT NULL,&lt;br&gt;
    balance INT NOT NULL CHECK (balance &amp;gt;= 0),&lt;br&gt;
    last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP&lt;br&gt;
);&lt;/p&gt;

&lt;p&gt;Then I inserted some sample data.&lt;/p&gt;

&lt;p&gt;INSERT INTO accounts (name, balance)&lt;br&gt;
VALUES&lt;br&gt;
('Alice', 1000),&lt;br&gt;
('Bob', 500);&lt;/p&gt;

&lt;p&gt;To verify the initial state, I checked the table.&lt;/p&gt;

&lt;p&gt;SELECT * FROM accounts;&lt;/p&gt;

&lt;p&gt;At this point, Alice had 1000 and Bob had 500.&lt;/p&gt;

&lt;p&gt;Next, I performed a successful money transfer of 200 from Alice to Bob using a transaction block.&lt;/p&gt;

&lt;p&gt;BEGIN;&lt;/p&gt;

&lt;p&gt;UPDATE accounts&lt;br&gt;
SET balance = balance - 200,&lt;br&gt;
    last_updated = CURRENT_TIMESTAMP&lt;br&gt;
WHERE id = 1;&lt;/p&gt;

&lt;p&gt;UPDATE accounts&lt;br&gt;
SET balance = balance + 200,&lt;br&gt;
    last_updated = CURRENT_TIMESTAMP&lt;br&gt;
WHERE id = 2;&lt;/p&gt;

&lt;p&gt;COMMIT;&lt;/p&gt;

&lt;p&gt;After executing this, I checked the table again.&lt;/p&gt;

&lt;p&gt;SELECT * FROM accounts;&lt;/p&gt;

&lt;p&gt;Now, Alice’s balance became 800 and Bob’s balance became 700. This shows that both debit and credit operations were completed successfully.&lt;/p&gt;

&lt;p&gt;To test Atomicity, I reset the balances.&lt;/p&gt;

&lt;p&gt;UPDATE accounts SET balance = 1000 WHERE id = 1;&lt;br&gt;
UPDATE accounts SET balance = 500 WHERE id = 2;&lt;/p&gt;

&lt;p&gt;Then I introduced an error during the transaction.&lt;/p&gt;

&lt;p&gt;BEGIN;&lt;/p&gt;

&lt;p&gt;UPDATE accounts&lt;br&gt;
SET balance = balance - 200,&lt;br&gt;
    last_updated = CURRENT_TIMESTAMP&lt;br&gt;
WHERE id = 1;&lt;/p&gt;

&lt;p&gt;-- Intentional error&lt;br&gt;
UPDATE accounts&lt;br&gt;
SET balanc = balance + 200&lt;br&gt;
WHERE id = 2;&lt;/p&gt;

&lt;p&gt;COMMIT;&lt;/p&gt;

&lt;p&gt;The second query fails because the column name is wrong. So the transaction is not completed.&lt;/p&gt;

&lt;p&gt;Now I checked the table again.&lt;/p&gt;

&lt;p&gt;SELECT * FROM accounts;&lt;/p&gt;

&lt;p&gt;I observed that Alice’s balance was still 1000 and Bob’s balance was still 500. Even though the first update was executed, it was not saved.&lt;br&gt;
This clearly shows that PostgreSQL does not allow partial updates. If any step fails, the entire transaction is rolled back.&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>database</category>
      <category>sql</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Users, Roles, Groups</title>
      <dc:creator>Sandhya Steffy M</dc:creator>
      <pubDate>Wed, 25 Mar 2026 11:25:28 +0000</pubDate>
      <link>https://dev.to/sandhya_steffym_4872a8be/users-roles-groups-2aae</link>
      <guid>https://dev.to/sandhya_steffym_4872a8be/users-roles-groups-2aae</guid>
      <description>&lt;p&gt;Task 1: Create a login role report_user that can only read from the film table&lt;/p&gt;

&lt;p&gt;CREATE ROLE report_user WITH LOGIN PASSWORD 'report123';&lt;br&gt;
GRANT SELECT ON film TO report_user;&lt;/p&gt;

&lt;p&gt;Task 2: Now try to access customer table. When report_user tries to query customer and gets permission denied. Fix it.&lt;br&gt;
To allow report_user to read the full customer table:&lt;/p&gt;

&lt;p&gt;GRANT SELECT ON customer TO report_user;&lt;/p&gt;

&lt;p&gt;Task 3: Allow report_user to see only customer_id, first_name, last_name of the customer table&lt;br&gt;
If full SELECT was already given in Task 2, first remove it, then give column-level permission:&lt;/p&gt;

&lt;p&gt;REVOKE SELECT ON customer FROM report_user;&lt;br&gt;
GRANT SELECT (customer_id, first_name, last_name) ON customer TO report_user;&lt;/p&gt;

&lt;p&gt;Task 4: Create support_user who can SELECT from customer, UPDATE only email column, Cannot DELETE&lt;/p&gt;

&lt;p&gt;CREATE ROLE support_user WITH LOGIN PASSWORD 'support123';&lt;br&gt;
GRANT SELECT ON customer TO support_user;&lt;br&gt;
GRANT UPDATE (email) ON customer TO support_user;&lt;/p&gt;

&lt;p&gt;DELETE permission is not given, so support_user cannot delete.&lt;/p&gt;

&lt;p&gt;Task 5: Remove SELECT access on film from report_user&lt;/p&gt;

&lt;p&gt;REVOKE SELECT ON film FROM report_user;&lt;/p&gt;

&lt;p&gt;Task 6: Create readonly_group that has SELECT on all tables&lt;/p&gt;

&lt;p&gt;CREATE ROLE readonly_group;&lt;br&gt;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly_group;&lt;/p&gt;

&lt;p&gt;Task 7: Create analyst1 and analyst2 and add them to readonly_group&lt;/p&gt;

&lt;p&gt;CREATE ROLE analyst1 WITH LOGIN PASSWORD 'analyst123';&lt;br&gt;
CREATE ROLE analyst2 WITH LOGIN PASSWORD 'analyst123';&lt;/p&gt;

&lt;p&gt;GRANT readonly_group TO analyst1;&lt;br&gt;
GRANT readonly_group TO analyst2;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>database</category>
      <category>postgres</category>
      <category>sql</category>
    </item>
    <item>
      <title>Move Zeros</title>
      <dc:creator>Sandhya Steffy M</dc:creator>
      <pubDate>Wed, 25 Mar 2026 11:18:27 +0000</pubDate>
      <link>https://dev.to/sandhya_steffym_4872a8be/move-zeros-1o5p</link>
      <guid>https://dev.to/sandhya_steffym_4872a8be/move-zeros-1o5p</guid>
      <description>&lt;p&gt;When I saw the Move Zeroes problem, it looked very easy, but it needs a small trick to solve it properly. The task is to move all the zero values in an array to the end, without changing the order of the other numbers.&lt;/p&gt;

&lt;p&gt;For example, if the input is [0, 1, 0, 3, 12], the output should be [1, 3, 12, 0, 0]. Here, we are not sorting the array, just shifting zeroes to the end.&lt;/p&gt;

&lt;p&gt;The idea is simple. Instead of thinking about zeroes, we focus on non-zero elements. We take a variable to track the position where the next non-zero value should be placed. Then we go through the array and place all non-zero elements in the front. After that, we fill the remaining positions with zero.&lt;/p&gt;

&lt;p&gt;This method works in-place and does not use extra space. It is also efficient because it only scans the array.&lt;/p&gt;

&lt;p&gt;def moveZeroes(nums):&lt;br&gt;
    index = 0&lt;br&gt;
    for i in range(len(nums)):&lt;br&gt;
        if nums[i] != 0:&lt;br&gt;
            nums[index] = nums[i]&lt;br&gt;
            index += 1&lt;br&gt;
    for i in range(index, len(nums)):&lt;br&gt;
        nums[i] = 0&lt;br&gt;
    return nums&lt;/p&gt;

&lt;p&gt;This problem helped me understand how to handle arrays efficiently and think in a better way while solving problems.&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>beginners</category>
      <category>dsa</category>
      <category>leetcode</category>
    </item>
    <item>
      <title>Users, Roles, Groups</title>
      <dc:creator>Sandhya Steffy M</dc:creator>
      <pubDate>Tue, 24 Mar 2026 17:13:44 +0000</pubDate>
      <link>https://dev.to/sandhya_steffym_4872a8be/users-roles-groups-20k7</link>
      <guid>https://dev.to/sandhya_steffym_4872a8be/users-roles-groups-20k7</guid>
      <description>&lt;p&gt;Task 1:Create a login role report_user that can only read from the film table&lt;br&gt;
CREATE ROLE report_user WITH LOGIN PASSWORD 'report123';&lt;/p&gt;

&lt;p&gt;GRANT SELECT ON film TO report_user;&lt;br&gt;
Here, we first create a new login role named report_user.&lt;br&gt;
Then we give only SELECT permission on the film table, so this user can only read that table.&lt;/p&gt;

&lt;p&gt;Task 2: Now try to access customer table. When report_user tries to query customer and gets permission denied. Fix it&lt;br&gt;
GRANT SELECT ON customer TO report_user;&lt;br&gt;
The error happens because report_user was not given permission on the customer table.&lt;br&gt;
So we fix it by granting SELECT access on customer.&lt;/p&gt;

&lt;p&gt;Task 3: Allow report_user to see only customer_id, first_name, last_name of the customer table&lt;br&gt;
REVOKE SELECT ON customer FROM report_user;&lt;/p&gt;

&lt;p&gt;GRANT SELECT (customer_id, first_name, last_name)&lt;br&gt;
ON customer&lt;br&gt;
TO report_user;&lt;br&gt;
If we want the user to see only some columns, full table access should be removed first.&lt;br&gt;
Then column-level SELECT permission is given only for the required columns.&lt;/p&gt;

&lt;p&gt;Task 4: Create support_user who can SELECT from customer, UPDATE only email column, and cannot DELETE&lt;br&gt;
CREATE ROLE support_user WITH LOGIN PASSWORD 'support123';&lt;/p&gt;

&lt;p&gt;GRANT SELECT ON customer TO support_user;&lt;/p&gt;

&lt;p&gt;GRANT UPDATE (email) ON customer TO support_user;&lt;br&gt;
This user should be able to read customer details and change only the email column.&lt;br&gt;
Since we do not give DELETE permission, the user cannot delete any row.&lt;/p&gt;

&lt;p&gt;Task 5: Remove SELECT access on film from report_user&lt;br&gt;
REVOKE SELECT ON film FROM report_user;&lt;br&gt;
Earlier, report_user was allowed to read from film.&lt;br&gt;
Now this command removes that permission.&lt;/p&gt;

&lt;p&gt;Task 6: Create readonly_group that has SELECT on all tables&lt;br&gt;
CREATE ROLE readonly_group;&lt;/p&gt;

&lt;p&gt;GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly_group;&lt;br&gt;
Here, readonly_group acts like a common read-only role.&lt;br&gt;
Anyone added to this group will get SELECT access on all tables in the public schema.&lt;/p&gt;

&lt;p&gt;Task 7: Create analyst1 and analyst2 and add them to readonly_group&lt;br&gt;
CREATE ROLE analyst1 WITH LOGIN PASSWORD 'analyst123';&lt;br&gt;
CREATE ROLE analyst2 WITH LOGIN PASSWORD 'analyst123';&lt;/p&gt;

&lt;p&gt;GRANT readonly_group TO analyst1;&lt;br&gt;
GRANT readonly_group TO analyst2;&lt;br&gt;
First, we create two login users.&lt;br&gt;
Then we add both of them to readonly_group,so they automatically get all read-only permissions of that group.&lt;/p&gt;

</description>
      <category>database</category>
      <category>postgres</category>
      <category>sql</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Bonus Q/A</title>
      <dc:creator>Sandhya Steffy M</dc:creator>
      <pubDate>Tue, 24 Mar 2026 16:41:17 +0000</pubDate>
      <link>https://dev.to/sandhya_steffym_4872a8be/bonus-qa-4o1k</link>
      <guid>https://dev.to/sandhya_steffym_4872a8be/bonus-qa-4o1k</guid>
      <description>&lt;p&gt;1.&lt;/p&gt;

&lt;p&gt;SELECT title, special_features&lt;br&gt;
FROM film&lt;br&gt;
WHERE special_features IS NULL;&lt;br&gt;
This question is asking us to find movies where no special feature is given at all.&lt;br&gt;
So instead of checking for empty text, we use IS NULL because NULL means “no value stored”.&lt;/p&gt;

&lt;p&gt;2.&lt;/p&gt;

&lt;p&gt;SELECT title, rental_duration&lt;br&gt;
FROM film&lt;br&gt;
WHERE rental_duration &amp;gt; 7;&lt;br&gt;
Here we only want movies whose rental duration is greater than 7 days.&lt;br&gt;
So we simply filter the rows using the &amp;gt; operator.&lt;/p&gt;

&lt;p&gt;3.&lt;/p&gt;

&lt;p&gt;SELECT title, rental_rate, replacement_cost&lt;br&gt;
FROM film&lt;br&gt;
WHERE rental_rate = 4.99&lt;br&gt;
  AND replacement_cost &amp;gt; 20;&lt;br&gt;
This question has two conditions, and both must be true at the same time.&lt;br&gt;
That is why we use AND to combine rental rate and replacement cost.&lt;/p&gt;

&lt;p&gt;4.&lt;/p&gt;

&lt;p&gt;SELECT title, rental_rate, rating&lt;br&gt;
FROM film&lt;br&gt;
WHERE rental_rate = 0.99&lt;br&gt;
   OR rating = 'PG-13';&lt;br&gt;
Here the movie can satisfy either one condition or the other.&lt;br&gt;
So we use OR because even if one part matches, the row should come.&lt;/p&gt;

&lt;p&gt;5.&lt;/p&gt;

&lt;p&gt;SELECT title&lt;br&gt;
FROM film&lt;br&gt;
ORDER BY title ASC&lt;br&gt;
LIMIT 5;&lt;br&gt;
First, the movies must be arranged in alphabetical order by title.&lt;br&gt;
After sorting, LIMIT 5 gives only the first 5 rows.&lt;/p&gt;

&lt;p&gt;6.&lt;/p&gt;

&lt;p&gt;SELECT title, replacement_cost&lt;br&gt;
FROM film&lt;br&gt;
ORDER BY replacement_cost DESC&lt;br&gt;
OFFSET 10&lt;br&gt;
LIMIT 3;&lt;br&gt;
This question says to skip the first 10 rows, then take the next 3.&lt;br&gt;
So we sort first, then use OFFSET 10 and LIMIT 3.&lt;/p&gt;

&lt;p&gt;7.&lt;/p&gt;

&lt;p&gt;SELECT title, rating&lt;br&gt;
FROM film&lt;br&gt;
WHERE rating IN ('G', 'PG', 'PG-13');&lt;br&gt;
Instead of writing many OR conditions, we can use IN.&lt;br&gt;
It makes the query shorter and easier to read when checking multiple values.&lt;/p&gt;

&lt;p&gt;8.&lt;/p&gt;

&lt;p&gt;SELECT title, rental_rate&lt;br&gt;
FROM film&lt;br&gt;
WHERE rental_rate BETWEEN 2 AND 4;&lt;br&gt;
The word “between” clearly tells us to use the BETWEEN operator.&lt;br&gt;
This checks whether the rental rate is inside the range from 2 to 4.&lt;/p&gt;

&lt;p&gt;9.&lt;/p&gt;

&lt;p&gt;SELECT title&lt;br&gt;
FROM film&lt;br&gt;
WHERE title LIKE 'The%';&lt;br&gt;
If the title starts with “The”, then “The” must come at the beginning.&lt;br&gt;
So we use LIKE 'The%', where % means anything can come after it.&lt;/p&gt;

&lt;p&gt;10.&lt;/p&gt;

&lt;p&gt;SELECT title, rental_rate, rating&lt;br&gt;
FROM film&lt;br&gt;
WHERE rental_rate IN (2.99, 4.99)&lt;br&gt;
  AND rating = 'R'&lt;br&gt;
  AND title ILIKE '%Love%'&lt;br&gt;
LIMIT 10;&lt;br&gt;
This question combines many filters together, so all of them must match.&lt;br&gt;
ILIKE is useful here because it checks for the word “Love” without worrying about uppercase or lowercase.&lt;/p&gt;

&lt;p&gt;11.&lt;/p&gt;

&lt;p&gt;SELECT title&lt;br&gt;
FROM film&lt;br&gt;
WHERE title LIKE '%\%%' ESCAPE '\';&lt;br&gt;
Normally % is treated as a wildcard in LIKE, not as a real symbol.&lt;br&gt;
So we use ESCAPE '\' to tell SQL that here % should be treated as an actual character.&lt;/p&gt;

&lt;p&gt;12.&lt;/p&gt;

&lt;p&gt;SELECT title&lt;br&gt;
FROM film&lt;br&gt;
WHERE title LIKE '%_%' ESCAPE '\';&lt;br&gt;
The underscore _ is also a wildcard in LIKE, for one character.&lt;br&gt;
So we escape it to search for a real underscore symbol inside the title.&lt;/p&gt;

&lt;p&gt;13.&lt;/p&gt;

&lt;p&gt;SELECT title&lt;br&gt;
FROM film&lt;br&gt;
WHERE (title LIKE 'A%s' OR title LIKE 'B%s');&lt;br&gt;
The title must begin with either A or B, and it must end with s.&lt;br&gt;
So we write two patterns and join them using OR.&lt;/p&gt;

&lt;p&gt;14.&lt;/p&gt;

&lt;p&gt;SELECT title&lt;br&gt;
FROM film&lt;br&gt;
WHERE title ILIKE '%Man%'&lt;br&gt;
   OR title ILIKE '%Men%'&lt;br&gt;
   OR title ILIKE '%Woman%';&lt;br&gt;
This question wants titles containing any one of these words.&lt;br&gt;
So we check each word separately and connect them using OR.&lt;/p&gt;

&lt;p&gt;15.&lt;/p&gt;

&lt;p&gt;SELECT title&lt;br&gt;
FROM film&lt;br&gt;
WHERE title ~ '[0-9]';&lt;br&gt;
Here we need titles that contain numbers anywhere inside them.&lt;br&gt;
The regex [0-9] means “any digit from 0 to 9”.&lt;/p&gt;

&lt;p&gt;16.&lt;/p&gt;

&lt;p&gt;SELECT title&lt;br&gt;
FROM film&lt;br&gt;
WHERE title LIKE '%\%' ESCAPE '\';&lt;br&gt;
Since backslash is a special escape character, searching for it is a little tricky.&lt;br&gt;
So we escape it properly to make SQL look for a real \ inside the title.&lt;/p&gt;

&lt;p&gt;17.&lt;/p&gt;

&lt;p&gt;SELECT title&lt;br&gt;
FROM film&lt;br&gt;
WHERE title ILIKE '%Love%'&lt;br&gt;
   OR title ILIKE '%Hate%';&lt;br&gt;
This question asks for movies whose titles contain either “Love” or “Hate”.&lt;br&gt;
So we search for both words and use OR because either one is enough.&lt;/p&gt;

&lt;p&gt;18.&lt;/p&gt;

&lt;p&gt;SELECT title&lt;br&gt;
FROM film&lt;br&gt;
WHERE title ILIKE '%er'&lt;br&gt;
   OR title ILIKE '%or'&lt;br&gt;
   OR title ILIKE '%ar'&lt;br&gt;
LIMIT 5;&lt;br&gt;
The question is asking for titles that end with specific letter combinations.&lt;br&gt;
So we use patterns ending in er, or, or ar, and then take only the first 5 rows.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>database</category>
      <category>sql</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>DB-TASK-001</title>
      <dc:creator>Sandhya Steffy M</dc:creator>
      <pubDate>Tue, 24 Mar 2026 15:37:29 +0000</pubDate>
      <link>https://dev.to/sandhya_steffym_4872a8be/db-task-001-3lil</link>
      <guid>https://dev.to/sandhya_steffym_4872a8be/db-task-001-3lil</guid>
      <description>&lt;ol&gt;
&lt;li&gt;Retrieving Data with Column Aliases
Sometimes, column names in tables are not user-friendly. So, we can rename them using aliases.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;SELECT title AS "Movie Title", rental_rate AS "Rate"&lt;br&gt;
FROM film;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Displaying Customer Details
We can also rename customer details to make them clear.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;SELECT first_name AS "First Name", last_name AS "Last Name", email&lt;br&gt;
FROM customer;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Sorting Data (ORDER BY)
Sorting helps us organize data.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;SELECT title, rental_rate&lt;br&gt;
FROM film&lt;br&gt;
ORDER BY rental_rate DESC, title ASC;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Sorting Actor Names&lt;br&gt;
SELECT first_name, last_name&lt;br&gt;
FROM actor&lt;br&gt;
ORDER BY last_name, first_name;&lt;br&gt;
This sorts actors by last name first.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using DISTINCT (Unique Values)&lt;br&gt;
To avoid duplicates, we use DISTINCT.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;SELECT DISTINCT replacement_cost&lt;br&gt;
FROM film;&lt;br&gt;
This shows only unique values.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Showing Film Duration&lt;br&gt;
SELECT title, length AS "Duration (min)"&lt;br&gt;
FROM film;&lt;br&gt;
Here, length is renamed to make it clearer.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Customer Active Status&lt;br&gt;
SELECT first_name, last_name, active AS "Is Active"&lt;br&gt;
FROM customer;&lt;br&gt;
This shows whether a customer is active or not.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Film Categories Sorted&lt;br&gt;
SELECT name&lt;br&gt;
FROM category&lt;br&gt;
ORDER BY name;&lt;br&gt;
This displays categories alphabetically.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sorting Films by Length&lt;br&gt;
SELECT title, length&lt;br&gt;
FROM film&lt;br&gt;
ORDER BY length DESC;&lt;br&gt;
This shows longest movies first.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sorting Actors in Reverse Order&lt;br&gt;
SELECT first_name, last_name&lt;br&gt;
FROM actor&lt;br&gt;
ORDER BY first_name DESC;&lt;br&gt;
11 &amp;amp; 12. Unique Ratings and Rental Durations&lt;br&gt;
SELECT DISTINCT rating FROM film;&lt;br&gt;
SELECT DISTINCT rental_duration FROM film;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Unique Customer Based on Status&lt;br&gt;
SELECT DISTINCT ON (active) customer_id, active&lt;br&gt;
FROM customer&lt;br&gt;
ORDER BY active, customer_id;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Earliest Rental Date for Each Customer&lt;br&gt;
SELECT customer_id, MIN(rental_date) AS rental_date&lt;br&gt;
FROM rental&lt;br&gt;
GROUP BY customer_id&lt;br&gt;
ORDER BY customer_id;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Shortest Films&lt;br&gt;
SELECT title, length&lt;br&gt;
FROM film&lt;br&gt;
ORDER BY length ASC&lt;br&gt;
LIMIT 10;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Top 5 Customers&lt;br&gt;
SELECT first_name, last_name&lt;br&gt;
FROM customer&lt;br&gt;
ORDER BY customer_id DESC&lt;br&gt;
LIMIT 5;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Unique Store IDs&lt;br&gt;
SELECT DISTINCT store_id&lt;br&gt;
FROM inventory;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sorted Replacement Cost&lt;br&gt;
SELECT DISTINCT replacement_cost&lt;br&gt;
FROM film&lt;br&gt;
ORDER BY replacement_cost;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;First Rental Date Per Store&lt;br&gt;
SELECT store_id, MIN(rental_date)&lt;br&gt;
FROM rental&lt;br&gt;
GROUP BY store_id&lt;br&gt;
ORDER BY store_id;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Unique Ratings Sorted&lt;br&gt;
SELECT DISTINCT rating&lt;br&gt;
FROM film&lt;br&gt;
ORDER BY rating;&lt;br&gt;
21.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;SELECT title, rating, length&lt;br&gt;
FROM film&lt;br&gt;
ORDER BY rating ASC, length DESC;&lt;br&gt;
22.&lt;/p&gt;

&lt;p&gt;SELECT first_name, last_name&lt;br&gt;
FROM actor&lt;br&gt;
ORDER BY last_name ASC, first_name DESC;&lt;br&gt;
23.&lt;/p&gt;

&lt;p&gt;SELECT title, replacement_cost, rental_rate&lt;br&gt;
FROM film&lt;br&gt;
ORDER BY replacement_cost ASC, rental_rate DESC;&lt;br&gt;
24.&lt;/p&gt;

&lt;p&gt;SELECT first_name, last_name&lt;br&gt;
FROM customer&lt;br&gt;
ORDER BY last_name ASC, first_name DESC;&lt;br&gt;
25.&lt;/p&gt;

&lt;p&gt;SELECT *&lt;br&gt;
FROM rental&lt;br&gt;
ORDER BY customer_id ASC, rental_date DESC;&lt;br&gt;
26.&lt;/p&gt;

&lt;p&gt;SELECT title, rental_duration&lt;br&gt;
FROM film&lt;br&gt;
ORDER BY rental_duration ASC, title DESC;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>database</category>
      <category>sql</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
