使用 SQL 条件提取固定宽度数据

Conditional extraction of fixed width data using SQL

我有一个场景,我从多个表中提取数据并且输出是固定宽度格式。固定宽度输出将如下所示:

当前输出:

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

期望的输出:

1001RJOHNKEITH25 20181017 NA
1002CDWANEKANE36          NA
1003RMIKAYLAGN44 20181010 RR

在此输出中,1001 是人员 ID,R/C 是硬编码指示符,然后是姓名、年龄和注册日期、记录类型。注册日期有一个条件。如果记录指示符为 R,则将显示注册日期。否则,它应该为空。我不确定如何根据固定宽度字段编写条件。

附加 Rextester 演示:https://rextester.com/MKESI50760

有什么帮助吗?!

Select ColA, CASE WHEN ColB (Criteria here) THEN NULL ELSE ColB END AS ColB, ColC

您只需更新查询中的一行:

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。

希望对您有所帮助。

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'。 该条件显示在您的 link.

的查询中

好的,这有点乱。但是因为您的输出是固定宽度的,所以您始终可以将查询放入视图或 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

处理固定宽度数据:

Data in a fixed-width text file or string is arranged in rows and columns, with one entry per row. Each column has a fixed width, specified in characters, which determines the maximum amount of data it can contain. No delimiters are used to separate the fields in the file.

解析 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;

因此,在您的示例中,您想要评估 "Indicator" 是否为 'R',您可以通过以下方式获得该值:

SUBSTRING([LineData], 5, 1)

不确定这是否适合您的任务。根据其他评论,还有更多关于如何确定 "Indicator" 的内容。

不理想,但您可以解析出所有字段,然后将它们放回一起对该指示符字段进行评估,或者在评估指示符是否为 R 时使用 case 语句中的内容将日期替换为空白字符串.

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;