Вычисление суммы значений, найденных в главной строке - PullRequest
0 голосов
/ 27 июня 2019

В настоящее время я работаю над данными по медицинской дозировке.Это большая таблица набора данных / оракула со строковой переменной, содержащей миллионы записей.строковая переменная выглядит следующим образом:

Drug_Direction
(1 JAN) INJECT 2ML (100MG) IV/IM AM THEN 0.5ML (25MG) 20 MIN LATER, THEN 2.5ML (125MG) PM
(SEP 20, 2018) INJECT 0.3ML (30MG) ON S1, 0.6ML (60MG) ON S2 AND 2ML(200MG) ON S3

Это примеры записей.Мне нужно найти дозы MG (Милиграмма) из этой основной строки и вычислить сумму.Например:

Required Output:
100+25+125=250
30+60+200=290`

Кроме того, строка не имеет фиксированного формата.и иногда есть изменения, такие как существует только 2 или 1 мг дозы.В таком случае.Мне нужно получить только те дозы MG.Я понимаю, что мне, возможно, потребуется подсчитать вхождения MG, найти числа и сделать сумму.Я работаю над этим одновременно.

Те же данные доступны и в Oracle.Так что если в Oracle-sql есть более простой способ сделать это, то это тоже приветствуется.

Ответы [ 2 ]

2 голосов
/ 27 июня 2019

Это довольно легко сделать в Oracle.Вы можете:

  1. Использовать REGEXP_COUNT для подсчета количества вхождений значений MG в каждой строке
  2. Использовать CONNECT BY для создания строки для каждого совпадения
  3. Используйте REGEXP_SUBSTR для получения каждого фактического соответствия
  4. Приведите строки к числовым значениям и сложите их

Примерно так:

WITH test_vals AS (
    SELECT '(1 JAN) INJECT 2ML (100MG) IV/IM AM THEN 0.5ML (25MG) 20 MIN LATER, THEN 2.5ML (125MG) PM' AS drug_direction FROM dual
    UNION ALL SELECT '(SEP 20, 2018) INJECT 0.3ML (30MG) ON S1, 0.6ML (60MG) ON S2 AND 2ML(200MG) ON S3' FROM dual
),

match_rows AS ( /* Get a row for each match */
    SELECT DISTINCT 
           m.drug_direction,
           LEVEL AS mg_occurrance_num
    FROM test_vals m
    CONNECT BY LEVEL <= REGEXP_COUNT(m.drug_direction, '((\d+\.)?\d+)MG') /* Count number of matches in each string */
)

SELECT r.drug_direction,
       SUM(
          TO_NUMBER(
              REGEXP_SUBSTR(
                  r.drug_direction, 
                  '((\d+\.)?\d+)MG', 
                  1, 
                  r.mg_occurrance_num, /* Search for this specific occurrance */
                  '', 
                  1 /* Get first sub-group (the actual numeric value) */
              )
          )
       ) AS total_mg_value
FROM match_rows r
GROUP BY r.drug_direction
ORDER BY r.drug_direction

Обратите внимание, чтопри этом предполагается, что все значения имеют точный формат (числовое значение, за которым следует строка «MG»).

1 голос
/ 27 июня 2019

Предполагая, что это отдельная текстовая строка, в Oracle вы можете использовать несколько рекурсивных выражений подзапроса для разбиения строки на подстроки:

Установка Oracle :

CREATE TABLE table_name ( id, value ) AS
  SELECT 1, '(1 JAN) INJECT 2ML (100MG) IV/IM AM THEN 0.5ML (25MG) 20 MIN LATER, THEN 2.5ML (125MG) PM'
            || '(SEP 20, 2018) INJECT 0.3ML (30MG) ON S1, 0.6ML (60MG) ON S2 AND 2ML(200MG) ON S3' FROM DUAL;

Запрос

WITH datelines ( id, value, dt, pos, lvl ) AS (
  SELECT id,
         value,
         REGEXP_SUBSTR(
           value,
           '\((([0-2]?\d|3[01]) (JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)|(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC) ([0-2]?\d|3[01]), \d{4})\)',
           1,
           1,
           NULL,
           1
         ),
         REGEXP_INSTR(
           value,
           '\((([0-2]?\d|3[01]) (JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)|(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC) ([0-2]?\d|3[01]), \d{4})\)',
           1,
           1
         ),
         1
  FROM   table_name
UNION ALL
  SELECT id,
         value,
         REGEXP_SUBSTR(
           value,
           '\((([0-2]?\d|3[01]) (JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)|(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC) ([0-2]?\d|3[01]), \d{4})\)',
           1,
           LVL + 1,
           NULL,
           1
         ),
         REGEXP_INSTR(
           value,
           '\((([0-2]?\d|3[01]) (JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)|(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC) ([0-2]?\d|3[01]), \d{4})\)',
           1,
           LVL + 1
         ),
         LVL + 1
  FROM   datelines
  WHERE  REGEXP_SUBSTR(
           value,
           '\((([0-2]?\d|3[01]) (JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)|(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC) ([0-2]?\d|3[01]), \d{4})\)',
           1,
           LVL + 1,
           NULL,
           1
         ) IS NOT NULL
),
actions ( id, dt, lvl, actions ) AS (
  SELECT id,
         dt,
         lvl,
         SUBSTR(
           value,
           pos + LENGTH( dt ) + 2,
           LEAD( pos, 1, LENGTH( value ) + 1 ) OVER ( PARTITION BY id ORDER BY lvl ) - pos - LENGTH( dt ) - 2
         )
  FROM   datelines
),
amounts ( id, dt, lvl, actions, amount, num_amounts, amount_lvl ) AS (
  SELECT id,
         dt,
         lvl,
         actions,
         TO_NUMBER( REGEXP_SUBSTR( actions, '\((\d+)MG\)', 1, 1, NULL, 1 ) ),
         REGEXP_COUNT( actions, '\((\d+)MG\)' ),
         1
  FROM   actions
UNION ALL
  SELECT id,
         dt,
         lvl,
         actions,
         TO_NUMBER( REGEXP_SUBSTR( actions, '\((\d+)MG\)', 1, amount_lvl + 1, NULL, 1 ) ),
         num_amounts,
         amount_lvl + 1
  FROM   amounts
  WHERE  amount_lvl < num_amounts
)
SELECT id,
       dt,
       SUM( amount ) AS total_amount
FROM   amounts
GROUP BY id, dt, lvl;

выход

ID | DT           | TOTAL_AMOUNT
-: | :----------- | -----------:
 1 | SEP 20, 2018 |          290
 1 | 1 JAN        |          250

дБ <> скрипка здесь


Обновление

Если каждая строка находится в отдельной строке таблицы базы данных, то:

Установка Oracle :

CREATE TABLE table_name ( id, value ) AS
  SELECT 1, '(1 JAN) INJECT 2ML (100MG) IV/IM AM THEN 0.5ML (25MG) 20 MIN LATER, THEN 2.5ML (125MG) PM' FROM DUAL UNION ALL
  SELECT 2, '(SEP 20, 2018) INJECT 0.3ML (30MG) ON S1, 0.6ML (60MG) ON S2 AND 2ML(200MG) ON S3' FROM DUAL;

Запрос

WITH amounts ( id, value, dt, amount, amount_index, num_amounts ) AS (
  SELECT id,
         value,
         REGEXP_SUBSTR( value, '\((.*?)\)', 1, 1, NULL, 1 ),
         TO_NUMBER( REGEXP_SUBSTR( value, '\((\d+)MG\)', 1, 1, NULL, 1 ) ),
         1,
         REGEXP_COUNT( value, '\((\d+)MG\)' )
  FROM   table_name
UNION ALL
  SELECT id,
         value,
         dt,
         TO_NUMBER( REGEXP_SUBSTR( value, '\((\d+)MG\)', 1, amount_index + 1, NULL, 1 ) ),
         amount_index + 1,
         num_amounts
  FROM   amounts
  WHERE  amount_index < num_amounts
)
SELECT id,
       MAX( dt ) AS dt,
       SUM( amount ) AS total_amount
FROM   amounts
GROUP BY id;

выход

ID | DT           | TOTAL_AMOUNT
-: | :----------- | -----------:
 1 | 1 JAN        |          250
 2 | SEP 20, 2018 |          290

дБ <> скрипка здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...