{dede:sql} 是一个非常强大的标签,它允许你直接执行自定义的 SQL 语句来获取数据库中的数据,但同时也需要开发者对 SQL 语法和数据库结构有基本的了解。

下面我将分步讲解如何实现 SQL 分页,并提供完整的代码示例和注意事项。
核心要点
- SQL 语句本身:编写你的
SELECT语句。 - 分页参数:使用 DedeCMS 的分页变量
pageno(当前页码) 和pagesize(每页显示条数)。 - DedeCMS 分页函数:使用
GetPageList()函数来生成分页导航条。
第一步:编写基础 SQL 语句
假设我们要从一个名为 dede_member (用户表) 的表中查询所有会员信息,并按注册时间倒序排列。
SELECT mid, uname, email, jointime FROM dede_member ORDER BY jointime DESC
第二步:整合分页参数
DedeCMS 的分页系统会自动提供两个变量:
pageno: 当前页码,从 1 开始。pagesize: 每页显示的记录数,可以在后台设置。
我们需要在 SQL 语句中使用这两个变量来实现分页查询,在 MySQL 中,我们使用 LIMIT 子句。

LIMIT 的语法是 LIMIT offset, count。
offset: 跳过的记录数,计算公式为(pageno - 1) * pagesize。count: 每页显示的记录数,即pagesize。
完整的 SQL 语句应该是这样的:
SELECT mid, uname, email, jointime FROM dede_member ORDER BY jointime DESC LIMIT (pageno - 1) * pagesize, pagesize
重要提示:
在 {dede:sql} 标签中,你不需要在 SQL 语句前加 SELECT,标签本身已经包含了,你需要写的是 SELECT 之后的部分,实际在模板中使用的 SQL 片段是:
mid, uname, email, jointime FROM dede_member ORDER BY jointime DESC LIMIT (pageno - 1) * pagesize, pagesize
第三步:在模板中使用 {dede:sql}
我们将上面的 SQL 片段放入 {dede:sql} 标签中,并用 {dede:list} 风格的循环来遍历查询结果。
(图片来源网络,侵删)
{dede:sql sql='mid, uname, email, jointime FROM dede_member ORDER BY jointime DESC LIMIT (pageno - 1) * pagesize, pagesize'}
<li>
<strong>用户名:</strong> [field:uname /]
<strong>邮箱:</strong> [field:email /]
<strong>注册时间:</strong> [field:jointime function="MyDate('Y-m-d H:i:s',@me)" /]
</li>
{/dede:sql}
说明:
sql='...': 这里填写你的 SQL 语句片段。
[field:字段名 /]: 用于输出查询结果中的特定字段。[field:uname /] 输出 uname 字段的值。
function="MyDate(...)": 这是 DedeCMS 的字段处理函数,用于格式化日期。@me 代表当前字段的原始值。
第四步:添加分页导航条
光有数据列表是不够的,我们还需要一个分页导航条让用户可以切换页面,这需要用到 GetPageList() 函数。
这个函数需要知道以下几个关键信息:
- 总记录数:你需要先执行一个
COUNT(*) 查询来获取。
- 分页变量名:通常是
pageno。
- 每页记录数:通常是
pagesize。
- 总分页数:总记录数 / 每页记录数。
一个完整的、包含分页导航的模板结构如下:
<h2>会员列表 (SQL分页)</h2>
<!-- 1. 数据列表 -->
<ul>
{dede:sql sql='mid, uname, email, jointime FROM dede_member ORDER BY jointime DESC LIMIT (pageno - 1) * pagesize, pagesize'}
<li>
<strong>用户名:</strong> [field:uname /]
<strong>邮箱:</strong> [field:email /]
<strong>注册时间:</strong> [field:jointime function="MyDate('Y-m-d H:i:s',@me)" /]
</li>
{/dede:sql}
</ul>
<!-- 2. 分页导航条 -->
<div class="page">
{dede:pagelist listsize='5' listitem='info,index,end,pre,next,pageno'}
</div>
</div>
上面的代码是错误的! 因为 {dede:sql} 标签无法直接获取总记录数,GetPageList() 函数无法工作,我们需要使用一个更高级的技巧。
完整、正确的实现方案
为了正确地获取总记录数并生成分页,我们需要在页面模板中引入一个自定义的 PHP 函数,这通常通过修改 include/extend.func.php 文件来实现。
步骤 1:创建自定义函数
打开 /include/extend.func.php 文件,在文件末尾添加以下 PHP 函数:
/**
* SQL分页函数
* @param string $query 查询语句
* @param int $pagesize 每页记录数
* @return string 返回分页HTML
*/
function GetSqlPage($query, $pagesize = 10) {
global $dsql, $pageno;
// 1. 获取总记录数
$countQuery = "SELECT COUNT(*) AS num FROM (" . $query . ") AS subquery";
$row = $dsql->GetOne($countQuery);
$totalResult = $row['num'];
// 2. 计算总页数
$totalPage = ceil($totalResult / $pagesize);
// 3. 获取当前页码
if(empty($pageno)) {
$pageno = 1;
}
if($pageno > $totalPage) {
$pageno = $totalPage;
}
// 4. 计算偏移量
$start = ($pageno - 1) * $pagesize;
// 5. 获取当前页的数据
$sql = $query . " LIMIT {$start}, {$pagesize}";
$dsql->Execute('me',$sql);
$items = array();
while($row = $dsql->GetArray('me')) {
$items[] = $row;
}
// 6. 生成数据列表HTML
$html = '';
if(count($items) > 0) {
foreach($items as $item) {
// 这里循环输出每一行数据,你可以根据需要修改
$html .= "<li>";
$html .= "用户名: " . $item['uname'] . " | ";
$html .= "邮箱: " . $item['email'] . " | ";
$html .= "注册时间: " . MyDate('Y-m-d H:i:s', $item['jointime']);
$html .= "</li>";
}
} else {
$html = "<li>暂无数据</li>";
}
// 7. 生成分页导航HTML
$pageNav = '';
// 引入DedeCMS的分页类
// 引入DedeCMS的分页类
require_once(DEDEINC.'/datalistcp.class.php');
$dl = new DataListCP();
$dl->pageSize = $pagesize;
$dl->SetParameter('pageno', $pageno);
$dl->SetTemplate(""); // 不需要模板,直接生成HTML
$dl->SetSource($totalResult);
$pageNav = $dl->GetPageList();
// 8. 返回数据列表和分页导航的组合
return $html . $pageNav;
}
函数说明:
- 这个函数接收一个 SQL 查询语句(不带
SELECT 和 LIMIT)和每页记录数。
- 它会先执行
COUNT(*) 计算总数,然后根据 pageno 和 pagesize 计算出当前页的数据。
- 它拼接出数据列表的 HTML 和分页导航的 HTML,并返回。
步骤 2:在模板中调用自定义函数
你的模板文件会变得非常简洁。
<h2>会员列表 (完整SQL分页)</h2>
<div>
{dede:global name='phpmy' function='GetSqlPage("mid, uname, email, jointime FROM dede_member ORDER BY jointime DESC", 10)'/}
</div>
模板代码解释:
{dede:global name='phpmy' ...}: 这是一个调用 PHP 函数的通用方法。
function='GetSqlPage(...)': 指定要调用的函数名就是我们刚刚创建的 GetSqlPage。
"mid, uname, email, jointime FROM dede_member ORDER BY jointime DESC": 传入的第一个参数,即我们的核心查询语句。
10: 传入的第二个参数,即每页显示10条记录。
这样,当页面加载时,GetSqlPage 函数会被执行,它会返回包含数据列表和分页导航的完整 HTML 代码,并显示在页面上。
总结与注意事项
- 性能问题:
{dede:sql} 绕过了 DedeCMS 的缓存机制,每次页面请求都会直接查询数据库,如果数据量很大或访问频繁,会对数据库造成较大压力,请谨慎使用。
- 安全风险:直接使用 SQL 查询存在 SQL 注入的风险,如果你的查询参数来自用户输入(如 URL 中的 ID),必须对参数进行严格的过滤和转义,使用
$dsql->GetOne() 或 $dsql->Execute() 来预处理参数。
- 适用场景:
{dede:sql} 最适合用于展示一些固定不变或更新不频繁的数据,比如公司简介、团队成员列表等,对于频繁更新的内容,仍然建议使用 DedeCMS 的内置模型(如文章、图集)。
- 调试:如果分页不工作,请检查:
- SQL 语句是否正确。
- 自定义函数
GetSqlPage 是否已成功添加到 extend.func.php。
- 模板中调用函数的语法是否正确。
- 检查浏览器地址栏中
pageno 参数是否正确传递(yourlist.php?pageno=2)。
希望这份详细的教程能帮助你掌握 DedeCMS 的 SQL 分页功能!
我们将上面的 SQL 片段放入 {dede:sql} 标签中,并用 {dede:list} 风格的循环来遍历查询结果。

