Рекурсивное самостоятельное объединение данных файла - PullRequest
0 голосов
/ 26 апреля 2018

Я знаю, что есть много вопросов о рекурсивных самообъединениях, но они в основном имеют иерархическую структуру данных следующим образом:

 ID   |   Value    | Parent id
 -----------------------------

Но мне было интересно, есть ли способ сделать это в конкретном случае, который у меня есть, когда у меня не обязательно есть родительский идентификатор. Мои данные будут выглядеть так, когда я начну загружать файл.

 ID   |  Line            | 
 -------------------------
 1    | 3,Formula,1,2,3,4,...
 2    | *,record,abc,efg,hij,...
 3    | ,,1,x,y,z,...
 4    | ,,2,q,r,s,...
 5    | 3,Formula,5,6,7,8,...
 6    | *,record,lmn,opq,rst,...
 7    | ,,1,t,u,v,...
 8    | ,,2,l,m,n,...

По сути, это CSV-файл, где каждая строка в таблице является строкой в ​​файле. Строки 1 и 5 идентифицируют заголовок объекта, а строки 3, 4, 7 и 8 идентифицируют строки, принадлежащие объекту. Строки заголовка объекта могут иметь только 40 атрибутов, поэтому объект разбит на несколько разделов в файле CSV.

То, что я хотел бы сделать, это взять таблицу, отделить столбец записи # и соединить его с собой несколько раз, чтобы получить что-то вроде этого:

 ID   |  Line            | 
 -------------------------
 1    | 3,Formula,1,2,3,4,5,6,7,8,...
 2    | *,record,abc,efg,hij,lmn,opq,rst
 3    | ,,1,x,y,z,t,u,v,...
 4    | ,,2,q,r,s,l,m,n,...

Я знаю, что это возможно, я просто не знаю, с чего начать. Моя первоначальная идея состояла в том, чтобы создать представление, которое разделяет первый и второй столбцы в представлении, и использовать это представление как способ повторного объединения этих двух столбцов. Однако у меня есть некоторые проблемы:

  1. Я не знаю, сколько разделов будет в файле для одного и того же объект
  2. Файл может содержать и другие объекты, поэтому объединение первых двух столбцов будет проблематичным, если у вас есть что-то вроде

 ID   |  Line            | 
 -------------------------
 1    | 3,Formula,1,2,3,4,...
 2    | *,record,abc,efg,hij,...
 3    | ,,1,x,y,z,...
 4    | ,,2,q,r,s,...
 5    | 3,Formula,5,6,7,8,...
 6    | *,record,lmn,opq,rst,...
 7    | ,,1,t,u,v,...
 8    | ,,2,l,m,n,...
 9    | ,4,Data,1,2,3,4,...
 10   | *,record,lmn,opq,rst,...
 11   | ,,1,t,u,v,...

В приведенном выше случае мой план может объединить строки из объекта Data в строке 9 с первыми строками объекта Formula путем сопоставления значения записи 1.

UPDATE

Я знаю, это несколько сбивает с толку. Я пытался сделать это с C # некоторое время назад, но мне пришлось в основном написать рекурсивный приличный синтаксический анализатор для анализа определенного формата файла, и это заняло много времени, потому что я должен был получить его в базе данных впоследствии, и это было слишком много для структуры лица , Конвертирование одного файла заняло несколько часов, поскольку эти файлы слишком велики.

В любом случае, @Nolan Shang имеет самый близкий результат к тому, что я хочу. Разница лишь в этом (извините за плохое форматирование):

+----+------------+------------------------------------------+-----------------------+
| ID | header     | x                                        | value                                         
|
+----+------------+------------------------------------------+-----------------------+
| 1  | 3,Formula, | ,1,2,3,4,5,6,7,8                         |3,Formula,1,2,3,4,5,6,7,8                     |
| 2  | ,,         | ,1,x,y,z,t,u,v                           | ,1,x,y,z,t,u,v                    |
| 3  | ,,         | ,2,q,r,s,l,m,n                           | ,2,q,r,s,l,m,n                    | 
| 4  | *,record,  | ,abc,efg,hij,lmn,opq,rst             |*,record,abc,efg,hij,lmn,opq,rst           |
| 5  | ,4,        | ,Data,1,2,3,4                            |,4,Data,1,2,3,4                               |
| 6  | *,record,  | ,lmn,opq,rst                             | ,lmn,opq,rst                                  |
| 7  | ,,         | ,1,t,u,v                                 | ,1,t,u,v                      |
+----+------------+------------------------------------------+-----------------------------------------------+

