- Yii2 How-To Guides
-
Basics
- How to Create a Dependent Dropdown in Yii2?
- How to Generate a PDF in Yii2 Using Mpdf
-
Swoole+YII2
- How to Run Yii2 with Swoole HTTP Server for Realtime Asynchronous Task Processing
-
Advanced
- How to Use CTE in Yii2 GridView: ArrayDataProvider vs. SQL View Approaches
- How to Add a New Application in Yii2 Basic Template (Without Switching to the Advanced Template)
How to Use CTE in Yii2 GridView: ArrayDataProvider vs. SQL View Approaches
Add to BookmarkWhat You Will Learn
- Definition and benefits of a CTE (Common Table Expression)
- Two practical ways to integrate CTE-based queries into Yii2 GridView:
- Using
ArrayDataProvider
- Creating a database view for use with
ActiveDataProvider
(supports built-in filtering)
- Using
Introduction: What Is a CTE?
A Common Table Expression (CTE) is a SQL construct that allows you to define a temporary result set, which can then be referenced within a larger SELECT
, INSERT
, UPDATE
, or DELETE
statement. For example:
WITH ranked_users AS (
SELECT
id,
name,
RANK() OVER (ORDER BY points DESC) AS rank
FROM user
)
SELECT *
FROM ranked_users
WHERE rank <= 10;
Out of the box, Yii2’s ActiveRecord does not support writing CTEs inline. However, two straightforward workarounds make it possible to leverage CTE logic inside a Yii2 GridView:
- Execute the CTE query directly and feed results into an
ArrayDataProvider
(no filter UI support). - Create a database view that wraps the CTE SQL, then define an ActiveRecord model for that view and use
ActiveDataProvider
(grid filters and sorting work natively).
Choose the method that best fits your requirement: quick display versus fully integrated grid filtering.
Method 1: Using ArrayDataProvider for CTE Queries
This approach is ideal if:
- You only need to show the result without requiring Yii2 GridView filter inputs.
- You are comfortable handling any sorting or pagination manually (using the provider’s basic configuration).
Step 1: Write and Execute the CTE SQL
In your controller action (e.g., actionIndex
):
use Yii;
use yii\data\ArrayDataProvider;
public function actionIndex()
{
$sql = <<<SQL
WITH ranked_users AS (
SELECT
id,
name,
RANK() OVER (ORDER BY points DESC) AS rank
FROM user
)
SELECT *
FROM ranked_users
WHERE rank <= 10;
SQL;
// Execute the query directly using DAO
$rows = Yii::$app->db->createCommand($sql)->queryAll();
// Create an ArrayDataProvider
$dataProvider = new ArrayDataProvider([
'allModels' => $rows,
'pagination' => [
'pageSize' => 10,
],
'sort' => [
'attributes' => ['id', 'name', 'rank'],
],
]);
return $this->render('index', [
'dataProvider' => $dataProvider,
]);
}
Step 2: Render the GridView in the View
In views/your-controller/index.php
:
use yii\grid\GridView;
use yii\helpers\Html;
/* @var $dataProvider yii\data\ArrayDataProvider */
?>
<div class="ranked-users-index">
<h1>Top Ranked Users</h1>
<?= GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'id',
'name',
'rank',
],
]); ?>
</div>
Pros and Cons
- Pros
- Direct control over any SQL, including advanced CTE and window functions.
- Simple to implement when you just need to display a fixed set of results.
- Direct control over any SQL, including advanced CTE and window functions.
- Cons
- GridView filtering (the filter inputs above each column) is not available. If you need filter forms, you must build them manually and adjust the query.
- Sorting must rely on the provider’s basic sort configuration; it won’t automatically adjust the CTE unless you rebuild the SQL based on GET parameters.
Method 2: Create a Database View and Use ActiveDataProvider
This approach integrates smoothly with the Yii2 filtering UI. By wrapping the CTE in a database view, you can treat the view exactly like a regular table in ActiveRecord. The GridView will support filtering, sorting, and pagination out of the box.
Step 1: Create a SQL View
Run the following SQL in your database (MySQL, PostgreSQL, etc.). Adjust column names and table names to match your schema.
CREATE OR REPLACE VIEW top_users AS
WITH ranked_users AS (
SELECT
id,
name,
RANK() OVER (ORDER BY points DESC) AS rank
FROM user
)
SELECT *
FROM ranked_users
WHERE rank <= 10;
top_users
is the view name.- The CTE logic remains inside the
WITH
clause. - Final
SELECT
returns only rows withrank <= 10
.
Step 2: Generate (or Manually Create) an ActiveRecord Model for the View
You can use Gii or write it by hand. If you run Gii, point it to the top_users
view; it will generate a TopUser
model class. Example of a manual definition:
namespace app\models;
use yii\db\ActiveRecord;
class TopUser extends ActiveRecord
{
/**
* Return the name of the view (same as tableName for tables).
*/
public static function tableName()
{
return 'top_users';
}
/**
* Define validation rules (mark all attributes as safe for search).
*/
public function rules()
{
return [
[['id', 'name', 'rank'], 'safe'],
];
}
/**
* Optional: Define labels if you want to customize column headers
*/
public function attributeLabels()
{
return [
'id' => 'User ID',
'name' => 'User Name',
'rank' => 'Rank',
];
}
}
Step 3: Configure ActiveDataProvider in Controller
In your controller’s action (for example, actionTopUsers
):
use app\models\TopUser;
use yii\data\ActiveDataProvider;
public function actionTopUsers()
{
$query = TopUser::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => [
'pageSize' => 10,
],
'sort' => [
'defaultOrder' => ['rank' => SORT_ASC],
'attributes' => ['id', 'name', 'rank'],
],
]);
return $this->render('top-users', [
'dataProvider' => $dataProvider,
]);
}
If you also want search/filter capabilities, you can create a TopUserSearch
model (extending TopUser
) with filtering rules, then pass both $searchModel
and $dataProvider
to the view. This follows the standard Yii2 “index with search model” pattern.
Step 4: Render the GridView in the View
In views/your-controller/top-users.php
:
use yii\grid\GridView;
use yii\helpers\Html;
/* @var $dataProvider yii\data\ActiveDataProvider */
/* @var $searchModel app\models\TopUserSearch */ // if using a search model
?>
<div class="top-users-index">
<h1>Top Ranked Users</h1>
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => isset($searchModel) ? $searchModel : null,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'id',
'name',
'rank',
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
</div>
- If you generated
TopUserSearch
, pass it asfilterModel
so that you get filter fields above each column automatically. - The built-in
ActionColumn
will renderview
,update
,delete
links if corresponding controller actions exist (you can remove it if not needed).
Pros and Cons
- Pros
- The GridView’s filtering, sorting, and pagination all work without extra manual code.
- Everything feels native to Yii2: you can use Gii, code completion, search models, and so on.
- If you need to change the sorting/filter logic, you can override
search()
or adjust the view SQL in one place.
- Cons
- Requires database-level privileges to create or alter views.
- For highly dynamic CTEs (where parameters or logic change at runtime), you might need to recreate or modify the view frequently.
- Adding parameters to a view (for example, filtering by date range inside the CTE) often involves creating multiple views or using dynamic SQL outside the view.
Comparison of Approaches
Approach | Filtering Support | Best Use Case | Complexity |
---|---|---|---|
ArrayDataProvider | No | Quick, one-off display of CTE results | Low |
SQL View + ActiveProvider | Yes | Fully functional grid with filters/sorts | Moderate |
- ArrayDataProvider: If you simply need to show a top-N result from a CTE and you do not plan to use GridView filters, this method is quickest.
- SQL View + ActiveProvider: If you want to leverage the standard Yii2 search model and GridView filter inputs, create a database view and treat it like a normal table.
Additional Tips
- When to Rerun or Refresh the View
- In development, if you modify the CTE logic inside the view, run
CREATE OR REPLACE VIEW …
again. - In production, consider wrapping the view update in maintenance scripts or migrations.
- In development, if you modify the CTE logic inside the view, run
- Search Model for Filtering
- To allow search fields above each column in Method 2, generate a
TopUserSearch
class via Gii. - In
search()
, you might add conditions likeandFilterWhere(['like', 'name', $this->name])
.
- To allow search fields above each column in Method 2, generate a
- Pagination and Sorting with Custom Column Names
- If your CTE/VIEW uses column aliases, ensure the attribute names match the model’s attribute labels.
- Confirm the
rules()
in your model mark attributes as safe, otherwise filter inputs will be ignored.
- Complex CTE Examples
- Recursive CTEs (e.g., organizational hierarchies).
- Multi-step CTEs (several
WITH
clauses chained). - Window functions combined with grouping/aggregation.
Conclusion
Using CTEs in Yii2 GridView unlocks powerful SQL capabilities—ranking, recursive queries, multi-step transformations—while still fitting within the MVC workflow. Depending on your needs:
- Choose ArrayDataProvider when you only need to display static or read-only CTE results without filter forms.
- Choose SQL View + ActiveDataProvider when you want a fully interactive GridView with built-in filtering, sorting, and pagination.
Both techniques let you write efficient, maintainable code while leveraging the full power of SQL. Pick the one that aligns with your project’s requirements and database permissions.
Prepare for Interview
- JavaScript Interview Questions for 0–1 Year Experience
- JavaScript Interview Questions For Fresher
- SQL Interview Questions for 5+ Years Experience
- SQL Interview Questions for 2–5 Years Experience
- SQL Interview Questions for 1–2 Years Experience
- SQL Interview Questions for 0–1 Year Experience
- SQL Interview Questions for Freshers
- Design Patterns in Python
- Dynamic Programming and Recursion in Python
- Trees and Graphs in Python
- Linked Lists, Stacks, and Queues in Python
- Sorting and Searching in Python
- Debugging in Python
- Unit Testing in Python
- Asynchronous Programming in PYthon
Random Blogs
- Variable Assignment in Python
- Ideas for Content of Every niche on Reader’s Demand during COVID-19
- AI Agents & Autonomous Systems – The Future of Self-Driven Intelligence
- Why to learn Digital Marketing?
- Time Series Analysis on Air Passenger Data
- Exploratory Data Analysis On Iris Dataset
- Google’s Core Update in May 2020: What You Need to Know
- Top 15 Recommended SEO Tools
- 15 Amazing Keyword Research Tools You Should Explore
- Government Datasets from 50 Countries for Machine Learning Training
- Datasets for Speech Recognition Analysis
- What to Do When Your MySQL Table Grows Too Wide
- How AI is Making Humans Weaker – The Hidden Impact of Artificial Intelligence
- Datasets for Natural Language Processing
- 5 Ways Use Jupyter Notebook Online Free of Cost
Datasets for Machine Learning
- Amazon Product Reviews Dataset
- Ozone Level Detection Dataset
- Bank Transaction Fraud Detection
- YouTube Trending Video Dataset (updated daily)
- Covid-19 Case Surveillance Public Use Dataset
- US Election 2020
- Forest Fires Dataset
- Mobile Robots Dataset
- Safety Helmet Detection
- All Space Missions from 1957
- OSIC Pulmonary Fibrosis Progression Dataset
- Wine Quality Dataset
- Google Audio Dataset
- Iris flower dataset
- Artificial Characters Dataset