核心思路
- 确定目标表:织梦的文章数据主要存储在
dede_archives(文章主表) 和dede_arctype(栏目表) 中,文章与栏目的关联字段是typeid。 - 编写SQL语句:我们需要编写一条
SELECT语句,从dede_archives表中查询数据,并通过WHERE子句来限定typeid必须在我们指定的栏目ID列表中。 - 在模板中执行:使用织梦的
{dede:sql}标签来执行我们写好的SQL语句,并将结果循环输出。
基础用法:调用指定ID的多个栏目
这是最直接的方法,假设你要调用栏目ID为 1, 3, 5 的文章。

(图片来源网络,侵删)
SQL语句
SELECT
id,
typeid,
litpic,
pubdate,
description
FROM
dede_archives
WHERE
typeid IN (1, 3, 5)
AND arcrank > -1 -- 可选:只显示已审核通过的文章
ORDER BY
pubdate DESC -- 按发布时间倒序排列
LIMIT 10; -- 可选:限制输出10条
SQL语句详解:
SELECT ... FROM dede_archives: 指定从文章主表查询。id, typeid, title, ...: 指定要查询的字段。id是文章ID,typeid是栏目ID,title,litpic是缩略图,pubdate是发布时间,description是摘要,你可以根据需要增减字段。WHERE typeid IN (1, 3, 5): 这是核心条件。IN关键字用于指定一个值列表,表示typeid字段的值必须是列表中的某一个。AND arcrank > -1: 这是一个非常好的实践。arcrank是文章状态,-1表示待审核,0表示正常,加上这个条件可以确保只调用已审核通过的文章,避免在前台显示未发布的草稿。ORDER BY pubdate DESC: 对结果进行排序,这里按发布时间倒序排列,让最新的文章显示在最前面。LIMIT 10: 限制返回的记录数为10条,防止数据量过大。
模板调用代码
将上面的SQL语句直接放入 {dede:sql} 标签中即可。
{dede:sql sql="SELECT id, typeid, title, litpic, pubdate, description FROM dede_archives WHERE typeid IN (1, 3, 5) AND arcrank > -1 ORDER BY pubdate DESC LIMIT 10"}
<li>
<a href="[field:typelink/]" class="class-a">[field:typename/]</a>
<a href="[field:arcurl/]" title="[field:title/]">[field:title function='cn_substr(@me,30)'/]</a>
<span class="dtime">[field:pubdate function='MyDate('Y-m-d',@me)'/]</span>
</li>
{/dede:sql}
注意:
- 在
{dede:sql}的结果集中,你仍然可以使用[field:字段名/]来获取查询出的字段值。 [field:arcurl/]和[field:typelink/]、[field:typename/]是织梦的特殊字段,虽然它们不在你的SQL查询中,但织梦会自动根据id和typeid来生成对应的链接和名称,非常方便。function='cn_substr(@me,30)'是对标题进行截断,防止过长。
进阶用法:调用指定顶级栏目及其所有子栏目
这是另一个非常常见的需求,你想调用“产品中心”(ID为2)这个顶级栏目及其下所有子栏目的文章。

