使用 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;
我有一个场景,我从多个表中提取数据并且输出是固定宽度格式。固定宽度输出将如下所示:
当前输出:
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;