-1

Based on https://stackoverflow.com/a/59666211/4250302 I created the stored function get_enum_item for future processing the lists of possible values in the ENUM() type fields.

It works fine enough, but... but I can't determine what to do if the delimiter itself is the part of a string being split. For example: (square brackets are for readability)

mysql> set @q=",v1,',v2'" --empty string, "v1", "comma-v2";
mysql> select concat('[',get_enum_item(@q,',',0),']') as item;
+------+
| item |
+------+
| []   |
+------+

it is OK

mysql> select concat('[',get_enum_item(@q,',',1),']') as item;
+------+
| item |
+------+
| [v1] |
+------+

it is also OK

mysql> select concat('[',get_enum_item(@q,',',2),']') as item;
+------+
| item |
+------+
| [']  |
+------+

It is not OK

the @q contains 3 commas, the first two of these are real delimiters, while the last one is the part of the third possible value: "comma-v-two". And I have no idea how to avoid confusion of splitting function. MySQL WorkBench in the "form editor" mode solves this trouble somehow, but how can I solve this with MySQL's code?

Well, I can rely on the fact that the show_columns-like queries show the enums in "hardcoded" manner:

select column_name,column_type
  from information_schema.columns
  where data_type='enum' and table_name='assemblies';
+--------------+------------------------------------------------------------------+
| COLUMN_NAME  | COLUMN_TYPE                                                      |
+--------------+------------------------------------------------------------------+
| AssetTagType | enum('','И/Н','Н/Н',',fgg')                                      |
| PCTagType    | enum('','И/Н','Н/Н')                                             |
| MonTagType   | enum('','И/Н','Н/Н')                                             |
| UPSTagType   | enum('','И/Н','Н/Н')                                             |
| OtherTagType | enum('','И/Н','Н/Н')                                             |
| state        | enum('в работе','на списание','списано')                         |
+--------------+------------------------------------------------------------------+

Thus I can try to use ',' as a delimiter, but this will not save me from the case if the "comma-apostrophe" combination is the part of possible value... :-( The only thing I can imagine is to count apostrophes and if the delimiting comma is after the even number of ''s, then it is the delimiter, while if it follows an odd number of ''s, it is the part of the value. And I can't invent anything except for dumb scanning the input string inside the loop. But maybe there are some other suggestions to get the values split correctly?

Please, don't suggest use PHP, Python, AWK, and so on. The query will be executed from the Pascal (Lazarus, CodeTyphoon) application, and calling external processors is highly unsafe. As a last resort, I can process the column_type with Pascal's code, but at first, I must make myself sure that the task is not solvable by MySQL's features.

edit:

select column_type from information_schema.columns
where column_name='assettagtype' and table_name='assemblies';

+------------------------------------------+
| COLUMN_TYPE                              |
+------------------------------------------+
| enum('','И/Н','Н/Н',''''',fgg','''')     |
+------------------------------------------+
1 row in set (0.00 sec)

Fourth field: '',fgg, fifth field: '

Troublemaker-DV
  • 174
  • 1
  • 11
  • 1
    *"Please, don't suggest..."*: yes, I will. SQL is not intended for that. – trincot Mar 06 '21 at 08:31
  • Simpel column splitting is possible, see [this](https://stackoverflow.com/questions/1096679/can-mysql-split-a-column), but this seems to be more complex. I am sure it CAN be one in MySQL, but SHOULD it be done, that's the question ... – Luuk Mar 06 '21 at 09:00
  • CSV list has 2 special characteristics (format options) - quote char/substring and delimiting char/substring. They have equal relative priority, and I cannot understand - why you prefer quoter against delimiter? If quoter and/or delimiter may be a substring of a value then you must use another substring simply. If possible then use CHAR(0) as delimiter, in this case you do not need quoter almost always... – Akina Mar 06 '21 at 09:03
  • @Akina, I did not selected the delimiters and boundaries. They're part of result of "show_columns"-like functions. See the `column_type` column in the last example of my question. If there is any way to change default apostrophe and comma to another symbols, I would be very grateful for suggestion – Troublemaker-DV Mar 06 '21 at 09:15
  • @trincot, well... explode the string like: `'в работе','на списание','списано','',v3'` where the "apostrophe-comma" is the part of latest value in list. – Troublemaker-DV Mar 06 '21 at 09:19
  • Why tell me? I wouldn't do that in SQL. – trincot Mar 06 '21 at 09:20
  • *I did not selected the delimiters and boundaries. They're part of result of "show_columns"-like functions.* If so then use another functions, maybe even custom ones, which uses another quoter/delimiter. Anycase you must obtain non-ambiguous value. – Akina Mar 06 '21 at 09:35
  • *`set @q=",v1,',v2'" --empty string, "v1", "comma-v2";`* Please prove (not explain why but prove without ambiguity) that the vales are not `empty string`, `v1`, `'`, and `v2'`. – Akina Mar 06 '21 at 09:37
  • The problem is not clear, please give (an example) definition of a table where `SHOW COLUMNS FROM tablename` is giving some results. In your question you claim `",v1,',v2'"` is possible, but later on every column is between single quotes, which makes this example worthless? – Luuk Mar 06 '21 at 09:55
  • @Akina, may be because `'` between `,` is not escaped? – Troublemaker-DV Mar 06 '21 at 10:12
  • @Luuk, I used double quotes for setting the value of variable in CLI. But how to parse the BS like: mysql> show fields from assemblies; `| AssetTagType | enum('','И/Н','Н/Н',''''',fgg','''') ` 4th field: `'',fgg` 5th field: `'` – Troublemaker-DV Mar 06 '21 at 10:17
  • @Luuk, the problem is "how to parse possible list of ENUM values, if these values may contain the delimiting and boundary symbols", using MySQL's features – Troublemaker-DV Mar 06 '21 at 10:20
  • *may be because ' between , is not escaped?* Escaping only tells "This symbol is regular in any case". It does not affect anything else. – Akina Mar 06 '21 at 10:22
  • @Akina, you asked, I answered :-) – Troublemaker-DV Mar 06 '21 at 10:26

1 Answers1

1
set @q="'в работе','на списание','списано'";
WITH RECURSIVE cte as (
   select 1 as a union all
   select a+1 from cte where a<35
   )
select distinct  regexp_substr(@q,'''[^,]*''',a) as E from cte;
  • Too high values for 35 raise an error ERROR 3686 (HY000): Index out of bounds in regular expression search.. (I created a bug for this)
  • The null value should be filtered out...

output:

E
'в работе'
'на списание'
'списано'
null

EDIT: With some effort, this also works for a more complex example (not for every "staged" example!)

set @q="'в работе','на списание','списано',''',fgg'";
select @q;

WITH RECURSIVE cte as (
   select 1 as a union all
   select a+1 from cte where a<35
   )
select distinct regexp_substr(@q,'(''([^,]|[^''][^''])*'')',a) E  from cte;

output:

E
'в работе'
'на списание'
'списано'
''',fgg'
Luuk
  • 12,245
  • 5
  • 22
  • 33
  • As I could understand, you've used cte as the "loop with counter"? Good idea, but regexp is faulty. It works good for simple string (one in your example). But in case of special chars it failed: `enum('','И/Н','Н/Н',''''',fgg','''')` +---------+ | E | +---------+ | '' | | 'И/Н' | | 'Н/Н' | | ''''' | | '''' | | ''' | | NULL | +---------+ Note: there is no field with `'',fgg` value – Troublemaker-DV Mar 06 '21 at 11:19
  • It seems that there's no other way than dumb sequential scanning of entire input string... – Troublemaker-DV Mar 06 '21 at 11:20
  • Please provide (in your question) a 'complex' example! – Luuk Mar 06 '21 at 11:20
  • Is `enum('','И/Н','Н/Н',''''',fgg','''')` complex enough? Well, it is "staged" example, but it shows the things I concerned of. – Troublemaker-DV Mar 06 '21 at 11:24
  • I, personally, am not impressed by "staged" examples. will this be a valid on that is possibly returned by an ENUM ? – Luuk Mar 06 '21 at 11:26
  • it is the real output of "select ... from infoschema.columns". I added the textual screenshot to my question – Troublemaker-DV Mar 06 '21 at 11:33
  • As to filtering NULL, it is very simple: wrapping your SELECT into another one: `select E from (Luuk's_SELECT) as LuukSelect where not isnull(E);` This construct will be executed once for filling form's picklists, so I don't care about some overhead – Troublemaker-DV Mar 06 '21 at 11:40
  • I see, that the updated regexp is also not universal, while the idea is cool enough. Thank you for participation. I will think more on these regexp – Troublemaker-DV Mar 06 '21 at 12:37