(图片来源网络,侵删)
这里需要用到 dede_arctype 表,并利用 INSTR() 函数来判断一个栏目ID是否是另一个栏目的子栏目。
SQL语句
SELECT
a.id,
a.typeid,
a.title,
a.litpic,
a.pubdate,
a.description
FROM
dede_archives a,
dede_arctype t
WHERE
-- 核心判断逻辑:当前文章的typeid,是顶级栏目ID的子栏目
INSTR(',' + t.reid + ',', ',2,') > 0 -- 将顶级栏目ID替换成你的,2
AND a.typeid = t.id -- 关联文章表和栏目表
AND a.arcrank > -1 -- 只显示已审核文章
ORDER BY
a.pubdate DESC
LIMIT 10;
SQL语句详解:
FROM dede_archives a, dede_arctype t: 使用了表的别名(a代表archives,t代表arctype)来简化SQL语句。INSTR(',' + t.reid + ',', ',2,') > 0: 这是判断子栏目的关键。t.reid: 是当前栏目t的父级栏目ID,顶级栏目的reid为0。INSTR(string, substring): 函数用于查找字符串中是否包含子字符串,如果包含则返回位置(大于0),否则返回0。',' + t.reid + ',': 通过在reid前后都加上逗号,可以精确匹配,如果t.reid是2,',' + t.reid + ','就变成',2,',这样可以避免错误匹配(匹配12或20)。',2,': 这是我们要查找的顶级栏目ID的格式。请务必将2替换成你自己的顶级栏目ID。
AND a.typeid = t.id: 这是连接两个表的条件,确保我们查询的是真实存在的栏目。
模板调用代码
<h3>产品中心及其子栏目最新文章</h3>
<ul>
{dede:sql sql="SELECT a.id, a.typeid, a.title, a.litpic, a.pubdate, a.description FROM dede_archives a, dede_arctype t WHERE INSTR(',' + t.reid + ',', ',2,') > 0 AND a.typeid = t.id AND a.arcrank > -1 ORDER BY a.pubdate DESC LIMIT 10"}
<li>
<a href="[field:arcurl/]" title="[field:title/]" target="_blank">
<img src="[field:litpic/]" alt="[field:title/]" />
<span>[field:title function='cn_substr(@me,24)'/]</span>
</a>
</li>
{/dede:sql}
</ul>
更灵活的用法:通过栏目名称列表获取ID
我们可能不记得栏目ID,只知道栏目名称,我们可以先通过栏目名称查出ID,再拼接到主查询中。
SQL语句
这个SQL稍微复杂一点,它在一个查询中完成了所有操作。

(图片来源网络,侵删)
SELECT
a.id,
a.title,
a.litpic,
a.pubdate
FROM
dede_archives a
WHERE
a.typeid IN (
SELECT id FROM dede_arctype WHERE typename IN ('公司新闻', '产品动态', '行业资讯')
)
AND a.arcrank > -1
ORDER BY
a.pubdate DESC
LIMIT 10;
SQL语句详解:
WHERE typeid IN (SELECT id FROM ...): 这是一个子查询,数据库会先执行括号内的SELECT语句,得到一个ID列表((1, 3, 5)),然后外层的WHERE条件就变成了typeid IN (1, 3, 5),逻辑就和第一种方法一样了。typename IN ('公司新闻', '产品动态', '行业资讯'): 这里直接使用了栏目名称列表,更直观,请确保括号内的名称与你后台的栏目名称完全一致。
总结与最佳实践
| 场景 | 推荐方法 | 优点 | 缺点 |
|---|---|---|---|
| 调用固定ID的几个栏目 | typeid IN (1,3,5) |
SQL简单直观,性能好。 | 需要手动维护栏目ID列表,如果栏目ID改变,代码需修改。 |
| 调用一个顶级栏目及其所有子栏目 | INSTR(',' + t.reid + ',') |
非常灵活,顶级栏目下新增子栏目无需修改代码。 | SQL稍复杂,需要理解 reid 字段和 INSTR 函数。 |
| 通过栏目名称调用 | 子查询 | 无需关心ID,直接使用名称,可读性好。 | 性能略低于直接使用ID,且对名称的准确性要求高。 |
重要提示:
- 安全第一:在模板中直接写SQL有一定安全风险,如果SQL内容来自用户输入,容易被SQL注入,但用于固定调用后台栏目是安全的。
- 性能考虑:SQL查询比标签调用更底层,性能通常更好,尤其是在大数据量时,但复杂的SQL可能会给数据库带来压力。
- 缓存:织梦有自带的缓存机制,对于不经常变动的栏目列表,可以考虑开启缓存以提高页面加载速度。
- 调试:如果SQL语句出错,可以先在数据库管理工具(如phpMyAdmin)中直接运行,确认结果正确后再放入模板。
希望这份详细的指南能帮助你熟练掌握在织梦中使用SQL语句调用多栏目文章!
