Converting procedural loops into efficient declarative SQL queries is a great way to improve performance, readability, and maintainability in your database code. In SQL, you avoid using explicit loops and instead rely on set-based operations, which are generally more efficient than row-by-row operations. Here are a few examples of how you can make this conversion:
1. Sum a Series of Values
Procedural Approach (Using Loop):
DECLARE @total INT = 0;
DECLARE @i INT = 1;
WHILE @i <= 10
BEGIN
SET @total = @total + @i;
SET @i = @i + 1;
END
SELECT @total;
Declarative Approach (Using SQL):
SELECT SUM(number) AS total
FROM (VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)) AS numbers(number);
2. Updating Rows Based on Condition
Procedural Approach (Using Loop):
DECLARE @id INT;
DECLARE @newValue INT;
DECLARE cursor_example CURSOR FOR
SELECT id FROM my_table WHERE status = 'active';
OPEN cursor_example;
FETCH NEXT FROM cursor_example INTO @id;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @newValue = @id * 10;
UPDATE my_table
SET value = @newValue
WHERE id = @id;
FETCH NEXT FROM cursor_example INTO @id;
END
CLOSE cursor_example;
DEALLOCATE cursor_example;
Declarative Approach (Using SQL):
UPDATE my_table
SET value = id * 10
WHERE status = 'active';
3. Iterating Over Data to Perform Aggregation
Procedural Approach (Using Loop):
DECLARE @sum INT = 0;
DECLARE @value INT;
DECLARE cursor_example CURSOR FOR
SELECT amount FROM transactions;
OPEN cursor_example;
FETCH NEXT FROM cursor_example INTO @value;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @sum = @sum + @value;
FETCH NEXT FROM cursor_example INTO @value;
END
CLOSE cursor_example;
DEALLOCATE cursor_example;
SELECT @sum AS total_sum;
Declarative Approach (Using SQL):
SELECT SUM(amount) AS total_sum
FROM transactions;
4. Inserting Data into Another Table with Transformations
Procedural Approach (Using Loop):
DECLARE @id INT;
DECLARE @value INT;
DECLARE cursor_example CURSOR FOR
SELECT id, value FROM old_table;
OPEN cursor_example;
FETCH NEXT FROM cursor_example INTO @id, @value;
WHILE @@FETCH_STATUS = 0
BEGIN
INSERT INTO new_table (id, transformed_value)
VALUES (@id, @value * 2);
FETCH NEXT FROM cursor_example INTO @id, @value;
END
CLOSE cursor_example;
DEALLOCATE cursor_example;
Declarative Approach (Using SQL):
INSERT INTO new_table (id, transformed_value)
SELECT id, value * 2
FROM old_table;
5. Removing Duplicate Rows
Procedural Approach (Using Loop):
DECLARE @id INT;
DECLARE cursor_example CURSOR FOR
SELECT DISTINCT id FROM my_table;
OPEN cursor_example;
FETCH NEXT FROM cursor_example INTO @id;
WHILE @@FETCH_STATUS = 0
BEGIN
DELETE FROM my_table
WHERE id = @id AND row_id NOT IN (
SELECT MIN(row_id)
FROM my_table
WHERE id = @id
GROUP BY id
);
FETCH NEXT FROM cursor_example INTO @id;
END
CLOSE cursor_example;
DEALLOCATE cursor_example;
Declarative Approach (Using SQL):
WITH CTE AS (
SELECT id, ROW_NUMBER() OVER (PARTITION BY id ORDER BY row_id) AS rn
FROM my_table
)
DELETE FROM my_table
WHERE row_id IN (SELECT row_id FROM CTE WHERE rn > 1);
Key Takeaways:
- Procedural loops often iterate over rows, one at a time. In SQL, this is inefficient because SQL is optimized for working with sets of data at once.
- The declarative SQL approach leverages set-based operations like
UPDATE
,INSERT
,SELECT
, andDELETE
that work with entire sets of rows in a single operation. - By avoiding cursors and loops, declarative SQL can significantly improve performance, especially for large datasets.
By converting your procedural logic into set-based SQL queries, you ensure the code is optimized for the relational database's capabilities, which are designed for set processing rather than row-by-row iteration.
No comments:
Post a Comment