状況:
文字列とセットを返す式を受け取る、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[
]]>
]]>
]]]]><![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# で最初にユーザー テーブルをクエリしてから、ユーザーごとに学年とおもちゃに対して 2 つの追加クエリを実行する必要はありません。1000 ユーザーの場合、2001 クエリを実行することになるからです。
- また、すべての結合を使用してクエリを実行し、PHP または C# で結果セットを調べたくありません。これは、ユーザー名が成績の数におもちゃの数を掛けた回数だけ送信されるためです。巨大なブロブを含むユーザー フィールドがあることを想像してみてください。
- グレード/おもちゃがまだ二重に表示されるため、結合されたテーブルで GROUP_CONCAT を単純に使用することはできません。
- また、DISTINCT で GROUP_CONCAT を使用すると、Bart の 2 つの E のように、同一の成績が失われます。
したがって、現在、次のステートメントを使用して、2 つの依存サブクエリを含むこの結果を取得します。これはうまくいきます:
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などの経験がないので、丁寧に説明してください。