{dede:sql sql='mid, uname, email, jointime FROM dede_member ORDER BY jointime DESC LIMIT (pageno - 1) * pagesize, pagesize'}
<li>
<strong>用户名:</strong> [field:uname /]
<strong>邮箱:</strong> [field:email /]
<strong>注册时间:</strong> [field:jointime function="MyDate('Y-m-d H:i:s',@me)" /]
</li>
{/dede:sql}
说明:
sql='...': 这里填写你的 SQL 语句片段。[field:字段名 /]: 用于输出查询结果中的特定字段。[field:uname /]输出uname字段的值。function="MyDate(...)": 这是 DedeCMS 的字段处理函数,用于格式化日期。@me代表当前字段的原始值。
第四步:添加分页导航条
光有数据列表是不够的,我们还需要一个分页导航条让用户可以切换页面,这需要用到 GetPageList() 函数。
这个函数需要知道以下几个关键信息:
- 总记录数:你需要先执行一个
COUNT(*)查询来获取。 - 分页变量名:通常是
pageno。 - 每页记录数:通常是
pagesize。 - 总分页数:总记录数 / 每页记录数。
一个完整的、包含分页导航的模板结构如下:
<h2>会员列表 (SQL分页)</h2>
<!-- 1. 数据列表 -->
<ul>
{dede:sql sql='mid, uname, email, jointime FROM dede_member ORDER BY jointime DESC LIMIT (pageno - 1) * pagesize, pagesize'}
<li>
<strong>用户名:</strong> [field:uname /]
<strong>邮箱:</strong> [field:email /]
<strong>注册时间:</strong> [field:jointime function="MyDate('Y-m-d H:i:s',@me)" /]
</li>
{/dede:sql}
</ul>
<!-- 2. 分页导航条 -->
<div class="page">
{dede:pagelist listsize='5' listitem='info,index,end,pre,next,pageno'}
</div>
</div>
上面的代码是错误的! 因为 {dede:sql} 标签无法直接获取总记录数,GetPageList() 函数无法工作,我们需要使用一个更高级的技巧。
完整、正确的实现方案
为了正确地获取总记录数并生成分页,我们需要在页面模板中引入一个自定义的 PHP 函数,这通常通过修改 include/extend.func.php 文件来实现。
步骤 1:创建自定义函数
打开 /include/extend.func.php 文件,在文件末尾添加以下 PHP 函数:
/**
* SQL分页函数
* @param string $query 查询语句
* @param int $pagesize 每页记录数
* @return string 返回分页HTML
*/
function GetSqlPage($query, $pagesize = 10) {
global $dsql, $pageno;
// 1. 获取总记录数
$countQuery = "SELECT COUNT(*) AS num FROM (" . $query . ") AS subquery";
$row = $dsql->GetOne($countQuery);
$totalResult = $row['num'];
// 2. 计算总页数
$totalPage = ceil($totalResult / $pagesize);
// 3. 获取当前页码
if(empty($pageno)) {
$pageno = 1;
}
if($pageno > $totalPage) {
$pageno = $totalPage;
}
// 4. 计算偏移量
$start = ($pageno - 1) * $pagesize;
// 5. 获取当前页的数据
$sql = $query . " LIMIT {$start}, {$pagesize}";
$dsql->Execute('me',$sql);
$items = array();
while($row = $dsql->GetArray('me')) {
$items[] = $row;
}
// 6. 生成数据列表HTML
$html = '';
if(count($items) > 0) {
foreach($items as $item) {
// 这里循环输出每一行数据,你可以根据需要修改
$html .= "<li>";
$html .= "用户名: " . $item['uname'] . " | ";
$html .= "邮箱: " . $item['email'] . " | ";
$html .= "注册时间: " . MyDate('Y-m-d H:i:s', $item['jointime']);
$html .= "</li>";
}
} else {
$html = "<li>暂无数据</li>";
}
// 7. 生成分页导航HTML
$pageNav = '';
// 引入DedeCMS的分页类
// 引入DedeCMS的分页类
require_once(DEDEINC.'/datalistcp.class.php');
$dl = new DataListCP();
$dl->pageSize = $pagesize;
$dl->SetParameter('pageno', $pageno);
$dl->SetTemplate(""); // 不需要模板,直接生成HTML
$dl->SetSource($totalResult);
$pageNav = $dl->GetPageList();
// 8. 返回数据列表和分页导航的组合
return $html . $pageNav;
}
函数说明:
- 这个函数接收一个 SQL 查询语句(不带
SELECT和LIMIT)和每页记录数。 - 它会先执行
COUNT(*)计算总数,然后根据pageno和pagesize计算出当前页的数据。 - 它拼接出数据列表的 HTML 和分页导航的 HTML,并返回。
步骤 2:在模板中调用自定义函数
你的模板文件会变得非常简洁。
<h2>会员列表 (完整SQL分页)</h2>
<div>
{dede:global name='phpmy' function='GetSqlPage("mid, uname, email, jointime FROM dede_member ORDER BY jointime DESC", 10)'/}
</div>
模板代码解释:
{dede:global name='phpmy' ...}: 这是一个调用 PHP 函数的通用方法。function='GetSqlPage(...)': 指定要调用的函数名就是我们刚刚创建的GetSqlPage。"mid, uname, email, jointime FROM dede_member ORDER BY jointime DESC": 传入的第一个参数,即我们的核心查询语句。10: 传入的第二个参数,即每页显示10条记录。
这样,当页面加载时,GetSqlPage 函数会被执行,它会返回包含数据列表和分页导航的完整 HTML 代码,并显示在页面上。
总结与注意事项
- 性能问题:
{dede:sql}绕过了 DedeCMS 的缓存机制,每次页面请求都会直接查询数据库,如果数据量很大或访问频繁,会对数据库造成较大压力,请谨慎使用。 - 安全风险:直接使用 SQL 查询存在 SQL 注入的风险,如果你的查询参数来自用户输入(如 URL 中的 ID),必须对参数进行严格的过滤和转义,使用
$dsql->GetOne()或$dsql->Execute()来预处理参数。 - 适用场景:
{dede:sql}最适合用于展示一些固定不变或更新不频繁的数据,比如公司简介、团队成员列表等,对于频繁更新的内容,仍然建议使用 DedeCMS 的内置模型(如文章、图集)。 - 调试:如果分页不工作,请检查:
- SQL 语句是否正确。
- 自定义函数
GetSqlPage是否已成功添加到extend.func.php。 - 模板中调用函数的语法是否正确。
- 检查浏览器地址栏中
pageno参数是否正确传递(yourlist.php?pageno=2)。
希望这份详细的教程能帮助你掌握 DedeCMS 的 SQL 分页功能!
