6

これまで照会されることを意図していなかった Xml データであるため、複数の値を含む非正規フィールドがあります。MySQL はこの xml 列を複数の行に分割できますか?

テーブル

NameA   |   <Xml><Values<Value>1</Value><Value>2</Value><Value>3</Value></Values></Xml>
NameB   |   <Xml><Values<Value>1</Value><Value>2</Value></Values></Xml>
NameC   |   <Xml><Values<Value>1</Value><Value>2</Value><Value>3</Value><Value>4</Value></Values></Xml>

私が欲しい

NameA   |   1
NameA   |   2
NameA   |   3
NameB   |   1

この MSSQL/TSQL ソリューションのように

SELECT
    I.Name,
    Value.value('.','VARCHAR(30)') AS Value 
FROM
    Item AS I
CROSS APPLY
    Xml.nodes('/Xml/Values/Value') AS T(Value)
WHERE
    I.TypeID = 'A'

しかし、MySQLでは私は得ることができるだけです

NameA   |   123
NameB   |   12
NameC   |   1234

SELECT
    I.`Name`,
    ExtractValue(Xml,'/Xml/Values/Value') AS ListOfValues
FROM
    Item AS I
WHERE
    I.TypeID = 'A'
;

MySQLでxmlを分割するエレガントな方法はありますか?

4

1 に答える 1

8

いいえ。他の mysql 分割列の問題と同様に、これを解決する必要があります。

つまり、具体的にはこの回答に基づいています

DROP FUNCTION IF EXISTS STRSPLIT;
DELIMITER $$
CREATE FUNCTION STRSPLIT($Str VARCHAR(20000), $delim VARCHAR(12), $pos INTEGER) 
    RETURNS VARCHAR(20000)
BEGIN
    DECLARE output VARCHAR(20000);

    SET output = REPLACE(SUBSTRING(SUBSTRING_INDEX($Str, $delim, $pos)
                 , LENGTH(SUBSTRING_INDEX($Str, $delim, $pos - 1)) + 1)
                 , $delim
                 , '');

    IF output = '' 
        THEN SET output = null;
    END IF;

    RETURN output;
END $$

次のように値を反復処理できます

DROP PROCEDURE IF EXISTS GetNameValues $$
CREATE PROCEDURE GetNameValues()
BEGIN
    DECLARE i INTEGER;

    DROP TEMPORARY TABLE IF EXISTS TempList;
    CREATE TEMPORARY TABLE TempList(
        `Name` VARCHAR(256) COLLATE utf8_unicode_ci NOT NULL,
        `ValueList` VARCHAR(20000) COLLATE utf8_unicode_ci NOT NULL
    );
    DROP TEMPORARY TABLE IF EXISTS Result;
    CREATE TEMPORARY TABLE Result(
        `Name` VARCHAR(256) COLLATE utf8_unicode_ci NOT NULL,
        `Value` VARCHAR(128) COLLATE utf8_unicode_ci NOT NULL
    );

    INSERT INTO
        TempList
    SELECT
        I.`Name`,
        ExtractValue(Xml,'/Xml/Values/Value') AS ValueList
    FROM
        Item AS I
    WHERE
        I.TypeID = 'A'
    ;

    SET i = 1;
    REPEAT
        INSERT INTO
            Result
        SELECT
            `Name`,
            CAST(STRSPLIT(ValueList, ' ', i) AS CHAR(128)) AS Value
        FROM
            TempList
        WHERE 
            CAST(STRSPLIT(ValueList, ' ', i) AS CHAR(128)) IS NOT NULL
        ;

        SET i = i + 1;
        UNTIL ROW_COUNT() = 0
    END REPEAT;

    SELECT * FROM Result ORDER BY `Name`;
END $$

DELIMITER ;

CALL GetNameValues();

これがいつか誰かに役立つことを願っています。

于 2012-06-04T23:25:40.873 に答える