2015-12-09 3 views
-2

enter image description here У меня есть столбец notes длиной более 80,0000 символов.Как захватить текст из столбца БД в SQL Server 2012?

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

  • Первые 300 символов в Column_A
  • Next 300 символов в Column_B
  • Следующие 300 символов в Column_C

и так далее.

Так что я ищу выход, как показано ниже:

enter image description here

Для каждого идентификатора клиента с концом длиной колонки примечаний.

+1

Где ваш код! что вы уже пробовали? – Marusyk

+2

Это не очень понятно. У вас есть точные 3 столбца, а затем столько строк, сколько требуется?Это крайне уродливая вещь, которую вы делаете с вашими данными здесь. –

+0

Вот мой сценарий: \t \t \t КОГДА CN.Note НЕ NULL И CN.Note <> '' \t ТОГДА LEFT (ISNULL (CN.NOTE, КОСМОС (1)), 100) END 'SCATEXT', \t \t \t Случай, когда CN.Note НЕ NULL AND CN.Note <> '' \t \t ТОГДА SUBSTRING (ISNULL (CN.NOTE, пространство (1)), 101, 300) КОНЕЦ 'SCATEXT1', \t \t \t случае, когда КС. Примечание НЕ IS NULL И CN.Note <> '' \t \t ТОГДА SUBSTRING (ISNULL (CN.NOTE, пространство (1)), 301, 500) КОНЕЦ 'SCATEXT2', \t \t \t \t \t \t CASE КОГДА CN.Note NOT NULL AND CN.Note <> '' \t THEN \t SUBSTRING (ISNULL (CN.NOTE, SPACE (1)), 501, 700) END 'SCATEXT3' – Peter

ответ

1

Ouch! Это довольно сложное требование. Вам нужно будет объединить несколько навыков, чтобы решить эту проблему.

Во-первых, вам нужно создать дополнительные строки. Один из способов добиться этого - через recursion. В приведенном ниже примере я подсчитал, сколько строк требуется для каждого идентификатора клиента. Затем я использовал рекурсию для их создания.

Вам также необходимо разбить каждую строку на 3 300 символьных блоков. В моем примере я использовал 3 3 символьных блока, поэтому его легче читать. Но принцип будет расширяться. Используя SUBSTRING и номер записи, вы можете рассчитать начальную точку для каждого столбца.

Я создал несколько образцов записей в CTE под названием Raw. Это позволяет любому следовать примеру, который находится на Stack Data Exchange (ссылка ниже).

Example

DECLARE @ColumnWidth INT = 3;  -- Use to adjust required length of columns A, B and C. 
DECLARE @ColumnCount INT = 3;  -- Use to adjust number of output columns. 


WITH [Raw] AS 
    (
     /* This CTE creates sample records for us to experiment with. 
     * The note column contains each letter of the alphabet, repeated 
     * 3 times. The repeatition will help us validate the result set. 
     * 
     * Using ceiling, to round up, the field length (@ColumnWidth) and 
     * the number of fields (@ColumnCount) and the number of charaters (LEN) 
     * we can calculate how many rows are required. 
     */ 
     SELECT 
      r.ClientId, 
      r.Note, 
      CEILING(CAST(LEN(r.Note) AS DECIMAL(18, 8))/(@ColumnWidth * @ColumnCount)) AS RecordsRequired 
     FROM 
      (
       VALUES 
        (1, 'aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzz'), 
        (2, 'aaabbbcccdddeeefffggghhhiiijjjkkklll'), 
        (3, 'aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnno'), 
        (4, 'aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnoooppp'), 
        (5, 'aaabbbcccdddeeefffggghhhiiijjj'), 
        (6, 'aaabbbcccdd') 
      ) AS r(ClientId, Note) 
    ), 
    MultiRow AS 
    (
      /* This CTE uses recursion to return multiple rows for 
      * each orginal row. 
      * The number returned matches the RecordsRequired value 
      * from the Raw CTE. 
      */ 
      SELECT 
       1 AS RecordNumber, 
       RecordsRequired, 
       ClientId, 
       Note 
      FROM  
       [Raw] 

     UNION ALL 

      -- Keep repeating each record until the number of required rows has been returned. 
      SELECT 
       RecordNumber + 1 AS RecordNumber, 
       RecordsRequired, 
       ClientId, 
       Note 
      FROM  
       MultiRow 
      WHERE 
       RecordNumber < RecordsRequired 

    ) 
/* Each record returned by the MultiRow CTE is numbered: 1, 2, 3 etc. 
* Using this we can extract blocks of text from the orginal Note column. 
*/ 
SELECT 
    ClientId, 
    SUBSTRING(Note, ((@ColumnWidth * @ColumnCount) * RecordNumber) - ((@ColumnWidth * 3) -1), @ColumnWidth) AS Column_A, 
    SUBSTRING(Note, ((@ColumnWidth * @ColumnCount) * RecordNumber) - ((@ColumnWidth * 2) -1), @ColumnWidth) AS Column_B, 
    SUBSTRING(Note, ((@ColumnWidth * @ColumnCount) * RecordNumber) - ((@ColumnWidth * 1) -1), @ColumnWidth) AS Column_C 
