织梦CMS的自定义查询主要通过两个核心标签来实现:

{dede:sql}:最常用、最灵活的标签,直接在模板中嵌入SQL语句。{dede:loop}:一个更底层的循环标签,通常与{dede:sql}配合使用,或者用于处理固定数组。
下面我将分步详细解释,并提供丰富的示例。
{dede:sql} 标签详解
这是进行自定义查询的主力标签,它的基本语法结构如下:
{dede:sql sql='你的SQL语句'}
// 循环体内,通过 [字段名] 来获取查询结果的值
<a href="[field:arcurl/]">[field:title/]</a>
<p>[field:pubdate function="MyDate('Y-m-d', @me)"/]</p>
<p>[field:body/]</p>
{/dede:sql}
核心属性
sql(必需属性): 这是你要执行的SQL查询语句。注意:语句必须用英文单引号 包裹。
循环体内字段调用
在 {dede:sql} 和 {/dede:sql} 之间,你可以像使用 {dede:arclist} 或 {dede:list} 一样,使用 [field:字段名/] 来获取查询结果中每一行的数据。
常用函数修饰
织梦允许你对获取到的字段值使用函数进行二次处理,这在处理时间、文本截取等方面非常有用。

-
时间格式化:
{dede:sql sql='SELECT pubdate FROM dede_archives LIMIT 5'} [field:pubdate function="MyDate('Y-m-d H:i:s', @me)"/] {/dede:sql}@me代表当前字段值(这里是pubdate)。MyDate是织梦内置的时间格式化函数。
-
文本截取:
{dede:sql sql='SELECT title FROM dede_archives LIMIT 5'} [field:title function="cn_substr(@me, 20)"/]... {/dede:sql}cn_substr是织梦的中文截取函数,可以安全处理中文字符,避免乱码。
-
其他函数: 你也可以使用PHP内置函数,如
htmlspecialchars(转义HTML)、strlen(获取长度) 等。
常见应用场景与示例
下面通过几个实际场景,让你更好地理解如何使用 {dede:sql}。

