情况:
我想创建一个名为 XMLify 的 mysql 函数,它接受一个字符串和一个返回集合的表达式
XMLify(string, expr)
该函数应该将集合中每个返回行的每个返回字段包装到它自己的 XML 标记中。标签的名称应该是字段名称。
小例子:
select XMLify('foo', (SELECT 1 as `a`, 2 as `b` UNION SELECT 3 as `a`, 4 as `b`));
应该返回:
<foo><a>1</a><b>2</b></foo><foo><a>3</a><b>4</b></foo>
我想要这个,因为它使我能够运行具有许多连接和/或依赖子查询的复杂查询,而不必向客户端返回冗余数据。
我已经有了一个没有我想要构建的功能的解决方法。但这涉及编写不易维护的困难查询。请参阅下面的示例。
确保字段名称是合法的 XML 节点名称是为了以后担心。一旦函数成立,我会想到一些算法,将字段名称转换为一些合法的 XML 节点名称。
转义 XML 数据也是为了以后担心。这将通过一个名为 的不同函数来完成,该函数CDATAify
将简单地将所有数据包装到<![CDATA[
and]]>
中,并将数据中任何先前出现的 转义]]>
到 中]]]]><![CDATA[>
。
我无法使用 MySQL 中的存储函数来完成此操作,因为这些函数不包含结果集。此外,即使您将 SQL 作为字符串传递,然后准备语句并执行它,如果您还不知道字段名称,您也无法访问这些字段。
所以现在我想知道这个技巧是否可以用用户定义的函数(UDF)来完成。这是我还没有使用过的东西,我希望在入船之前得到你的建议。
问题:
所以我现在的问题是:
- 回顾一下,我想要一个 MySQL 函数,我可以传递一个表达式或结果集,并且我还可以在其中使用结果集的字段名称。
- 我是否正确地假设这在存储的函数中是不可能的?
- UDF 会将表达式/它们的结果集作为参数吗?
- UDF 是否允许我访问结果集的字段名称,因此我可以将它们用作 XML 标记名称
- 它也可以在 Windows 上运行吗?我读到 UDF 有一些限制
- 有没有更好的方法我还没有想到?
- 我能否拥有一个可以在我自己的开发计算机上创建的 UDF .dll,然后将 .dll 文件复制到我的服务器并在那里使用它?
- 我如何让这个节目一炮而红?请彻底并考虑到我在 Windows 计算机上安装了 MySQL 5.5 64 位。
例子:
想象一下有以下 3 个表:
users: grades: toys:
+----+------+ +--------+-------+ +--------+--------------+
| id | name | | userid | grade | | userid | toy |
+----+------+ +--------+-------+ +--------+--------------+
| 1 | Bart | | 1 | E | | 1 | slingshot |
| 2 | Lisa | | 1 | E | | 1 | Krusty |
| .. | ... | | 2 | A | | 2 | Malibu Stacy |
| .. | ... | | 2 | B | | 2 | calculator |
+----+------+ +--------+-------+ +--------+--------------+
我想要的结果是,仅限于 Bart 和 Lisa:
<users>
<user>
<id><![CDATA[1]]></id>
<name><![CDATA[Bart]]></name>
<grades>
<grade><![CDATA[E]]></grade>
<grade><![CDATA[E]]></grade>
</grades>
<toys>
<toy><![CDATA[slingshot]]></toy>
<toy><![CDATA[Krusty]]></toy>
</toys>
</user>
<user>
<id><![CDATA[1]]></id>
<name><![CDATA[Lisa]]></name>
<grades>
<grade><![CDATA[A]]></grade>
<grade><![CDATA[B]]></grade>
</grades>
<toys>
<toy><![CDATA[Malibu Stacey]]></toy>
<toy><![CDATA[calculator]]></toy>
</toys>
</user>
</users>
考虑:
- 我不希望在 PHP 或 C# 中必须首先查询用户表,然后每个用户运行两个额外的成绩和玩具查询。因为对于 1000 个用户,我将运行 2001 个查询。
- 我也不想运行一个包含所有连接的查询并通过 PHP 或 C# 中的结果集,因为用户名的发送次数与成绩数量乘以玩具数量一样多。想象一下,有一个包含巨大 blob 的用户字段!
- 我不能简单地在连接表上使用 GROUP_CONCAT,因为成绩/玩具仍然会出现双倍。
- 如果我将 GROUP_CONCAT 与 DISTINCT 一起使用,我将失去相同的成绩,例如 Bart 的两个 E。
所以目前我会使用下面的语句来得到这个结果,涉及两个依赖子查询。这很好用:
SELECT
CONCAT(
'<users>',
IFNULL(
GROUP_CONCAT(
'<user>',
'<id><![CDATA[',
REPLACE(u.id,']]>',']]]]><![CDATA[>'),
']]></id>',
'<name><![CDATA[',
REPLACE(u.name,']]>',']]]]><![CDATA[>'),
']]></name>',
'<grades>',
(
SELECT
IFNULL(
GROUP_CONCAT(
'<grade><![CDATA[',
REPLACE(g.grade,']]>',']]]]><![CDATA[>'),
']]></grade>'
SEPARATOR ''
),
'')
FROM
grades g
WHERE
g.userid = u.id
),
'</grades>',
'<toys>',
(
SELECT
IFNULL(
GROUP_CONCAT(
'<toys><![CDATA[',
REPLACE(t.toy,']]>',']]]]><![CDATA[>'),
']]></toys>'
SEPARATOR ''
),
'')
FROM
toys t
WHERE
t.userid = u.id
),
'</toys>',
'</user>'
SEPARATOR ''
),
''
),
'</users>'
)
FROM
users u
WHERE
u.name = 'Bart' or u.name = 'Lisa'
;
现在您可能会注意到,这是一个相当大且丑陋的查询,阅读时会伤眼睛。维护这样的查询很困难。如果我有我的函数 XMLify 和 CDATAify,我可以简单地写这个:
SELECT
XMLify('users',(
XMLify('user',(
SELECT
CDATAify(u.id) as id,
CDATAify(u.name) as name,
XMLify('grade',(
SELECT
CDATAify(g.grade) as grade
FROM
grades g
where
g.userid = u.id
)) AS grades,
XMLify('toys',(
SELECT
CDATAify(t.toy) as toy
FROM
toys t
where
t.userid = u.id
)) AS grades
FROM
users u
WHERE
u.name = 'Bart' or u.name = 'Lisa'
))
))
;
编辑:
正如 NB 的评论中提到的,在 Github 上有一个存储库,可能包含我需要的所有内容。然而,我现在花了几天时间试图让它在我的系统上运行,但没有成功。任何包含如何在 Windows 上运行的 MySQL 5.5 64 位服务器上安装它的分步操作方法的答案也是可以接受的。
请考虑到我没有使用 make、makefile 等方面的经验。所以请彻底解释。