<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>SQL &#8211; Bits of .NET</title>
	<atom:link href="http://blog.ercanopak.com/category/sql/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.ercanopak.com</link>
	<description>Daily micro-tips for C#, SQL, performance, and scalable backend engineering.</description>
	<lastBuildDate>Mon, 30 Mar 2026 17:51:53 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>http://blog.ercanopak.com/wp-content/uploads/2018/06/cropped-EO_LOGO_32-32x32.png</url>
	<title>SQL &#8211; Bits of .NET</title>
	<link>http://blog.ercanopak.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>SQL: Use CTEs for Readable Complex Queries</title>
		<link>http://blog.ercanopak.com/sql-use-ctes-for-readable-complex-queries-2/</link>
					<comments>http://blog.ercanopak.com/sql-use-ctes-for-readable-complex-queries-2/#respond</comments>
		
		<dc:creator><![CDATA[ErcanOPAK]]></dc:creator>
		<pubDate>Mon, 30 Mar 2026 17:51:53 +0000</pubDate>
				<category><![CDATA[SQL]]></category>
		<category><![CDATA[Advanced SQL]]></category>
		<category><![CDATA[Common Table Expressions]]></category>
		<category><![CDATA[cte]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[Query Readability]]></category>
		<category><![CDATA[Recursive CTE]]></category>
		<category><![CDATA[SQL Best Practices]]></category>
		<category><![CDATA[SQL Tips]]></category>
		<category><![CDATA[WITH Clause]]></category>
		<guid isPermaLink="false">http://blog.ercanopak.com/sql-use-ctes-for-readable-complex-queries-2/</guid>

					<description><![CDATA[📝 Named Subqueries Nested subqueries everywhere? Can&#8217;t understand your own query? CTEs (WITH clause) create temporary named result sets. Makes complex queries readable. The Subquery Nightmare -- ❌ Nested subqueries - Unreadable! SELECT customer_name, total_orders, avg_order_value FROM ( SELECT c.name AS customer_name, COUNT(o.id) AS total_orders, AVG(o.total) AS avg_order_value FROM customers c JOIN ( SELECT * [&#8230;]]]></description>
										<content:encoded><![CDATA[<div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 50px 40px; border-radius: 16px; margin: 40px 0; box-shadow: 0 20px 60px rgba(0,0,0,0.3);">
<h2 style="margin: 0 0 20px 0; font-size: 2.8em; font-weight: 800; line-height: 1.2;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4dd.png" alt="📝" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Named Subqueries</h2>
<p style="font-size: 1.4em; line-height: 1.8; margin: 0; opacity: 0.95;">Nested subqueries everywhere? Can&#8217;t understand your own query? <strong>CTEs (WITH clause)</strong> create temporary named result sets. Makes complex queries readable.</p>
</p></div>
<h3 style="color: #2c3e50; font-size: 2.2em; margin: 50px 0 30px 0; font-weight: 700; border-left: 5px solid #764ba2; padding-left: 20px;">The Subquery Nightmare</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">
-- <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Nested subqueries - Unreadable!
SELECT 
  customer_name,
  total_orders,
  avg_order_value
FROM (
  SELECT 
    c.name AS customer_name,
    COUNT(o.id) AS total_orders,
    AVG(o.total) AS avg_order_value
  FROM customers c
  JOIN (
    SELECT * 
    FROM orders 
    WHERE status = 'completed'
  ) o ON c.id = o.customer_id
  WHERE c.created_at > '2024-01-01'
  GROUP BY c.id, c.name
) customer_stats
WHERE total_orders > 5
ORDER BY avg_order_value DESC;

-- Hard to read, maintain, debug
</pre>
<h3 style="color: #2c3e50; font-size: 2.2em; margin: 50px 0 30px 0; font-weight: 700; border-left: 5px solid #27ae60; padding-left: 20px;">CTE Solution &#8211; Clean &#038; Readable</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">
-- <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> CTE - Step by step, readable
WITH completed_orders AS (
  SELECT * 
  FROM orders 
  WHERE status = 'completed'
),
recent_customers AS (
  SELECT * 
  FROM customers 
  WHERE created_at > '2024-01-01'
),
customer_stats AS (
  SELECT 
    c.id,
    c.name AS customer_name,
    COUNT(o.id) AS total_orders,
    AVG(o.total) AS avg_order_value
  FROM recent_customers c
  JOIN completed_orders o ON c.id = o.customer_id
  GROUP BY c.id, c.name
)
SELECT 
  customer_name,
  total_orders,
  avg_order_value
FROM customer_stats
WHERE total_orders > 5
ORDER BY avg_order_value DESC;

-- Each step has a name!
-- Easy to understand flow
-- Easy to debug each CTE separately
</pre>
<div style="background: #f8f9fa; padding: 40px; border-radius: 12px; margin: 40px 0; border: 2px solid #667eea;">
<h4 style="color: #667eea; margin-top: 0; font-size: 1.7em; font-weight: 700;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f3af.png" alt="🎯" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Multiple CTEs</h4>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">
-- Define multiple CTEs with comma separation
WITH 
-- CTE 1: Sales by product
product_sales AS (
  SELECT 
    product_id,
    SUM(quantity) AS total_quantity,
    SUM(total_price) AS total_revenue
  FROM order_items
  WHERE order_date >= '2024-01-01'
  GROUP BY product_id
),
-- CTE 2: Top products
top_products AS (
  SELECT 
    product_id,
    total_revenue
  FROM product_sales
  WHERE total_revenue > 10000
),
-- CTE 3: Product details
product_details AS (
  SELECT 
    p.id,
    p.name,
    p.category,
    tp.total_revenue
  FROM products p
  JOIN top_products tp ON p.id = tp.product_id
)
-- Final query uses all CTEs
SELECT 
  category,
  COUNT(*) AS product_count,
  SUM(total_revenue) AS category_revenue
FROM product_details
GROUP BY category
ORDER BY category_revenue DESC;
</pre>
</p></div>
<h3 style="color: #2c3e50; font-size: 2.2em; margin: 50px 0 30px 0; font-weight: 700; border-left: 5px solid #f39c12; padding-left: 20px;">Recursive CTEs</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">
-- Hierarchical data: Employee org chart
WITH RECURSIVE employee_hierarchy AS (
  -- Base case: Top-level managers (no manager)
  SELECT 
    id,
    name,
    manager_id,
    1 AS level,
    name AS path
  FROM employees
  WHERE manager_id IS NULL
  
  UNION ALL
  
  -- Recursive case: Employees with managers
  SELECT 
    e.id,
    e.name,
    e.manager_id,
    eh.level + 1,
    eh.path || ' > ' || e.name
  FROM employees e
  JOIN employee_hierarchy eh ON e.manager_id = eh.id
)
SELECT 
  id,
  name,
  level,
  path
FROM employee_hierarchy
ORDER BY level, name;

-- Result:
-- id | name    | level | path
-- 1  | CEO     | 1     | CEO
-- 2  | CTO     | 2     | CEO > CTO
-- 3  | CFO     | 2     | CEO > CFO
-- 4  | Dev1    | 3     | CEO > CTO > Dev1
-- 5  | Dev2    | 3     | CEO > CTO > Dev2
</pre>
<div style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); color: white; padding: 35px; border-radius: 12px; margin: 40px 0;">
<h4 style="margin-top: 0; font-size: 1.7em; font-weight: 700;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f504.png" alt="🔄" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Generate Number Series</h4>
<pre style="background: rgba(0,0,0,0.3); color: #fff; padding: 25px; border-radius: 8px; font-size: 1.05em; line-height: 1.8;">
-- Generate numbers 1 to 100
WITH RECURSIVE numbers AS (
  SELECT 1 AS n
  UNION ALL
  SELECT n + 1
  FROM numbers
  WHERE n < 100
)
SELECT n FROM numbers;

-- Generate date range
WITH RECURSIVE date_range AS (
  SELECT DATE('2024-01-01') AS date
  UNION ALL
  SELECT DATE(date, '+1 day')
  FROM date_range
  WHERE date < '2024-12-31'
)
SELECT date FROM date_range;

-- Use case: Fill gaps in data
WITH RECURSIVE all_months AS (
  SELECT DATE('2024-01-01') AS month
  UNION ALL
  SELECT DATE(month, '+1 month')
  FROM all_months
  WHERE month < '2024-12-01'
)
SELECT 
  am.month,
  COALESCE(s.revenue, 0) AS revenue
FROM all_months am
LEFT JOIN monthly_sales s ON am.month = s.month;
</pre>
</p></div>
<h3 style="color: #2c3e50; font-size: 2.2em; margin: 50px 0 30px 0; font-weight: 700; border-left: 5px solid #667eea; padding-left: 20px;">Real-World Examples</h3>
<div style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); color: white; padding: 35px; border-radius: 12px; margin: 40px 0;">
<h4 style="margin-top: 0; font-size: 1.7em; font-weight: 700;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4ca.png" alt="📊" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Dashboard Query</h4>
<pre style="background: rgba(0,0,0,0.3); color: #fff; padding: 25px; border-radius: 8px; font-size: 1.05em; line-height: 1.8;">
WITH 
-- Today's sales
today_sales AS (
  SELECT SUM(total) AS today_total
  FROM orders
  WHERE DATE(created_at) = CURRENT_DATE
),
-- Yesterday's sales
yesterday_sales AS (
  SELECT SUM(total) AS yesterday_total
  FROM orders
  WHERE DATE(created_at) = CURRENT_DATE - INTERVAL '1 day'
),
-- This month's sales
month_sales AS (
  SELECT SUM(total) AS month_total
  FROM orders
  WHERE DATE_TRUNC('month', created_at) = DATE_TRUNC('month', CURRENT_DATE)
),
-- Active users today
active_users AS (
  SELECT COUNT(DISTINCT user_id) AS active_count
  FROM user_sessions
  WHERE DATE(created_at) = CURRENT_DATE
)
-- Combine all metrics
SELECT 
  ts.today_total,
  ys.yesterday_total,
  ts.today_total - ys.yesterday_total AS daily_change,
  ms.month_total,
  au.active_count
FROM today_sales ts, yesterday_sales ys, month_sales ms, active_users au;
</pre>
</p></div>
<div style="background: linear-gradient(135deg, #d4edda 0%, #c3e6cb 100%); padding: 35px; border-radius: 12px; margin: 40px 0; border-left: 5px solid #28a745;">
<h4 style="color: #155724; margin-top: 0; font-size: 1.7em; font-weight: 700;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Benefits of CTEs</h4>
<ul style="color: #155724; font-size: 1.15em; line-height: 2.2; margin: 20px 0;">
<li><strong>Readability:</strong> Named steps are self-documenting</li>
<li><strong>Maintainability:</strong> Easy to modify individual steps</li>
<li><strong>Debugging:</strong> Test each CTE separately</li>
<li><strong>Reusability:</strong> Reference same CTE multiple times</li>
<li><strong>Recursion:</strong> Handle hierarchical data</li>
</ul></div>
<div style="background: linear-gradient(135deg, #fff3cd 0%, #ffe69c 100%); border-left: 5px solid #ffc107; padding: 35px; margin: 50px 0; border-radius: 12px;">
<h4 style="color: #856404; margin-top: 0; font-size: 1.7em; font-weight: 700;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Pro Tips</h4>
<ul style="color: #856404; font-size: 1.15em; line-height: 2.2; margin: 20px 0;">
<li><strong>Name meaningfully:</strong> recent_customers, not temp1</li>
<li><strong>One CTE per logical step:</strong> Don't try to do everything in one</li>
<li><strong>Debug incrementally:</strong> Run each CTE separately first</li>
<li><strong>Consider performance:</strong> CTEs not always faster than subqueries</li>
<li><strong>Use for recursion:</strong> Perfect for trees, graphs</li>
</ul></div>
<blockquote style="background: linear-gradient(to right, #e8eaf6, #c5cae9); border-left: 6px solid #5c6bc0; padding: 40px; margin: 50px 0; border-radius: 12px;">
<p style="font-size: 1.5em; line-height: 1.9; margin: 0; color: #1a237e; font-style: italic; font-weight: 500;">"Inherited 200-line query with 7 levels of nested subqueries. Couldn't understand it. Rewrote with CTEs. Now 15 named steps, crystal clear. Junior dev understood it immediately."</p>
<footer style="margin-top: 20px; color: #283593; font-size: 1.15em; font-weight: 600;">— Database Developer</footer>
</blockquote>
]]></content:encoded>
					
					<wfw:commentRss>http://blog.ercanopak.com/sql-use-ctes-for-readable-complex-queries-2/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>SQL: Use Window Functions for Advanced Analytical Queries</title>
		<link>http://blog.ercanopak.com/sql-use-window-functions-for-advanced-analytical-queries/</link>
					<comments>http://blog.ercanopak.com/sql-use-window-functions-for-advanced-analytical-queries/#respond</comments>
		
		<dc:creator><![CDATA[ErcanOPAK]]></dc:creator>
		<pubDate>Mon, 30 Mar 2026 17:51:47 +0000</pubDate>
				<category><![CDATA[SQL]]></category>
		<category><![CDATA[Advanced SQL]]></category>
		<category><![CDATA[analytics]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[Query Optimization]]></category>
		<category><![CDATA[RANK]]></category>
		<category><![CDATA[row_number]]></category>
		<category><![CDATA[sql server]]></category>
		<category><![CDATA[SQL Tips]]></category>
		<category><![CDATA[Window Functions]]></category>
		<guid isPermaLink="false">http://blog.ercanopak.com/sql-use-window-functions-for-advanced-analytical-queries/</guid>

					<description><![CDATA[📊 SQL Superpowers Need row numbers? Running totals? Rankings? Window functions perform calculations across table rows without GROUP BY. Game-changing for analytics. ROW_NUMBER() &#8211; Assign Row Numbers -- ❌ Old way: Can't number rows easily SELECT name, salary, department FROM employees ORDER BY salary DESC; -- ✅ Window function: Add row numbers SELECT ROW_NUMBER() OVER [&#8230;]]]></description>
										<content:encoded><![CDATA[<div style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); color: white; padding: 50px 40px; border-radius: 16px; margin: 40px 0; box-shadow: 0 20px 60px rgba(0,0,0,0.3);">
<h2 style="margin: 0 0 20px 0; font-size: 2.8em; font-weight: 800; line-height: 1.2;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4ca.png" alt="📊" class="wp-smiley" style="height: 1em; max-height: 1em;" /> SQL Superpowers</h2>
<p style="font-size: 1.4em; line-height: 1.8; margin: 0; opacity: 0.95;">Need row numbers? Running totals? Rankings? <strong>Window functions</strong> perform calculations across table rows without GROUP BY. Game-changing for analytics.</p>
</p></div>
<h3 style="color: #2c3e50; font-size: 2.2em; margin: 50px 0 30px 0; font-weight: 700; border-left: 5px solid #00f2fe; padding-left: 20px;">ROW_NUMBER() &#8211; Assign Row Numbers</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">
-- <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Old way: Can't number rows easily
SELECT name, salary, department
FROM employees
ORDER BY salary DESC;

-- <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Window function: Add row numbers
SELECT 
  ROW_NUMBER() OVER (ORDER BY salary DESC) AS row_num,
  name,
  salary,
  department
FROM employees;

-- Result:
-- row_num | name    | salary | department
-- 1       | Alice   | 120000 | Engineering
-- 2       | Bob     | 110000 | Engineering
-- 3       | Charlie | 100000 | Sales
-- 4       | David   | 95000  | Marketing

-- Row number per department
SELECT 
  ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS dept_rank,
  name,
  salary,
  department
FROM employees;

-- Result: Separate numbering per department
-- dept_rank | name    | salary | department
-- 1         | Alice   | 120000 | Engineering
-- 2         | Bob     | 110000 | Engineering
-- 1         | Charlie | 100000 | Sales
-- 1         | David   | 95000  | Marketing
</pre>
<div style="background: #f8f9fa; padding: 40px; border-radius: 12px; margin: 40px 0; border: 2px solid #4facfe;">
<h4 style="color: #00f2fe; margin-top: 0; font-size: 1.7em; font-weight: 700;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4c8.png" alt="📈" class="wp-smiley" style="height: 1em; max-height: 1em;" /> RANK() and DENSE_RANK()</h4>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">
-- RANK() - Gaps in ranking for ties
SELECT 
  RANK() OVER (ORDER BY score DESC) AS rank,
  name,
  score
FROM students;

-- score: 100, 100, 95, 90
-- rank:  1,   1,   3,  4  (gap at 2!)

-- DENSE_RANK() - No gaps
SELECT 
  DENSE_RANK() OVER (ORDER BY score DESC) AS rank,
  name,
  score
FROM students;

-- score: 100, 100, 95, 90
-- rank:  1,   1,   2,  3  (no gap)

-- Top 3 salaries per department
SELECT *
FROM (
  SELECT 
    name,
    salary,
    department,
    RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dept_rank
  FROM employees
) ranked
WHERE dept_rank <= 3;
</pre>
</p></div>
<h3 style="color: #2c3e50; font-size: 2.2em; margin: 50px 0 30px 0; font-weight: 700; border-left: 5px solid #667eea; padding-left: 20px;">Running Totals with SUM()</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">
-- Running total of sales
SELECT 
  order_date,
  amount,
  SUM(amount) OVER (ORDER BY order_date) AS running_total
FROM orders;

-- Result:
-- order_date | amount | running_total
-- 2024-01-01 | 100    | 100
-- 2024-01-02 | 150    | 250  (100 + 150)
-- 2024-01-03 | 200    | 450  (100 + 150 + 200)

-- Running total per customer
SELECT 
  customer_id,
  order_date,
  amount,
  SUM(amount) OVER (
    PARTITION BY customer_id 
    ORDER BY order_date
  ) AS customer_running_total
FROM orders;

-- Separate running total for each customer
</pre>
<h3 style="color: #2c3e50; font-size: 2.2em; margin: 50px 0 30px 0; font-weight: 700; border-left: 5px solid #f39c12; padding-left: 20px;">LAG() and LEAD() - Previous/Next Row</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">
-- Compare with previous day
SELECT 
  order_date,
  revenue,
  LAG(revenue) OVER (ORDER BY order_date) AS prev_day_revenue,
  revenue - LAG(revenue) OVER (ORDER BY order_date) AS daily_change
FROM daily_revenue;

-- Result:
-- order_date | revenue | prev_day_revenue | daily_change
-- 2024-01-01 | 1000    | NULL             | NULL
-- 2024-01-02 | 1200    | 1000             | 200
-- 2024-01-03 | 950     | 1200             | -250

-- LEAD() for next row
SELECT 
  order_date,
  revenue,
  LEAD(revenue) OVER (ORDER BY order_date) AS next_day_revenue
FROM daily_revenue;

-- LAG with offset (2 days ago)
SELECT 
  order_date,
  revenue,
  LAG(revenue, 2) OVER (ORDER BY order_date) AS two_days_ago
FROM daily_revenue;
</pre>
<div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 35px; border-radius: 12px; margin: 40px 0;">
<h4 style="margin-top: 0; font-size: 1.7em; font-weight: 700;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f3af.png" alt="🎯" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Moving Averages</h4>
<pre style="background: rgba(0,0,0,0.3); color: #fff; padding: 25px; border-radius: 8px; font-size: 1.05em; line-height: 1.8;">
-- 7-day moving average
SELECT 
  order_date,
  revenue,
  AVG(revenue) OVER (
    ORDER BY order_date
    ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
  ) AS moving_avg_7day
FROM daily_revenue;

-- 3-month moving average
SELECT 
  month,
  total_sales,
  AVG(total_sales) OVER (
    ORDER BY month
    ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
  ) AS moving_avg_3month
FROM monthly_sales;
</pre>
</p></div>
<h3 style="color: #2c3e50; font-size: 2.2em; margin: 50px 0 30px 0; font-weight: 700; border-left: 5px solid #27ae60; padding-left: 20px;">NTILE() - Divide into Buckets</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">
-- Divide customers into 4 quartiles by spend
SELECT 
  customer_id,
  total_spend,
  NTILE(4) OVER (ORDER BY total_spend DESC) AS quartile
FROM customer_totals;

-- Result:
-- customer_id | total_spend | quartile
-- 101         | 50000       | 1  (top 25%)
-- 102         | 48000       | 1
-- 103         | 30000       | 2
-- 104         | 28000       | 2
-- 105         | 15000       | 3
-- 106         | 12000       | 3
-- 107         | 5000        | 4  (bottom 25%)
-- 108         | 3000        | 4

-- Use case: Segment customers
SELECT quartile, COUNT(*) as customer_count
FROM (
  SELECT NTILE(4) OVER (ORDER BY total_spend DESC) AS quartile
  FROM customer_totals
) quartiles
GROUP BY quartile;
</pre>
<div style="background: linear-gradient(135deg, #d4edda 0%, #c3e6cb 100%); padding: 35px; border-radius: 12px; margin: 40px 0; border-left: 5px solid #28a745;">
<h4 style="color: #155724; margin-top: 0; font-size: 1.7em; font-weight: 700;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Real-World Examples</h4>
<h5 style="color: #27ae60; font-size: 1.3em; margin: 20px 0 10px 0;">Pagination</h5>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">
-- Page 2, 10 items per page
SELECT *
FROM (
  SELECT 
    ROW_NUMBER() OVER (ORDER BY created_at DESC) AS row_num,
    *
  FROM posts
) numbered
WHERE row_num BETWEEN 11 AND 20;
</pre>
<h5 style="color: #27ae60; font-size: 1.3em; margin: 20px 0 10px 0;">Top N Per Group</h5>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">
-- Top 5 products per category by sales
SELECT category, product_name, total_sales
FROM (
  SELECT 
    category,
    product_name,
    total_sales,
    ROW_NUMBER() OVER (
      PARTITION BY category 
      ORDER BY total_sales DESC
    ) AS rank
  FROM product_sales
) ranked
WHERE rank <= 5;
</pre>
<h5 style="color: #27ae60; font-size: 1.3em; margin: 20px 0 10px 0;">Percentage of Total</h5>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">
SELECT 
  product,
  sales,
  sales * 100.0 / SUM(sales) OVER () AS pct_of_total
FROM product_sales;

-- Result:
-- product | sales | pct_of_total
-- A       | 5000  | 50.0
-- B       | 3000  | 30.0
-- C       | 2000  | 20.0
</pre>
</p></div>
<div style="background: linear-gradient(135deg, #fff3cd 0%, #ffe69c 100%); border-left: 5px solid #ffc107; padding: 35px; margin: 50px 0; border-radius: 12px;">
<h4 style="color: #856404; margin-top: 0; font-size: 1.7em; font-weight: 700;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Window Function Syntax</h4>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">
<function> OVER (
  [PARTITION BY column]   -- Optional: Group by
  [ORDER BY column]       -- Optional: Sort order
  [ROWS/RANGE clause]     -- Optional: Frame specification
)

-- Common functions:
-- ROW_NUMBER(), RANK(), DENSE_RANK()
-- SUM(), AVG(), MIN(), MAX(), COUNT()
-- LAG(), LEAD()
-- FIRST_VALUE(), LAST_VALUE()
-- NTILE()
</pre>
</p></div>
<blockquote style="background: linear-gradient(to right, #e0f7fa, #b2ebf2); border-left: 6px solid #00bcd4; padding: 40px; margin: 50px 0; border-radius: 12px;">
<p style="font-size: 1.5em; line-height: 1.9; margin: 0; color: #006064; font-style: italic; font-weight: 500;">"Dashboard needed top 10 products per category. Was using subqueries and JOINs. Switched to window functions with ROW_NUMBER(). Query went from 2 seconds to 0.1 seconds. Code so much cleaner."</p>
<footer style="margin-top: 20px; color: #00838f; font-size: 1.15em; font-weight: 600;">— Data Analyst</footer>
</blockquote>
]]></content:encoded>
					
					<wfw:commentRss>http://blog.ercanopak.com/sql-use-window-functions-for-advanced-analytical-queries/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>SQL: Read Execution Plans to Find Performance Bottlenecks</title>
		<link>http://blog.ercanopak.com/sql-read-execution-plans-to-find-performance-bottlenecks/</link>
					<comments>http://blog.ercanopak.com/sql-read-execution-plans-to-find-performance-bottlenecks/#respond</comments>
		
		<dc:creator><![CDATA[ErcanOPAK]]></dc:creator>
		<pubDate>Sun, 22 Mar 2026 09:05:22 +0000</pubDate>
				<category><![CDATA[SQL]]></category>
		<category><![CDATA[Database Optimization]]></category>
		<category><![CDATA[Database Performance]]></category>
		<category><![CDATA[execution plans]]></category>
		<category><![CDATA[indexing]]></category>
		<category><![CDATA[Performance Tuning]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[Query Optimization]]></category>
		<category><![CDATA[sql server]]></category>
		<category><![CDATA[SQL Tips]]></category>
		<guid isPermaLink="false">http://blog.ercanopak.com/sql-read-execution-plans-to-find-performance-bottlenecks/</guid>

					<description><![CDATA[🔍 See What Database Actually Does Query slow? Don&#8217;t guess. Execution plans show exactly how database executes query. Find bottlenecks, fix performance. Get Execution Plan -- SQL Server SET STATISTICS IO ON; SET STATISTICS TIME ON; -- Show estimated plan (doesn't run query) SET SHOWPLAN_TEXT ON; GO SELECT * FROM orders WHERE user_id = 123; [&#8230;]]]></description>
										<content:encoded><![CDATA[<div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 50px 40px; border-radius: 16px; margin: 40px 0; box-shadow: 0 20px 60px rgba(0,0,0,0.3);">
<h2 style="margin: 0 0 20px 0; font-size: 2.8em; font-weight: 800; line-height: 1.2;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f50d.png" alt="🔍" class="wp-smiley" style="height: 1em; max-height: 1em;" /> See What Database Actually Does</h2>
<p style="font-size: 1.4em; line-height: 1.8; margin: 0; opacity: 0.95;">Query slow? Don&#8217;t guess. <strong>Execution plans</strong> show exactly how database executes query. Find bottlenecks, fix performance.</p>
</p></div>
<h3 style="color: #2c3e50; font-size: 2.2em; margin: 50px 0 30px 0; font-weight: 700; border-left: 5px solid #764ba2; padding-left: 20px;">Get Execution Plan</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">
-- SQL Server
SET STATISTICS IO ON;
SET STATISTICS TIME ON;

-- Show estimated plan (doesn't run query)
SET SHOWPLAN_TEXT ON;
GO
SELECT * FROM orders WHERE user_id = 123;
GO
SET SHOWPLAN_TEXT OFF;

-- Show actual plan (runs query)
SET STATISTICS PROFILE ON;
SELECT * FROM orders WHERE user_id = 123;
SET STATISTICS PROFILE OFF;

-- Or use SSMS: Ctrl + M (actual plan)

-- PostgreSQL
EXPLAIN ANALYZE
SELECT * FROM orders WHERE user_id = 123;

-- MySQL
EXPLAIN
SELECT * FROM orders WHERE user_id = 123;
</pre>
<div style="background: #f8f9fa; padding: 40px; border-radius: 12px; margin: 40px 0; border: 2px solid #667eea;">
<h4 style="color: #667eea; margin-top: 0; font-size: 1.7em; font-weight: 700;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f6a8.png" alt="🚨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Red Flags to Look For</h4>
<table style="width: 100%; border-collapse: collapse; margin: 20px 0;">
<tr style="background: #667eea; color: white;">
<th style="padding: 15px; text-align: left;">Problem</th>
<th style="padding: 15px; text-align: left;">What It Means</th>
<th style="padding: 15px; text-align: left;">Fix</th>
</tr>
<tr>
<td style="padding: 12px; border-bottom: 1px solid #ddd; font-weight: bold;">Table Scan</td>
<td style="padding: 12px; border-bottom: 1px solid #ddd;">Reading entire table</td>
<td style="padding: 12px; border-bottom: 1px solid #ddd;">Add index</td>
</tr>
<tr style="background: #f8f9fa;">
<td style="padding: 12px; border-bottom: 1px solid #ddd; font-weight: bold;">Index Scan (large)</td>
<td style="padding: 12px; border-bottom: 1px solid #ddd;">Reading whole index</td>
<td style="padding: 12px; border-bottom: 1px solid #ddd;">Better WHERE clause</td>
</tr>
<tr>
<td style="padding: 12px; border-bottom: 1px solid #ddd; font-weight: bold;">Nested Loops</td>
<td style="padding: 12px; border-bottom: 1px solid #ddd;">Join with no index</td>
<td style="padding: 12px; border-bottom: 1px solid #ddd;">Add index on join column</td>
</tr>
<tr style="background: #f8f9fa;">
<td style="padding: 12px; border-bottom: 1px solid #ddd; font-weight: bold;">Sort (high cost)</td>
<td style="padding: 12px; border-bottom: 1px solid #ddd;">ORDER BY without index</td>
<td style="padding: 12px; border-bottom: 1px solid #ddd;">Index on ORDER BY column</td>
</tr>
<tr>
<td style="padding: 12px; border-bottom: 1px solid #ddd; font-weight: bold;">Key Lookup</td>
<td style="padding: 12px; border-bottom: 1px solid #ddd;">Extra data fetch</td>
<td style="padding: 12px; border-bottom: 1px solid #ddd;">Covering index</td>
</tr>
<tr style="background: #f8f9fa;">
<td style="padding: 12px;">Implicit Conversion</td>
<td style="padding: 12px;">Data type mismatch</td>
<td style="padding: 12px;">Match column types</td>
</tr>
</table></div>
<h3 style="color: #2c3e50; font-size: 2.2em; margin: 50px 0 30px 0; font-weight: 700; border-left: 5px solid #f39c12; padding-left: 20px;">Real Example: Before &#038; After</h3>
<div style="background: linear-gradient(135deg, #ff6b6b 0%, #ee5a6f 100%); color: white; padding: 35px; border-radius: 12px; margin: 40px 0;">
<h4 style="margin-top: 0; font-size: 1.7em; font-weight: 700;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Before (Slow)</h4>
<pre style="background: rgba(0,0,0,0.3); color: #fff; padding: 25px; border-radius: 8px; font-size: 1.05em; line-height: 1.8;">
SELECT *
FROM orders o
INNER JOIN users u ON o.user_id = u.id
WHERE o.status = 'pending'
ORDER BY o.created_at DESC;

-- Execution Plan Shows:
-- Table Scan on orders (500,000 rows)
-- No index on status column
-- Sort operation (expensive)
-- Execution time: 8 seconds
</pre>
</p></div>
<div style="background: linear-gradient(135deg, #56ab2f 0%, #a8e063 100%); color: white; padding: 35px; border-radius: 12px; margin: 40px 0;">
<h4 style="margin-top: 0; font-size: 1.7em; font-weight: 700;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> After (Fast)</h4>
<pre style="background: rgba(0,0,0,0.3); color: #fff; padding: 25px; border-radius: 8px; font-size: 1.05em; line-height: 1.8;">
-- Add index
CREATE INDEX idx_orders_status_date 
ON orders(status, created_at DESC);

-- Same query
SELECT *
FROM orders o
INNER JOIN users u ON o.user_id = u.id
WHERE o.status = 'pending'
ORDER BY o.created_at DESC;

-- Execution Plan Shows:
-- Index Seek (2,000 rows - only pending orders)
-- No sort needed (already sorted in index)
-- Execution time: 0.05 seconds
-- 160x faster!
</pre>
</p></div>
<h3 style="color: #2c3e50; font-size: 2.2em; margin: 50px 0 30px 0; font-weight: 700; border-left: 5px solid #00f2fe; padding-left: 20px;">Reading The Numbers</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">
Execution Plan Output:

|--Index Seek  (Cost: 5%)
   Rows: 100
   Estimated Rows: 95
   
|--Nested Loops  (Cost: 30%)
   Rows: 10,000
   Estimated Rows: 100  ← Problem! Estimate way off
   
|--Table Scan  (Cost: 65%)  ← Most expensive operation
   Rows: 500,000

Key Metrics:
- Cost %: Higher = slower (focus on > 20%)
- Rows: Actual rows processed
- Estimated Rows: Database guess (way off = update stats)
</pre>
<div style="background: linear-gradient(135deg, #d4edda 0%, #c3e6cb 100%); padding: 35px; border-radius: 12px; margin: 40px 0; border-left: 5px solid #28a745;">
<h4 style="color: #155724; margin-top: 0; font-size: 1.7em; font-weight: 700;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f3af.png" alt="🎯" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Quick Wins</h4>
<ul style="color: #155724; font-size: 1.15em; line-height: 2.2; margin: 20px 0;">
<li><strong>Table Scan → Index Seek:</strong> Add index on WHERE columns</li>
<li><strong>Sort → No Sort:</strong> Index on ORDER BY columns</li>
<li><strong>Nested Loops → Hash Match:</strong> Update statistics</li>
<li><strong>Key Lookup:</strong> Create covering index (include SELECT columns)</li>
<li><strong>Parameter Sniffing:</strong> Use <code>OPTION (RECOMPILE)</code></li>
</ul></div>
<div style="background: linear-gradient(135deg, #fff3cd 0%, #ffe69c 100%); border-left: 5px solid #ffc107; padding: 35px; margin: 50px 0; border-radius: 12px;">
<h4 style="color: #856404; margin-top: 0; font-size: 1.7em; font-weight: 700;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Pro Tips</h4>
<ul style="color: #856404; font-size: 1.15em; line-height: 2.2; margin: 20px 0;">
<li><strong>Use actual plan:</strong> Estimated can be wrong</li>
<li><strong>Look at percentages:</strong> Focus on operations > 20% cost</li>
<li><strong>Check row counts:</strong> Estimated vs Actual mismatch? Update stats</li>
<li><strong>Read right to left:</strong> Execution flows from right (data source) to left (result)</li>
<li><strong>Save plans:</strong> Compare before/after optimization</li>
</ul></div>
<blockquote style="background: linear-gradient(to right, #e8eaf6, #c5cae9); border-left: 6px solid #5c6bc0; padding: 40px; margin: 50px 0; border-radius: 12px;">
<p style="font-size: 1.5em; line-height: 1.9; margin: 0; color: #1a237e; font-style: italic; font-weight: 500;">&#8220;Query took 30 seconds. Execution plan showed table scan. Added one index. Query now takes 0.1 seconds. 300x faster. Execution plans are X-ray vision for databases.&#8221;</p>
<footer style="margin-top: 20px; color: #283593; font-size: 1.15em; font-weight: 600;">— Database Administrator</footer>
</blockquote>
]]></content:encoded>
					
					<wfw:commentRss>http://blog.ercanopak.com/sql-read-execution-plans-to-find-performance-bottlenecks/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>SQL: Use CTEs (WITH Clause) for Readable Complex Queries</title>
		<link>http://blog.ercanopak.com/sql-use-ctes-with-clause-for-readable-complex-queries/</link>
					<comments>http://blog.ercanopak.com/sql-use-ctes-with-clause-for-readable-complex-queries/#respond</comments>
		
		<dc:creator><![CDATA[ErcanOPAK]]></dc:creator>
		<pubDate>Sun, 22 Mar 2026 09:05:16 +0000</pubDate>
				<category><![CDATA[SQL]]></category>
		<category><![CDATA[Advanced SQL]]></category>
		<category><![CDATA[Common Table Expressions]]></category>
		<category><![CDATA[CTEs]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[Query Optimization]]></category>
		<category><![CDATA[Readable Code]]></category>
		<category><![CDATA[Recursive Queries]]></category>
		<category><![CDATA[SQL Tips]]></category>
		<category><![CDATA[WITH Clause]]></category>
		<guid isPermaLink="false">http://blog.ercanopak.com/sql-use-ctes-with-clause-for-readable-complex-queries/</guid>

					<description><![CDATA[📝 Name Your Subqueries Nested subqueries everywhere? Unreadable mess? CTEs (Common Table Expressions) name intermediate results. Code becomes self-documenting. The Subquery Nightmare -- ❌ Nested subqueries: Hard to read SELECT u.name, (SELECT COUNT(*) FROM orders o WHERE o.user_id = u.id) as order_count, (SELECT AVG(total) FROM orders o WHERE o.user_id = u.id) as avg_order FROM users [&#8230;]]]></description>
										<content:encoded><![CDATA[<div style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); color: white; padding: 50px 40px; border-radius: 16px; margin: 40px 0; box-shadow: 0 20px 60px rgba(0,0,0,0.3);">
<h2 style="margin: 0 0 20px 0; font-size: 2.8em; font-weight: 800; line-height: 1.2;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4dd.png" alt="📝" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Name Your Subqueries</h2>
<p style="font-size: 1.4em; line-height: 1.8; margin: 0; opacity: 0.95;">Nested subqueries everywhere? Unreadable mess? <strong>CTEs (Common Table Expressions)</strong> name intermediate results. Code becomes self-documenting.</p>
</p></div>
<h3 style="color: #2c3e50; font-size: 2.2em; margin: 50px 0 30px 0; font-weight: 700; border-left: 5px solid #00f2fe; padding-left: 20px;">The Subquery Nightmare</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">
-- <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Nested subqueries: Hard to read
SELECT 
    u.name,
    (SELECT COUNT(*) FROM orders o WHERE o.user_id = u.id) as order_count,
    (SELECT AVG(total) FROM orders o WHERE o.user_id = u.id) as avg_order
FROM users u
WHERE u.id IN (
    SELECT user_id 
    FROM orders 
    WHERE created_at > '2024-01-01'
    GROUP BY user_id
    HAVING COUNT(*) > 5
)
AND u.country IN (
    SELECT country 
    FROM countries 
    WHERE region = 'EU'
);

-- What does this do? Hard to understand at a glance
</pre>
<h3 style="color: #2c3e50; font-size: 2.2em; margin: 50px 0 30px 0; font-weight: 700; border-left: 5px solid #27ae60; padding-left: 20px;">CTE Solution: Clear and Readable</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">
-- <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> WITH clause: Self-documenting
WITH 
    active_users AS (
        SELECT user_id
        FROM orders
        WHERE created_at > '2024-01-01'
        GROUP BY user_id
        HAVING COUNT(*) > 5
    ),
    eu_countries AS (
        SELECT country
        FROM countries
        WHERE region = 'EU'
    ),
    user_stats AS (
        SELECT 
            user_id,
            COUNT(*) as order_count,
            AVG(total) as avg_order
        FROM orders
        GROUP BY user_id
    )
SELECT 
    u.name,
    s.order_count,
    s.avg_order
FROM users u
INNER JOIN active_users a ON u.id = a.user_id
INNER JOIN eu_countries e ON u.country = e.country
LEFT JOIN user_stats s ON u.id = s.user_id;

-- Clear logic: Filter active users, EU countries, join stats
</pre>
<div style="background: #f8f9fa; padding: 40px; border-radius: 12px; margin: 40px 0; border: 2px solid #4facfe;">
<h4 style="color: #00f2fe; margin-top: 0; font-size: 1.7em; font-weight: 700;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f3af.png" alt="🎯" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Basic CTE Syntax</h4>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">
WITH cte_name AS (
    SELECT column1, column2
    FROM table
    WHERE condition
)
SELECT *
FROM cte_name;

-- Multiple CTEs
WITH 
    cte1 AS (
        SELECT ...
    ),
    cte2 AS (
        SELECT ...
        FROM cte1  -- Can reference previous CTE
    )
SELECT *
FROM cte2;
</pre>
</p></div>
<h3 style="color: #2c3e50; font-size: 2.2em; margin: 50px 0 30px 0; font-weight: 700; border-left: 5px solid #667eea; padding-left: 20px;">Recursive CTE (Hierarchies)</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">
-- Organization chart: Manager → Employee hierarchy
WITH RECURSIVE org_chart AS (
    -- Base case: Top-level managers
    SELECT 
        id,
        name,
        manager_id,
        1 as level,
        CAST(name AS VARCHAR(1000)) as path
    FROM employees
    WHERE manager_id IS NULL
    
    UNION ALL
    
    -- Recursive case: Employees under managers
    SELECT 
        e.id,
        e.name,
        e.manager_id,
        oc.level + 1,
        CAST(oc.path || ' -> ' || e.name AS VARCHAR(1000))
    FROM employees e
    INNER JOIN org_chart oc ON e.manager_id = oc.id
)
SELECT 
    REPEAT('  ', level - 1) || name as hierarchy,
    level,
    path
FROM org_chart
ORDER BY path;

-- Output:
-- CEO              1  CEO
--   VP Sales       2  CEO -> VP Sales
--     Sales Rep    3  CEO -> VP Sales -> Sales Rep
--   VP Eng         2  CEO -> VP Eng
--     Dev Lead     3  CEO -> VP Eng -> Dev Lead
</pre>
<div style="background: linear-gradient(135deg, #fa709a 0%, #fee140 100%); color: white; padding: 35px; border-radius: 12px; margin: 40px 0;">
<h4 style="margin-top: 0; font-size: 1.7em; font-weight: 700;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4ca.png" alt="📊" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Sales Report Example</h4>
<pre style="background: rgba(0,0,0,0.3); color: #fff; padding: 25px; border-radius: 8px; font-size: 1.05em; line-height: 1.8;">
WITH 
    monthly_sales AS (
        SELECT 
            DATE_TRUNC('month', order_date) as month,
            SUM(total) as revenue
        FROM orders
        WHERE order_date >= '2024-01-01'
        GROUP BY DATE_TRUNC('month', order_date)
    ),
    sales_with_growth AS (
        SELECT 
            month,
            revenue,
            LAG(revenue) OVER (ORDER BY month) as prev_month_revenue,
            revenue - LAG(revenue) OVER (ORDER BY month) as growth
        FROM monthly_sales
    )
SELECT 
    TO_CHAR(month, 'Mon YYYY') as period,
    revenue,
    prev_month_revenue,
    growth,
    ROUND((growth / NULLIF(prev_month_revenue, 0)) * 100, 2) as growth_pct
FROM sales_with_growth
ORDER BY month;
</pre>
</p></div>
<h3 style="color: #2c3e50; font-size: 2.2em; margin: 50px 0 30px 0; font-weight: 700; border-left: 5px solid #f39c12; padding-left: 20px;">CTE vs Subquery vs Temp Table</h3>
<table style="width: 100%; border-collapse: collapse; margin: 40px 0; box-shadow: 0 5px 15px rgba(0,0,0,0.2);">
<tr style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white;">
<th style="padding: 18px; text-align: left; font-size: 1.2em;">Feature</th>
<th style="padding: 18px; text-align: center; font-size: 1.2em;">CTE</th>
<th style="padding: 18px; text-align: center; font-size: 1.2em;">Subquery</th>
<th style="padding: 18px; text-align: center; font-size: 1.2em;">Temp Table</th>
</tr>
<tr style="background: #f8f9fa;">
<td style="padding: 15px; font-weight: bold;">Readability</td>
<td style="padding: 15px; text-align: center; color: #27ae60;">✓ High</td>
<td style="padding: 15px; text-align: center; color: #e74c3c;">✗ Low</td>
<td style="padding: 15px; text-align: center; color: #f39c12;">~ Medium</td>
</tr>
<tr>
<td style="padding: 15px; font-weight: bold;">Reusability</td>
<td style="padding: 15px; text-align: center; color: #27ae60;">✓ In query</td>
<td style="padding: 15px; text-align: center; color: #e74c3c;">✗ No</td>
<td style="padding: 15px; text-align: center; color: #27ae60;">✓ Session</td>
</tr>
<tr style="background: #f8f9fa;">
<td style="padding: 15px; font-weight: bold;">Performance</td>
<td style="padding: 15px; text-align: center; color: #f39c12;">~ Same as subquery</td>
<td style="padding: 15px; text-align: center; color: #f39c12;">~ Depends</td>
<td style="padding: 15px; text-align: center; color: #27ae60;">✓ Can index</td>
</tr>
<tr>
<td style="padding: 15px; font-weight: bold;">Recursive</td>
<td style="padding: 15px; text-align: center; color: #27ae60;">✓ Yes</td>
<td style="padding: 15px; text-align: center; color: #e74c3c;">✗ No</td>
<td style="padding: 15px; text-align: center; color: #e74c3c;">✗ No</td>
</tr>
</table>
<div style="background: linear-gradient(135deg, #d4edda 0%, #c3e6cb 100%); padding: 35px; border-radius: 12px; margin: 40px 0; border-left: 5px solid #28a745;">
<h4 style="color: #155724; margin-top: 0; font-size: 1.7em; font-weight: 700;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> When to Use CTEs</h4>
<ul style="color: #155724; font-size: 1.15em; line-height: 2.2; margin: 20px 0;">
<li><strong>Complex queries:</strong> Break down into logical steps</li>
<li><strong>Readability:</strong> Name intermediate results meaningfully</li>
<li><strong>Hierarchies:</strong> Recursive CTEs for tree structures</li>
<li><strong>Debugging:</strong> Test each CTE separately</li>
<li><strong>Documentation:</strong> CTE names explain query logic</li>
</ul></div>
<div style="background: linear-gradient(135deg, #fff3cd 0%, #ffe69c 100%); border-left: 5px solid #ffc107; padding: 35px; margin: 50px 0; border-radius: 12px;">
<h4 style="color: #856404; margin-top: 0; font-size: 1.7em; font-weight: 700;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Pro Tips</h4>
<ul style="color: #856404; font-size: 1.15em; line-height: 2.2; margin: 20px 0;">
<li><strong>Name meaningfully:</strong> <code>active_users</code> not <code>cte1</code></li>
<li><strong>Limit recursion:</strong> Add <code>WHERE level <= 10</code> to prevent infinite loops</li>
<li><strong>Test incrementally:</strong> Run each CTE alone to verify logic</li>
<li><strong>Don't overuse:</strong> Simple queries don't need CTEs</li>
</ul></div>
<blockquote style="background: linear-gradient(to right, #e0f7fa, #b2ebf2); border-left: 6px solid #00bcd4; padding: 40px; margin: 50px 0; border-radius: 12px;">
<p style="font-size: 1.5em; line-height: 1.9; margin: 0; color: #006064; font-style: italic; font-weight: 500;">"Inherited 500-line query with 8 levels of nested subqueries. Rewrote with CTEs in 2 hours. Same logic, 10x more readable. Junior devs can now understand and modify it."</p>
<footer style="margin-top: 20px; color: #00838f; font-size: 1.15em; font-weight: 600;">— Database Developer</footer>
</blockquote>
]]></content:encoded>
					
					<wfw:commentRss>http://blog.ercanopak.com/sql-use-ctes-with-clause-for-readable-complex-queries/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>SQL: Use Indexed Views to Cache Complex Query Results</title>
		<link>http://blog.ercanopak.com/sql-use-indexed-views-to-cache-complex-query-results/</link>
					<comments>http://blog.ercanopak.com/sql-use-indexed-views-to-cache-complex-query-results/#respond</comments>
		
		<dc:creator><![CDATA[ErcanOPAK]]></dc:creator>
		<pubDate>Thu, 19 Mar 2026 20:29:25 +0000</pubDate>
				<category><![CDATA[SQL]]></category>
		<category><![CDATA[Aggregations]]></category>
		<category><![CDATA[caching]]></category>
		<category><![CDATA[Database Performance]]></category>
		<category><![CDATA[Indexed Views]]></category>
		<category><![CDATA[Materialized Views]]></category>
		<category><![CDATA[Query Optimization]]></category>
		<category><![CDATA[sql server]]></category>
		<category><![CDATA[SQL Tips]]></category>
		<guid isPermaLink="false">http://blog.ercanopak.com/sql-use-indexed-views-to-cache-complex-query-results/</guid>

					<description><![CDATA[⚡ Materialized Views in SQL Server Complex aggregation query taking 10 seconds? Create indexed view. Query becomes instant. Data stays fresh automatically. Problem: Slow Aggregate Query -- This runs every time, slow on large tables SELECT CategoryId, COUNT(*) AS ProductCount, AVG(Price) AS AvgPrice, SUM(Stock) AS TotalStock FROM Products GROUP BY CategoryId; -- 10 seconds on [&#8230;]]]></description>
										<content:encoded><![CDATA[<div style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); color: white; padding: 50px 40px; border-radius: 16px; margin: 40px 0; box-shadow: 0 20px 60px rgba(0,0,0,0.3);">
<h2 style="margin: 0 0 20px 0; font-size: 2.8em; font-weight: 800; line-height: 1.2;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a1.png" alt="⚡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Materialized Views in SQL Server</h2>
<p style="font-size: 1.4em; line-height: 1.8; margin: 0; opacity: 0.95;">Complex aggregation query taking 10 seconds? Create indexed view. Query becomes instant. Data stays fresh automatically.</p>
</p></div>
<h3 style="color: #2c3e50; font-size: 2.2em; margin: 50px 0 30px 0; font-weight: 700; border-left: 5px solid #00f2fe; padding-left: 20px;">Problem: Slow Aggregate Query</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">
-- This runs every time, slow on large tables
SELECT 
    CategoryId,
    COUNT(*) AS ProductCount,
    AVG(Price) AS AvgPrice,
    SUM(Stock) AS TotalStock
FROM Products
GROUP BY CategoryId;

-- 10 seconds on 10M rows
</pre>
<h3 style="color: #2c3e50; font-size: 2.2em; margin: 50px 0 30px 0; font-weight: 700; border-left: 5px solid #27ae60; padding-left: 20px;">Solution: Indexed View</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">
-- Step 1: Create view with SCHEMABINDING
CREATE VIEW dbo.ProductStats
WITH SCHEMABINDING
AS
SELECT 
    CategoryId,
    COUNT_BIG(*) AS ProductCount,
    SUM(Price) AS TotalPrice,
    SUM(Stock) AS TotalStock
FROM dbo.Products
GROUP BY CategoryId;
GO

-- Step 2: Create clustered index
CREATE UNIQUE CLUSTERED INDEX IX_ProductStats
ON dbo.ProductStats(CategoryId);
GO

-- Step 3: Query it like a table
SELECT * FROM ProductStats;

-- Now: < 0.1 seconds!
</pre>
<div style="background: #f8f9fa; padding: 40px; border-radius: 12px; margin: 40px 0; border: 2px solid #4facfe;">
<h4 style="color: #00f2fe; margin-top: 0; font-size: 1.7em; font-weight: 700;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f3af.png" alt="🎯" class="wp-smiley" style="height: 1em; max-height: 1em;" /> How It Works</h4>
<ul style="font-size: 1.15em; line-height: 2.5; color: #2c3e50; margin: 20px 0;">
<li><strong>Materialized:</strong> Results stored physically on disk</li>
<li><strong>Auto-updated:</strong> When base tables change, view updates</li>
<li><strong>Indexed:</strong> Query optimizer uses indexes</li>
<li><strong>Transparent:</strong> Apps don't know it's a view</li>
</ul></div>
<div style="background: linear-gradient(135deg, #fff3cd 0%, #ffe69c 100%); border-left: 5px solid #ffc107; padding: 35px; margin: 50px 0; border-radius: 12px;">
<h4 style="color: #856404; margin-top: 0; font-size: 1.7em; font-weight: 700;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Requirements</h4>
<ul style="color: #856404; font-size: 1.15em; line-height: 2.2; margin: 20px 0;">
<li><strong>WITH SCHEMABINDING</strong> required</li>
<li><strong>Must use COUNT_BIG</strong> not COUNT</li>
<li><strong>No OUTER joins</strong> (INNER only)</li>
<li><strong>No subqueries</strong> in SELECT</li>
<li><strong>First index must be UNIQUE CLUSTERED</strong></li>
</ul></div>
<div style="background: linear-gradient(135deg, #d4edda 0%, #c3e6cb 100%); padding: 35px; border-radius: 12px; margin: 40px 0; border-left: 5px solid #28a745;">
<h4 style="color: #155724; margin-top: 0; font-size: 1.7em; font-weight: 700;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> When to Use</h4>
<ul style="color: #155724; font-size: 1.15em; line-height: 2.2; margin: 20px 0;">
<li><strong>Heavy aggregations</strong> (COUNT, SUM, AVG)</li>
<li><strong>Complex joins</strong> queried frequently</li>
<li><strong>Reporting queries</strong> on large tables</li>
<li><strong>Dashboard queries</strong> that don't change much</li>
</ul></div>
<blockquote style="background: linear-gradient(to right, #e0f7fa, #b2ebf2); border-left: 6px solid #00bcd4; padding: 40px; margin: 50px 0; border-radius: 12px;">
<p style="font-size: 1.5em; line-height: 1.9; margin: 0; color: #006064; font-style: italic; font-weight: 500;">"Dashboard aggregation query took 12 seconds. Created indexed view. Now instant. Reports load in real-time. Users think we upgraded servers."</p>
<footer style="margin-top: 20px; color: #00838f; font-size: 1.15em; font-weight: 600;">— Database Administrator</footer>
</blockquote>
]]></content:encoded>
					
					<wfw:commentRss>http://blog.ercanopak.com/sql-use-indexed-views-to-cache-complex-query-results/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>SQL: Use Window Functions for Running Totals Without Self-Joins</title>
		<link>http://blog.ercanopak.com/sql-use-window-functions-for-running-totals-without-self-joins/</link>
					<comments>http://blog.ercanopak.com/sql-use-window-functions-for-running-totals-without-self-joins/#respond</comments>
		
		<dc:creator><![CDATA[ErcanOPAK]]></dc:creator>
		<pubDate>Thu, 19 Mar 2026 20:29:18 +0000</pubDate>
				<category><![CDATA[SQL]]></category>
		<category><![CDATA[Advanced SQL]]></category>
		<category><![CDATA[analytics]]></category>
		<category><![CDATA[Data Analysis]]></category>
		<category><![CDATA[RANK]]></category>
		<category><![CDATA[row_number]]></category>
		<category><![CDATA[Running Total]]></category>
		<category><![CDATA[SQL Tips]]></category>
		<category><![CDATA[Window Functions]]></category>
		<guid isPermaLink="false">http://blog.ercanopak.com/sql-use-window-functions-for-running-totals-without-self-joins/</guid>

					<description><![CDATA[📊 Advanced Analytics Made Easy Need running totals, rankings, moving averages? Window functions do it in one query. No self-joins. Running Total Example -- Calculate cumulative sales per day SELECT SaleDate, Amount, SUM(Amount) OVER (ORDER BY SaleDate) AS RunningTotal FROM Sales ORDER BY SaleDate; -- Result: -- SaleDate Amount RunningTotal -- 2024-01-01 100 100 -- [&#8230;]]]></description>
										<content:encoded><![CDATA[<div style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); color: white; padding: 50px 40px; border-radius: 16px; margin: 40px 0; box-shadow: 0 20px 60px rgba(0,0,0,0.3);">
<h2 style="margin: 0 0 20px 0; font-size: 2.8em; font-weight: 800; line-height: 1.2;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4ca.png" alt="📊" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Advanced Analytics Made Easy</h2>
<p style="font-size: 1.4em; line-height: 1.8; margin: 0; opacity: 0.95;">Need running totals, rankings, moving averages? <strong>Window functions</strong> do it in one query. No self-joins.</p>
</p></div>
<h3 style="color: #2c3e50; font-size: 2.2em; margin: 50px 0 30px 0; font-weight: 700; border-left: 5px solid #f5576c; padding-left: 20px;">Running Total Example</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">
-- Calculate cumulative sales per day
SELECT 
    SaleDate,
    Amount,
    SUM(Amount) OVER (ORDER BY SaleDate) AS RunningTotal
FROM Sales
ORDER BY SaleDate;

-- Result:
-- SaleDate    Amount  RunningTotal
-- 2024-01-01  100     100
-- 2024-01-02  150     250
-- 2024-01-03  200     450
</pre>
<div style="background: #f8f9fa; padding: 40px; border-radius: 12px; margin: 40px 0; border: 2px solid #f093fb;">
<h4 style="color: #f5576c; margin-top: 0; font-size: 1.7em; font-weight: 700;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f3af.png" alt="🎯" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Common Window Functions</h4>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">
-- ROW_NUMBER: Sequential numbering
SELECT 
    Name,
    Salary,
    ROW_NUMBER() OVER (ORDER BY Salary DESC) AS Rank
FROM Employees;

-- RANK: Ranking with gaps
SELECT 
    Name,
    Score,
    RANK() OVER (ORDER BY Score DESC) AS Rank
FROM Students;

-- DENSE_RANK: Ranking without gaps
SELECT 
    Product,
    Sales,
    DENSE_RANK() OVER (ORDER BY Sales DESC) AS Rank
FROM Products;

-- LAG/LEAD: Previous/Next row values
SELECT 
    SaleDate,
    Amount,
    LAG(Amount) OVER (ORDER BY SaleDate) AS PreviousDay,
    LEAD(Amount) OVER (ORDER BY SaleDate) AS NextDay
FROM Sales;
</pre>
</p></div>
<h3 style="color: #2c3e50; font-size: 2.2em; margin: 50px 0 30px 0; font-weight: 700; border-left: 5px solid #667eea; padding-left: 20px;">Partition By (Group Within Group)</h3>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">
-- Top 3 salaries per department
SELECT *
FROM (
    SELECT 
        Department,
        Name,
        Salary,
        ROW_NUMBER() OVER (
            PARTITION BY Department 
            ORDER BY Salary DESC
        ) AS DeptRank
    FROM Employees
) ranked
WHERE DeptRank <= 3;

-- Running total per category
SELECT 
    Category,
    Product,
    Sales,
    SUM(Sales) OVER (
        PARTITION BY Category 
        ORDER BY SaleDate
    ) AS CategoryRunningTotal
FROM Products;
</pre>
<div style="background: linear-gradient(135deg, #d4edda 0%, #c3e6cb 100%); padding: 35px; border-radius: 12px; margin: 40px 0; border-left: 5px solid #28a745;">
<h4 style="color: #155724; margin-top: 0; font-size: 1.7em; font-weight: 700;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f3a8.png" alt="🎨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Moving Average</h4>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">
-- 7-day moving average
SELECT 
    SaleDate,
    Amount,
    AVG(Amount) OVER (
        ORDER BY SaleDate 
        ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
    ) AS MovingAvg7Day
FROM Sales;
</pre>
</p></div>
<blockquote style="background: linear-gradient(to right, #fce4ec, #f8bbd0); border-left: 6px solid #e91e63; padding: 40px; margin: 50px 0; border-radius: 12px;">
<p style="font-size: 1.5em; line-height: 1.9; margin: 0; color: #880e4f; font-style: italic; font-weight: 500;">"Replaced 5 self-joins with one window function query. Execution time: 8 seconds → 0.3 seconds. Dashboard analytics became real-time. Window functions are SQL superpowers."</p>
<footer style="margin-top: 20px; color: #ad1457; font-size: 1.15em; font-weight: 600;">— Data Analyst</footer>
</blockquote>
]]></content:encoded>
					
					<wfw:commentRss>http://blog.ercanopak.com/sql-use-window-functions-for-running-totals-without-self-joins/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>SQL: Use OFFSET FETCH for Pagination</title>
		<link>http://blog.ercanopak.com/sql-use-offset-fetch-for-pagination/</link>
					<comments>http://blog.ercanopak.com/sql-use-offset-fetch-for-pagination/#respond</comments>
		
		<dc:creator><![CDATA[ErcanOPAK]]></dc:creator>
		<pubDate>Thu, 19 Mar 2026 20:08:28 +0000</pubDate>
				<category><![CDATA[SQL]]></category>
		<category><![CDATA[Data Retrieval]]></category>
		<category><![CDATA[OFFSET FETCH]]></category>
		<category><![CDATA[pagination]]></category>
		<category><![CDATA[Query Paging]]></category>
		<category><![CDATA[Result Sets]]></category>
		<category><![CDATA[SQL Best Practices]]></category>
		<category><![CDATA[sql server]]></category>
		<category><![CDATA[SQL Tips]]></category>
		<guid isPermaLink="false">http://blog.ercanopak.com/sql-use-offset-fetch-for-pagination/</guid>

					<description><![CDATA[Building pagination? OFFSET FETCH is standard SQL way. -- Page 1 (rows 1-10) SELECT * FROM Products ORDER BY ProductId OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY; -- Page 2 (rows 11-20) SELECT * FROM Products ORDER BY ProductId OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY; -- Dynamic pagination DECLARE @PageNumber INT = [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Building pagination? OFFSET FETCH is standard SQL way.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- Page 1 (rows 1-10)
SELECT * FROM Products
ORDER BY ProductId
OFFSET 0 ROWS
FETCH NEXT 10 ROWS ONLY;

-- Page 2 (rows 11-20)
SELECT * FROM Products
ORDER BY ProductId
OFFSET 10 ROWS
FETCH NEXT 10 ROWS ONLY;

-- Dynamic pagination
DECLARE @PageNumber INT = 3;
DECLARE @PageSize INT = 10;

SELECT * FROM Products
ORDER BY ProductId
OFFSET (@PageNumber - 1) * @PageSize ROWS
FETCH NEXT @PageSize ROWS ONLY;
</pre>
<p><strong>Note:</strong> ORDER BY required with OFFSET FETCH.</p>
]]></content:encoded>
					
					<wfw:commentRss>http://blog.ercanopak.com/sql-use-offset-fetch-for-pagination/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>SQL: Use COALESCE to Handle NULL Values</title>
		<link>http://blog.ercanopak.com/sql-use-coalesce-to-handle-null-values/</link>
					<comments>http://blog.ercanopak.com/sql-use-coalesce-to-handle-null-values/#respond</comments>
		
		<dc:creator><![CDATA[ErcanOPAK]]></dc:creator>
		<pubDate>Thu, 19 Mar 2026 20:08:21 +0000</pubDate>
				<category><![CDATA[SQL]]></category>
		<category><![CDATA[coalesce]]></category>
		<category><![CDATA[Data Cleaning]]></category>
		<category><![CDATA[Data Quality]]></category>
		<category><![CDATA[Default Values]]></category>
		<category><![CDATA[NULL Handling]]></category>
		<category><![CDATA[NULL Values]]></category>
		<category><![CDATA[SQL Best Practices]]></category>
		<category><![CDATA[SQL Functions]]></category>
		<category><![CDATA[SQL Tips]]></category>
		<guid isPermaLink="false">http://blog.ercanopak.com/sql-use-coalesce-to-handle-null-values/</guid>

					<description><![CDATA[NULL values breaking calculations? Use COALESCE for fallback. -- Returns first non-NULL value SELECT COALESCE(Phone, Email, 'No contact') AS Contact FROM Users; -- Default values in calculations SELECT Name, Price * COALESCE(Quantity, 0) AS Total FROM Orders; -- Multiple fallbacks SELECT COALESCE(PreferredName, FirstName, 'Unknown') AS DisplayName FROM Users; vs ISNULL: COALESCE is ANSI standard (works [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>NULL values breaking calculations? Use COALESCE for fallback.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- Returns first non-NULL value
SELECT COALESCE(Phone, Email, 'No contact') AS Contact
FROM Users;

-- Default values in calculations
SELECT 
  Name,
  Price * COALESCE(Quantity, 0) AS Total
FROM Orders;

-- Multiple fallbacks
SELECT COALESCE(PreferredName, FirstName, 'Unknown') AS DisplayName
FROM Users;
</pre>
<p><strong>vs ISNULL:</strong> COALESCE is ANSI standard (works everywhere). ISNULL is SQL Server only.</p>
<p><strong>vs CASE:</strong> Shorter, cleaner syntax.</p>
]]></content:encoded>
					
					<wfw:commentRss>http://blog.ercanopak.com/sql-use-coalesce-to-handle-null-values/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>SQL: Use CROSS APPLY for Correlated Subqueries Performance</title>
		<link>http://blog.ercanopak.com/sql-use-cross-apply-for-correlated-subqueries-performance/</link>
					<comments>http://blog.ercanopak.com/sql-use-cross-apply-for-correlated-subqueries-performance/#respond</comments>
		
		<dc:creator><![CDATA[ErcanOPAK]]></dc:creator>
		<pubDate>Thu, 19 Mar 2026 19:32:18 +0000</pubDate>
				<category><![CDATA[SQL]]></category>
		<category><![CDATA[Advanced SQL]]></category>
		<category><![CDATA[Correlated Subquery]]></category>
		<category><![CDATA[CROSS APPLY]]></category>
		<category><![CDATA[Database Optimization]]></category>
		<category><![CDATA[Query Optimization]]></category>
		<category><![CDATA[Query Performance]]></category>
		<category><![CDATA[sql server]]></category>
		<category><![CDATA[SQL Tips]]></category>
		<guid isPermaLink="false">http://blog.ercanopak.com/sql-use-cross-apply-for-correlated-subqueries-performance/</guid>

					<description><![CDATA[⚡ Faster Correlated Queries Correlated subqueries in SELECT run for every row. CROSS APPLY runs once. -- ❌ SLOW (subquery runs per row) SELECT c.Name, (SELECT TOP 1 OrderDate FROM Orders WHERE CustomerId = c.CustomerId ORDER BY OrderDate DESC) AS LastOrder FROM Customers c; -- ✅ FAST (CROSS APPLY optimized) SELECT c.Name, o.OrderDate FROM Customers [&#8230;]]]></description>
										<content:encoded><![CDATA[<div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 40px; border-radius: 12px; margin: 25px 0;">
<h2 style="margin-top: 0; font-size: 2.2em;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a1.png" alt="⚡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Faster Correlated Queries</h2>
<p style="font-size: 1.3em; line-height: 1.8;">Correlated subqueries in SELECT run for every row. CROSS APPLY runs once.</p>
</div>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> SLOW (subquery runs per row)
SELECT 
  c.Name,
  (SELECT TOP 1 OrderDate 
   FROM Orders 
   WHERE CustomerId = c.CustomerId 
   ORDER BY OrderDate DESC) AS LastOrder
FROM Customers c;

-- <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> FAST (CROSS APPLY optimized)
SELECT c.Name, o.OrderDate
FROM Customers c
CROSS APPLY (
  SELECT TOP 1 OrderDate
  FROM Orders
  WHERE CustomerId = c.CustomerId
  ORDER BY OrderDate DESC
) o;
</pre>
<p><strong>Result:</strong> 10-100x faster on large tables.</p>
<p><strong>When to Use:</strong> Need top N related rows, complex subquery logic.</p>
]]></content:encoded>
					
					<wfw:commentRss>http://blog.ercanopak.com/sql-use-cross-apply-for-correlated-subqueries-performance/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>SQL: Use CTEs for Readable Complex Queries</title>
		<link>http://blog.ercanopak.com/sql-use-ctes-for-readable-complex-queries/</link>
					<comments>http://blog.ercanopak.com/sql-use-ctes-for-readable-complex-queries/#respond</comments>
		
		<dc:creator><![CDATA[ErcanOPAK]]></dc:creator>
		<pubDate>Thu, 19 Mar 2026 19:32:11 +0000</pubDate>
				<category><![CDATA[SQL]]></category>
		<category><![CDATA[Clean Code]]></category>
		<category><![CDATA[Common Table Expressions]]></category>
		<category><![CDATA[Complex Queries]]></category>
		<category><![CDATA[cte]]></category>
		<category><![CDATA[Query Readability]]></category>
		<category><![CDATA[SQL Best Practices]]></category>
		<category><![CDATA[sql server]]></category>
		<category><![CDATA[SQL Tips]]></category>
		<category><![CDATA[WITH Clause]]></category>
		<guid isPermaLink="false">http://blog.ercanopak.com/sql-use-ctes-for-readable-complex-queries/</guid>

					<description><![CDATA[📖 Readable SQL Nested subqueries hurt readability. CTEs (Common Table Expressions) make complex queries clear. -- Clear, readable, step-by-step WITH ActiveUsers AS ( SELECT * FROM Users WHERE IsActive = 1 ), RecentOrders AS ( SELECT * FROM Orders WHERE CreatedAt &#62; DATEADD(month, -1, GETDATE()) ) SELECT u.Name, COUNT(o.OrderId) AS OrderCount FROM ActiveUsers u LEFT [&#8230;]]]></description>
										<content:encoded><![CDATA[<div style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); color: white; padding: 40px; border-radius: 12px; margin: 25px 0;">
<h2 style="margin-top: 0; font-size: 2.2em;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4d6.png" alt="📖" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Readable SQL</h2>
<p style="font-size: 1.3em; line-height: 1.8;">Nested subqueries hurt readability. CTEs (Common Table Expressions) make complex queries clear.</p>
</div>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">-- Clear, readable, step-by-step
WITH ActiveUsers AS (
  SELECT * FROM Users WHERE IsActive = 1
),
RecentOrders AS (
  SELECT * FROM Orders WHERE CreatedAt &gt; DATEADD(month, -1, GETDATE())
)
SELECT 
  u.Name,
  COUNT(o.OrderId) AS OrderCount
FROM ActiveUsers u
LEFT JOIN RecentOrders o ON u.UserId = o.UserId
GROUP BY u.Name;
</pre>
<p><strong>Benefit:</strong> Each CTE has a name. Easy to understand query logic. Easier to debug.</p>
<p><strong>Performance:</strong> Same as subqueries. Optimizer treats them identically.</p>
]]></content:encoded>
					
					<wfw:commentRss>http://blog.ercanopak.com/sql-use-ctes-for-readable-complex-queries/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