示例1:调用指定栏目ID下的文章列表
假设我们要调用栏目ID为 5 的文章,并显示标题、链接和发布时间。
<h3>栏目ID为5的最新文章</h3>
<ul>
{dede:sql sql='SELECT id, title, pubdate FROM dede_archives WHERE typeid = 5 ORDER BY pubdate DESC LIMIT 10'}
<li>
<a href="[field:arcurl/]" title="[field:title/]">[field:title/]</a>
<span>[field:pubdate function="MyDate('Y-m-d', @me)"/]</span>
</li>
{/dede:sql}
</ul>
说明:
typeid = 5: 筛选条件,只查询栏目ID为5的文章。ORDER BY pubdate DESC: 按发布时间降序排列。LIMIT 10: 限制只查询10条记录。[field:arcurl/]: 这里有个小问题,dede_archives表里没有直接的arcurl(文章链接) 字段,我们需要用id来拼接链接。
修正版(更常用):
{dede:sql sql='SELECT id, title, pubdate FROM dede_archives WHERE typeid = 5 ORDER BY pubdate DESC LIMIT 10'}
<li>
<a href="/plus/view.php?aid=[field:id/]" title="[field:title/]">[field:title/]</a>
<span>[field:pubdate function="MyDate('Y-m-d', @me)"/]</span>
</li>
{/dede:sql}
文章的默认链接格式是 /plus/view.php?aid=[文章ID]。
示例2:调用指定会员发布的所有文章
假设我们要查询会员ID为 100 的用户发布的所有文章标题和点击量。
<h3>会员ID为100发布的文章</h3>
<ul>
{dede:sql sql='SELECT title, click FROM dede_archives WHERE mid = 100'}
<li>
[field:title/] - 点击量: [field:click/]
</li>
{/dede:sql}
</ul>
说明:
mid = 100:mid是dede_archives表中记录文章所属会员的字段。
示例3:调用自定义模型(产品)的数据
假设你创建了一个自定义模型“产品”,模型ID为 6,你需要查询所有价格大于1000的产品。
<h3>高价产品列表</h3>
<ul>
{dede:sql sql='SELECT a.id, a.title, b.price FROM dede_archives AS a LEFT JOIN dede_addon6 AS b ON a.id = b.aid WHERE b.price > 1000'}
<li>
产品名: [field:title/] - 价格: [field:price/]元
<a href="/plus/view.php?aid=[field:id/]">查看详情</a>
</li>
{/dede:sql}
</ul>
说明:
- 多表关联: 自定义模型的附加表(如
dede_addon6)需要与主表dede_archives进行关联,使用LEFT JOIN和ON a.id = b.aid是标准做法。 - 表别名: 使用
AS a和AS b给表起别名,可以让SQL语句更简洁清晰。 - 字段前缀: 在调用字段时,不需要加表别名前缀,直接写
[field:price/]即可。
示例4:调用特定时间段内的文章
查询2025年1月1日之后发布的所有文章。
<h3>2025年以来的文章</h3>
<ul>
{dede:sql sql='SELECT title, pubdate FROM dede_archives WHERE pubdate > UNIX_TIMESTAMP("2025-01-01 00:00:00")'}
<li>
[field:title/] - 发布时间: [field:pubdate function="MyDate('Y-m-d', @me)"/]
</li>
{/dede:sql}
</ul>
说明:
UNIX_TIMESTAMP(): 是MySQL函数,用于将日期字符串转换为时间戳,便于比较。- 这种方法比在PHP中格式化时间再进行比较效率更高。
{dede:loop} 标签简介
{dede:loop} 通常用于两种情况:
- 执行一个不返回结果集的SQL语句(如
INSERT,UPDATE,DELETE)。 - 处理一个固定的PHP数组。
语法结构
{dede:loop table='数据表名' sort='排序字段' row='记录条数'}
// 循环体内,通过 [字段名] 获取值
[field:字段名/]
{/dede:loop}
示例:使用 loop 查询数据
它的功能与 {dede:sql} 类似,但语法更简单,灵活性较差。
{dede:loop table='dede_archives' sort='pubdate' row='5'}
<a href="/plus/view.php?aid=[field:id/]">[field:title/]</a>
<br>
{/dede:loop}
这个例子会从 dede_archives 表中按 pubdate 排序取出5条记录,但如果你需要 WHERE 条件,{dede:sql} 是更好的选择。
重要注意事项与最佳实践
-
安全第一:防止SQL注入! 当SQL语句中包含来自用户输入的变量时(如栏目ID、会员ID),绝对不能直接拼接,必须使用织梦提供的
GetOne或Select等安全方法,或者对变量进行严格的过滤和转义。 错误示范:$typeid = $_GET['typeid']; // 用户输入 // 错误!直接拼接,有巨大的SQL注入风险 {dede:sql sql='SELECT * FROM dede_archives WHERE typeid = $typeid'}正确做法(在PHP文件中处理): 如果你需要在PHP文件中执行,可以这样做:
require_once(dirname(__FILE__)."/include/common.inc.php"); $typeid = isset($_GET['typeid']) ? intval($_GET['typeid']) : 0; // 使用intval()强制转为整数 if($typeid > 0) { $dsql->SetQuery("SELECT id, title FROM dede_archives WHERE typeid = $typeid LIMIT 10"); $dsql->Execute(); while($row = $dsql->GetArray()) { echo "<a href='/plus/view.php?aid={$row['id']}'>{$row['title']}</a><br>"; } }在模板中,尽量使用固定的、已知的值来构造SQL。
-
性能考虑
- *避免使用 `SELECT
**: 尽量只查询你需要的字段,如SELECT id, title, pubdate`,这样可以减少数据传输量,提高查询速度。 - 为字段添加索引: 如果你的查询条件(
WHERE子句)经常用到的字段(如typeid,mid,pubdate),确保在数据库中为这些字段建立了索引,可以极大提升查询效率。 - 谨慎使用
LIMIT大数字:LIMIT 1000000会给数据库带来很大压力。
- *避免使用 `SELECT
-
表前缀 如果你的数据库表前缀不是默认的
dede_(例如修改为cms_),那么在写SQL语句时需要使用正确的表前缀。{dede:sql sql='SELECT id, title FROM cms_archives WHERE typeid = 5'}
| 功能 | 推荐标签 | 优点 | 缺点 |
|---|---|---|---|
复杂查询 (多表关联、WHERE、ORDER BY等) |
{dede:sql} |
功能最强大,最灵活,几乎支持所有SQL语法 | 语法相对复杂,需要一定的SQL基础 |
| 简单查询 (单表、无复杂条件) | {dede:loop} |
语法简单直观 | 功能有限,无法实现复杂条件 |
| 在PHP文件中执行 | $dsql 对象 |
最安全,性能最好,可结合PHP逻辑 | 需要修改PHP文件,不适合纯模板调用 |
对于绝大多数在模板中进行的自定义数据调用需求,{dede:sql} 是你的首选工具,只要掌握了它的基本用法和安全注意事项,你就可以轻松实现织梦CMS中几乎所有的自定义数据展示功能。
