Условное извлечение данных фиксированной ширины с использованием SQL - PullRequest
0 голосов
/ 17 октября 2018

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

Токовый выход:

1001RJOHNKEITH25 20181017 NA
1002CDWANEKANE36 20181010 RR
1003CMIKAYLAGN44 20181011 RR

Требуемый выход:

1001RJOHNKEITH25 20181017 NA
1002CDWANEKANE36          NA
1003RMIKAYLAGN44 20181010 RR

В этом выводе 1001 - это идентификатор человека, R /C - это жестко запрограммированный индикатор, затем идет имя, возраст и дата регистрации, тип записи.Есть условие для даты регистрации.Если индикатор записи R, дата регистрации будет отображаться.В противном случае оно должно быть нулевым.Я не уверен, как написать условие, основанное на поле фиксированной ширины.

Прикрепленная демонстрационная программа Rextester: https://rextester.com/MKESI50760

Любая помощь?!

Ответы [ 5 ]

0 голосов
/ 17 октября 2018

Работа с данными фиксированной ширины:

Данные в текстовом файле или строке фиксированной ширины располагаются в строках и столбцах, по одной записи на строку.Каждый столбец имеет фиксированную ширину, указанную в символах, которая определяет максимальный объем данных, которые он может содержать.Разделители не используются для разделения полей в файле.

При анализе этих данных в T-SQL вы можете использовать SUBSTRING

https://docs.microsoft.com/en-us/sql/t-sql/functions/substring-transact-sql?view=sql-server-2017

SUBSTRING ( expression ,start , length ) 

Вот пример:

DECLARE @SampleData TABLE
    (
        [LineData] NVARCHAR(255)
    );

INSERT INTO @SampleData (
                            [LineData]
                        )
VALUES ( '1001RJOHNKEITH25 20181017 NA' )
     , ( '1002CDWANEKANE36 20181010 RR' )
     , ( '1003CMIKAYLAGN44 20181011 RR' );

SELECT SUBSTRING([LineData], 1, 4) AS [PersonId]
     , SUBSTRING([LineData], 5, 1) AS [Indicator]
     , SUBSTRING([LineData], 6, 9) AS [Name]
     , SUBSTRING([LineData], 15, 2) AS [Age]
     , SUBSTRING([LineData], 18, 8) AS [RegDate]
     , SUBSTRING([LineData], 27, 2) AS [RecordType]
     , *
FROM   @SampleData;

Итак, в вашем примере вы хотите оценить, является ли «Индикатор» «R», вы можете получить это значение с помощью:

SUBSTRING([LineData], 5, 1)

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

Не идеально, но вы можете разобрать все поля и затем собрать их вместе, выполняя оценку в этом поле индикатора или использовать материал воператор case для замены даты пробелами при оценке, если в строке указан индикатор R.

DECLARE @SampleData TABLE
    (
        [LineData] NVARCHAR(255)
    );

INSERT INTO @SampleData (
                            [LineData]
                        )
VALUES ( '1001RJOHNKEITH25 20181017 NA' )
     , ( '1002CDWANEKANE36 20181010 RR' )
     , ( '1003CMIKAYLAGN44 20181011 RR' );

--We check for R using substring
--when not equal to R we replace where Registration date in the string was with blanks.
SELECT CASE WHEN SUBSTRING([LineData], 5, 1) = 'R' THEN [LineData]
            ELSE STUFF([LineData], 18, 8, '        ')
       END AS [LineData]
FROM   @SampleData;
0 голосов
/ 17 октября 2018

ОК, это немного грязно.Но поскольку ваш вывод имеет фиксированную ширину, вы всегда можете превратить запрос в представление или CTE (как показано ниже), а затем получить доступ к определенным позициям в строке через функцию SUBSTRING.

Есть много недостатков для этого.Если кто-нибудь изменит порядок или размер полей, которые будут объединены ... все ломается.Итак, в духе ответа на ваш вопрос ... это способ сделать это.Но я не думаю, что это хороший способ.

WITH BaseQuery as

(
    select 
    t.Cid,
    cast
    (
     concat(
         LEFT(CONCAT(isnull(t.Cid,''),space(5)),5), -- PersonID
         LEFT(CONCAT(isnull
              ((case when t.registeredonline = '1' and t.recordtype = 'NA' then 'R'
                    else 'C' end),''),space(10)),10),-- Record Indicator
         LEFT(CONCAT(isnull(t.name,''),space(14)),14), --name
         LEFT(CONCAT(isnull(t.age,''),space(5)),5), --age
         LEFT(CONCAT(isnull(t.registrationdate,''),space(14)),14), -- Registration date should show up when record indicator is 'R'
         LEFT(CONCAT(isnull(t.recordtype,''),space(3)),3) --Record type  
         ) as nvarchar(max) 
        ) result
     from #temp t
)

SELECT
    CONCAT(
        SUBSTRING(result, 1, 34) -- portion before the 'registration date' region
        , CASE WHEN SUBSTRING (RESULT, 6, 1) = 'R' THEN SUBSTRING (RESULT, 35, 10) ELSE SPACE(10) END 
        , SUBSTRING (RESULT, 46, 5)
        )

FROM 
    BaseQuery

это дает результат:

1001 R         JOHNKEITH     25   2018-10-17   NA
1002 C         DWANEKANE     36                RR
1003 C         JOHNKEITH     44                RR
0 голосов
/ 17 октября 2018

Вам просто нужно обновить одну строку в вашем запросе:

LEFT(CONCAT(isnull(t.registrationdate,''),space(14)),14), -- Registration date should show up when record indicator is 'R'

становится

LEFT(CONCAT(isnull(CASE WHEN t.registeredonline = '1' and t.recordtype = 'NA' THEN CONVERT(char(10), t.registrationdate,126) ELSE NULL END,''),space(14)),14), -- Registration date should show up when record indicator is 'R'

Это проверит ваше поле даты и поставит пробелы вместо даты, когда логикадля индикатора записи значение равно 'R'

Требуется оператор 'convert', в противном случае дата NULL в итоге будет отображаться как 1900-01-01.

Надеюсь, это поможет.

0 голосов
/ 17 октября 2018

Строка

LEFT(CONCAT(isnull(t.registrationdate,''),space(14)),14)

становится

CASE WHEN t.registeredonline = '1' and t.recordtype = 'NA' THEN LEFT(CONCAT(isnull(t.registrationdate,''),space(14)),14) ELSE SPACE(14) END, --     Registration date should show up when record indicator is 'R'

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

0 голосов
/ 17 октября 2018

Выберите ColA, СЛУЧАЙ, КОГДА ColB (Критерии здесь), ТОЛЬКО NULL ИЛИ ColB КОНЕЦ КАК ColB, ColC

...