Can you split/explode a field in a MySQL query?

后端 未结 17 873
无人及你
无人及你 2020-11-22 04:03

I have to create a report on some student completions. The students each belong to one client. Here are the tables (simplified for this question).

CREATE TAB         


        
17条回答
  •  灰色年华
    2020-11-22 04:44

    MySQL's only string-splitting function is SUBSTRING_INDEX(str, delim, count). You can use this, to, for example:

    • Return the item before the first separator in a string:

      mysql> SELECT SUBSTRING_INDEX('foo#bar#baz#qux', '#', 1);
      +--------------------------------------------+
      | SUBSTRING_INDEX('foo#bar#baz#qux', '#', 1) |
      +--------------------------------------------+
      | foo                                        |
      +--------------------------------------------+
      1 row in set (0.00 sec)
      
    • Return the item after the last separator in a string:

      mysql> SELECT SUBSTRING_INDEX('foo#bar#baz#qux', '#', -1);
      +---------------------------------------------+
      | SUBSTRING_INDEX('foo#bar#baz#qux', '#', -1) |
      +---------------------------------------------+
      | qux                                         |
      +---------------------------------------------+
      1 row in set (0.00 sec)
      
    • Return everything before the third separator in a string:

      mysql> SELECT SUBSTRING_INDEX('foo#bar#baz#qux', '#', 3);
      +--------------------------------------------+
      | SUBSTRING_INDEX('foo#bar#baz#qux', '#', 3) |
      +--------------------------------------------+
      | foo#bar#baz                                |
      +--------------------------------------------+
      1 row in set (0.00 sec)
      
    • Return the second item in a string, by chaining two calls:

      mysql> SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('foo#bar#baz#qux', '#', 2), '#', -1);
      +----------------------------------------------------------------------+
      | SUBSTRING_INDEX(SUBSTRING_INDEX('foo#bar#baz#qux', '#', 2), '#', -1) |
      +----------------------------------------------------------------------+
      | bar                                                                  |
      +----------------------------------------------------------------------+
      1 row in set (0.00 sec)
      

    In general, a simple way to get the nth element of a #-separated string (assuming that you know it definitely has at least n elements) is to do:

    SUBSTRING_INDEX(SUBSTRING_INDEX(your_string, '#', n), '#', -1);
    

    The inner SUBSTRING_INDEX call discards the nth separator and everything after it, and then the outer SUBSTRING_INDEX call discards everything except the final element that remains.

    If you want a more robust solution that returns NULL if you ask for an element that doesn't exist (for instance, asking for the 5th element of 'a#b#c#d'), then you can count the delimiters using REPLACE and then conditionally return NULL using IF():

    IF(
        LENGTH(your_string) - LENGTH(REPLACE(your_string, '#', '')) / LENGTH('#') < n - 1,
        NULL,
        SUBSTRING_INDEX(SUBSTRING_INDEX(your_string, '#', n), '#', -1)
    )
    

    Of course, this is pretty ugly and hard to understand! So you might want to wrap it in a function:

    CREATE FUNCTION split(string TEXT, delimiter TEXT, n INT)
    RETURNS TEXT DETERMINISTIC
    RETURN IF(
        (LENGTH(string) - LENGTH(REPLACE(string, delimiter, ''))) / LENGTH(delimiter) < n - 1,
        NULL,
        SUBSTRING_INDEX(SUBSTRING_INDEX(string, delimiter, n), delimiter, -1)
    );
    

    You can then use the function like this:

    mysql> SELECT SPLIT('foo,bar,baz,qux', ',', 3);
    +----------------------------------+
    | SPLIT('foo,bar,baz,qux', ',', 3) |
    +----------------------------------+
    | baz                              |
    +----------------------------------+
    1 row in set (0.00 sec)
    
    mysql> SELECT SPLIT('foo,bar,baz,qux', ',', 5);
    +----------------------------------+
    | SPLIT('foo,bar,baz,qux', ',', 5) |
    +----------------------------------+
    | NULL                             |
    +----------------------------------+
    1 row in set (0.00 sec)
    
    mysql> SELECT SPLIT('foo###bar###baz###qux', '###', 2);
    +------------------------------------------+
    | SPLIT('foo###bar###baz###qux', '###', 2) |
    +------------------------------------------+
    | bar                                      |
    +------------------------------------------+
    1 row in set (0.00 sec)
    

提交回复
热议问题