FROM 
    MultiRow 
ORDER BY 
    ClientId, RecordNumber 
; 
+0

Да, я успешно вносил изменения в скрипты .. спасибо вам за помощь. Действительно оцените вашу помощь! – Peter

+0

Это отличная новость. –

1

Вот как вы можете это сделать:

DECLARE @c TABLE(ID INT, Notes VARCHAR(26)) 
INSERT INTO @c VALUES 
(1, 'abcdefghijklmnopqrstuvwxyz'), 
(2, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ') 

DECLARE @size INT = 26 
DECLARE @chunk INT = 5 

;WITH tally AS(SELECT 1 s1, @chunk + 1 s2, 2*@chunk + 1 s3 
       UNION ALL 
       SELECT s3 + @chunk, s3 + 2*@chunk, s3 + 3*@chunk FROM tally 
       WHERE s3 < @size) 
SELECT c.ID, 
     SUBSTRING(Notes, t.s1, @chunk) A, 
     SUBSTRING(Notes, t.s2, @chunk) B, 
     SUBSTRING(Notes, t.s3, @chunk) C 
FROM @c c 
CROSS JOIN tally t 
ORDER BY c.ID, t.s1 

Выход:

ID A  B  C 
1 abcde fghij klmno 
1 pqrst uvwxy z 
2 ABCDE FGHIJ KLMNO 
2 PQRST UVWXY Z 

Описание:

Tally таблица возвращает вам стартовое позиционирование ns, который вы будете использовать в функции substring. Для указанных выше конфигурации она возвращает:

s1 s2 s3 
1 6 11 
16 21 26 

Для этого используется рекурсивные ОТВАМИ распространяющихся стартовыми позиций по рядам с 3 исходным положением. Остальное должно быть легко понять.

+0

Я пробовал решение с использованием рекурсивного CTE, но я получал ошибку max recursion.couldn't устранить эту проблему. Вот почему я иду с методом looping – mindbdev

+0

@mindbdev, вы можете установить опцию 'FROM @cc CROSS JOIN tally t ORDER BY c.ID, t.s1 ОПЦИЯ (MAXRECURSION 0) ' –

+0

Большое спасибо. Я знал, что мы можем использовать 0 для этого, но я не мог вспомнить. Не знаю, как я пропустил его, когда я это сделал. Спасибо тебе за это. – mindbdev

0

Требуемый результат может быть получен с помощью простого зацикливание

/* Declare a temperory table for storing the results */ 
    DECLARE @Result_TABLE AS TABLE 
    ( 
    CustomerId  BIGINT 
    ,ColA   VARCHAR(300) 
    ,ColB   VARCHAR(300) 
    ,ColC   VARCHAR(300) 
    ) 

    DECLARE @CustomerCount INT  --To store customer count 
    DECLARE @IteratorForCustomers INT = 1 --To iterate for each customers 
    /* Get Count of cutomers */ 
    SELECT @CustomerCount = COUNT (1) FROM Customers 

    DECLARE @CustomerId BIGINT --To store customer id in looping 
    DECLARE @TempNote VARCHAR(MAX) -- To store customer note of each customer in looping 
    /* Loop for all customers */ 
    WHILE (@IteratorForCustomers <[email protected]) 
    BEGIN 
     ;WITH CTE AS 
     (
     SELECT 
     ROW_NUMBER() OVER (ORDER BY CustomerID) AS RowId 
     ,CustomerId 
     ,Customer_Note 
     FROM Customers 
     ) 
     SELECT 
      @CustomerId = a.CustomerId 
     ,@TempNote = a.Customer_Note 
     FROM CTE a 
     WHERE 
     RowId = @IteratorForCustomers 

     /* Loop for generating each row with three columns */ 
     WHILE (LEN(@TempNote)>0) 
     BEGIN 
      INSERT INTO @Result_TABLE 
      VALUES 

      (
      @CustomerId,SUBSTRING(@TempNote,1,300),SUBSTRING(@TempNote,301,300),SUBSTRING(@TempNote,601,300) 
      ) 

      SET @TempNote = CASE WHEN LEN(@TempNote)>900 THEN SUBSTRING(@TempNote,901,LEN(@TempNote)-900) 
          ELSE NULL END 


     END 

     SET @IteratorForCustomers = @IteratorForCustomers + 1 

    END 

    SELECT * FROM @Result_TABLE 
+0

Я немного изменил свой запрос таким же образом. У него также есть улучшение производительности. – Peter

Смежные вопросы