Ответы [ 2 ]

0 голосов
/ 26 апреля 2018

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

    DECLARE  @testdata TABLE(ID int,Line varchar(8000))
    INSERT INTO @testdata
        SELECT 1,'3,Formula,1,2,3,4,...' UNION ALL 
        SELECT 2,'*,record,abc,efg,hij,...'  UNION ALL 
        SELECT 3,',,1,x,y,z,...'  UNION ALL 
        SELECT 4,',,2,q,r,s,...'  UNION ALL 
        SELECT 5,'3,Formula,5,6,7,8,...'  UNION ALL 
        SELECT 6,'*,record,lmn,opq,rst,...'  UNION ALL 
        SELECT 7,',,1,t,u,v,...'  UNION ALL 
        SELECT 8,',,2,l,m,n,...'  UNION ALL 
        SELECT 9,',4,Data,1,2,3,4,...'  UNION ALL 
        SELECT 10,'*,record,lmn,opq,rst,...'  UNION ALL 
        SELECT 11,',,1,t,u,v,...'
    ;WITH t AS(
    SELECT *,REPLACE(SUBSTRING(t.Line,LEN(c.header)+1,LEN(t.Line)),',...','')  AS data
    FROM @testdata AS t
    CROSS APPLY(VALUES(LEFT(t.Line,CHARINDEX(',',t.Line, CHARINDEX(',',t.Line)+1 )))) c(header)
    )
    SELECT MIN(ID) AS ID,t.header,c.x,t.header+STUFF(c.x,1,1,'') AS value
    FROM t
    OUTER APPLY(SELECT ','+tb.data FROM t AS tb WHERE tb.header=t.header FOR XML PATH('') ) c(x)
    GROUP BY t.header,c.x
+----+------------+------------------------------------------+-----------------------------------------------+
| ID | header     | x                                        | value                                         |
+----+------------+------------------------------------------+-----------------------------------------------+
| 1  | 3,Formula, | ,1,2,3,4,5,6,7,8                         | 3,Formula,1,2,3,4,5,6,7,8                    |
| 3  | ,,         | ,1,x,y,z,2,q,r,s,1,t,u,v,2,l,m,n,1,t,u,v | ,,1,x,y,z,2,q,r,s,1,t,u,v,2,l,m,n,1,t,u,v    |
| 2  | *,record,  | ,abc,efg,hij,lmn,opq,rst,lmn,opq,rst     | *,record,abc,efg,hij,lmn,opq,rst,lmn,opq,rst |
| 9  | ,4,        | ,Data,1,2,3,4                            | ,4,Data,1,2,3,4                              |
+----+------------+------------------------------------------+-----------------------------------------------+
0 голосов
/ 26 апреля 2018

Я согласен, что было бы лучше экспортировать это на язык сценариев и делать это там. Это будет много работы в TSQL.

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

Одним из подходов было бы сделать LEFT JOIN для жестко закодированной таблицы возможных идентифицирующих подстрок, таких как:

3,Formula,
*,record,
,,1,
,,2,
,4,Data,

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

Затем вы выбираете SELECT из этой искусственно созданной таблицы (или производной таблицы или CTE) и LEFT JOIN к вашей фактической таблице с LIKE, чтобы получить все строки, которые используют каждое из этих значений в качестве своей начальной подстроки, удаляя начальные символы, чтобы получить остальную часть строки, и использовать XML-трюк STUFF..FOR , чтобы создать желаемый Line.

Способ получения столбца идентификатора зависит от того, что вы хотите, например, во втором примере, я не знаю, какой идентификатор вы хотите для строки ,4,Data,.... Вы хотите 5, потому что это следующее число в результатах, или вы хотите 9, потому что это идентификатор первого вхождения этой подстроки? Код соответственно. Если вы хотите 5, это ROW_NUMBER(). Если вы хотите 9, вы можете добавить столбец ID в искусственную таблицу, которую вы создали в начале этого подхода.

Кстати, на самом деле нет ничего рекурсивного в том, что вам нужно сделать, поэтому, если вы все еще думаете в этих терминах, сейчас самое время остановиться. Это скорее проблема «групповой конкатенации».

...