如何在 SQL 服务器中对 table 进行 UNPIVOT?
How to UNPIVOT a table in SQL Server?
我正在尝试对我的数据进行逆透视,但得到了一些奇怪的结果。我怎样才能做到这一点?
下面是我的代码和结果截图。 (SQL Fiddle)
select distinct recId, caseNumber, servtype, mins
from
(
select
recid
,caseNumber
,[preEnrollment_type]
,[preEnrollment_minutes]
,[screening_type]
,[screeningEnA_minutes]
,[ifsp_type]
,[ifsp_minutes]
from
CaseManagementProgressNote
where
[formComplete]=1
and [reviewed]<>1
and [dataentry]<>1
and [caseManagementEntry]=1
and [serviceCoordinator] <> 'webmaster@company.net'
and [contactDateTime] >= '1/1/2015'
and [childID] is not null
) as cp
unpivot
(
servType for servTypes in ([preEnrollment_type],[screening_type],[ifsp_type])
) as up1
unpivot
(
mins for minutess in ([preEnrollment_minutes],[screeningEnA_minutes],[ifsp_minutes])
) as up2
order by
recId
顶部是 奇怪的 unpivot
ed 数据,底部是实际的 table.
正如您在 unpivot
ed 数据中看到的那样,[column]_type
重复了两次并且对应值不正确。
我需要
1439 964699 -NA- null
1439 964699 SC 45
1439 964699 TCM FF 20
还要考虑到我还有更多专栏要 select。
这是我使用的参考资料mssqltips
SQL Fiddle 上面的例子。
您可以在这里使用 Cross Apply
代替 unpivot
。我发现语法更容易理解,并且您将能够保留空值。尝试类似的东西:
select recid, casenumber, servtype, mins
from CaseManagementProgressNote a
cross apply (VALUES (preEnrollment_type, preEnrollment_minutes),
(screening_type, screeningEna_Minutes),
(ifsp_type, ifsp_minutes)) unpvt (servtype, mins)
您的印象似乎是您的两个 UNPIVOT
操作不知何故 linked。它们不是,除了第二个 UNPIVOT
是对第一个的结果执行的。
如果您查看第一个 UNPIVOT
的结果:
select *
from
(
select
recid
,caseNumber
,[preEnrollment_type]
,[preEnrollment_minutes]
,[screening_type]
,[screeningEnA_minutes]
,[ifsp_type]
,[ifsp_minutes]
from
CaseManagementProgressNote
) as cp
unpivot
(
servType for servTypes in ([preEnrollment_type],[screening_type],[ifsp_type])
) as up1
你会看到
╔═════════╦═════════════╦════════════════════════╦═══════════════════════╦═══════════════╦═══════════╦════════════════════╗
║ recid ║ caseNumber ║ preEnrollment_minutes ║ screeningEnA_minutes ║ ifsp_minutes ║ servType ║ servTypes ║
╠═════════╬═════════════╬════════════════════════╬═══════════════════════╬═══════════════╬═══════════╬════════════════════╣
║ 143039 ║ 964699 ║ (null) ║ 45 ║ 20 ║ -NA- ║ preEnrollment_type ║
║ 143039 ║ 964699 ║ (null) ║ 45 ║ 20 ║ SC ║ screening_type ║
║ 143039 ║ 964699 ║ (null) ║ 45 ║ 20 ║ TCM FF ║ ifsp_type ║
╚═════════╩═════════════╩════════════════════════╩═══════════════════════╩═══════════════╩═══════════╩════════════════════╝
从这里应该清楚第二个 UNPIVOT
操作做了什么,为什么它给你它的结果:要从中得到你想要的结果,你 不 需要旋转。 UNPIVOT
将列转换为行。那不是你要找的。您已经有了想要的行。您想要的是将所有三个 minutes
列放在一个单独的列中,具体取决于 servTypes
。有很多方法可以做到这一点,例如通过向 SELECT
列表添加一个表达式,如下所示:
CASE servType
WHEN 'preEnrollment_type' THEN preEnrollment_minutes
WHEN 'screening_type' THEN screeningEnA_minutes
WHEN 'ifsp_type' THEN isfp_minutes
END
或者使用@ander2ed 的方法并完全删除 UNPIVOT
,如果您不介意它不会过滤掉 NULL
s。
您 link 的文章也涵盖了这个问题:
The only complication here is matching the output phone to the corresponding phone type - for this we need to do some string interrogation to ensure that Phone1 matches to PhoneType1, Phone2 matches to PhoneType2, etc.
做第二个UNPIVOT
,然后过滤结果就解决了。您可以通过 linking servTypes
和 minutess
使其工作。在您的特定示例数据中,它们的第一个字符足以识别,并且在两列中相同,因此您可以将 where left(servTypes, 1) = left(minutess, 1)
添加到您的查询中。
这对我来说似乎毫无意义地复杂,我不会推荐它,但这是文章和您的查询之间的区别,这就是您的查询在文章有效时无效的原因。
我正在尝试对我的数据进行逆透视,但得到了一些奇怪的结果。我怎样才能做到这一点?
下面是我的代码和结果截图。 (SQL Fiddle)
select distinct recId, caseNumber, servtype, mins
from
(
select
recid
,caseNumber
,[preEnrollment_type]
,[preEnrollment_minutes]
,[screening_type]
,[screeningEnA_minutes]
,[ifsp_type]
,[ifsp_minutes]
from
CaseManagementProgressNote
where
[formComplete]=1
and [reviewed]<>1
and [dataentry]<>1
and [caseManagementEntry]=1
and [serviceCoordinator] <> 'webmaster@company.net'
and [contactDateTime] >= '1/1/2015'
and [childID] is not null
) as cp
unpivot
(
servType for servTypes in ([preEnrollment_type],[screening_type],[ifsp_type])
) as up1
unpivot
(
mins for minutess in ([preEnrollment_minutes],[screeningEnA_minutes],[ifsp_minutes])
) as up2
order by
recId
顶部是 奇怪的 unpivot
ed 数据,底部是实际的 table.
正如您在 unpivot
ed 数据中看到的那样,[column]_type
重复了两次并且对应值不正确。
我需要
1439 964699 -NA- null
1439 964699 SC 45
1439 964699 TCM FF 20
还要考虑到我还有更多专栏要 select。
这是我使用的参考资料mssqltips
SQL Fiddle 上面的例子。
您可以在这里使用 Cross Apply
代替 unpivot
。我发现语法更容易理解,并且您将能够保留空值。尝试类似的东西:
select recid, casenumber, servtype, mins
from CaseManagementProgressNote a
cross apply (VALUES (preEnrollment_type, preEnrollment_minutes),
(screening_type, screeningEna_Minutes),
(ifsp_type, ifsp_minutes)) unpvt (servtype, mins)
您的印象似乎是您的两个 UNPIVOT
操作不知何故 linked。它们不是,除了第二个 UNPIVOT
是对第一个的结果执行的。
如果您查看第一个 UNPIVOT
的结果:
select *
from
(
select
recid
,caseNumber
,[preEnrollment_type]
,[preEnrollment_minutes]
,[screening_type]
,[screeningEnA_minutes]
,[ifsp_type]
,[ifsp_minutes]
from
CaseManagementProgressNote
) as cp
unpivot
(
servType for servTypes in ([preEnrollment_type],[screening_type],[ifsp_type])
) as up1
你会看到
╔═════════╦═════════════╦════════════════════════╦═══════════════════════╦═══════════════╦═══════════╦════════════════════╗ ║ recid ║ caseNumber ║ preEnrollment_minutes ║ screeningEnA_minutes ║ ifsp_minutes ║ servType ║ servTypes ║ ╠═════════╬═════════════╬════════════════════════╬═══════════════════════╬═══════════════╬═══════════╬════════════════════╣ ║ 143039 ║ 964699 ║ (null) ║ 45 ║ 20 ║ -NA- ║ preEnrollment_type ║ ║ 143039 ║ 964699 ║ (null) ║ 45 ║ 20 ║ SC ║ screening_type ║ ║ 143039 ║ 964699 ║ (null) ║ 45 ║ 20 ║ TCM FF ║ ifsp_type ║ ╚═════════╩═════════════╩════════════════════════╩═══════════════════════╩═══════════════╩═══════════╩════════════════════╝
从这里应该清楚第二个 UNPIVOT
操作做了什么,为什么它给你它的结果:要从中得到你想要的结果,你 不 需要旋转。 UNPIVOT
将列转换为行。那不是你要找的。您已经有了想要的行。您想要的是将所有三个 minutes
列放在一个单独的列中,具体取决于 servTypes
。有很多方法可以做到这一点,例如通过向 SELECT
列表添加一个表达式,如下所示:
CASE servType
WHEN 'preEnrollment_type' THEN preEnrollment_minutes
WHEN 'screening_type' THEN screeningEnA_minutes
WHEN 'ifsp_type' THEN isfp_minutes
END
或者使用@ander2ed 的方法并完全删除 UNPIVOT
,如果您不介意它不会过滤掉 NULL
s。
您 link 的文章也涵盖了这个问题:
The only complication here is matching the output phone to the corresponding phone type - for this we need to do some string interrogation to ensure that Phone1 matches to PhoneType1, Phone2 matches to PhoneType2, etc.
做第二个UNPIVOT
,然后过滤结果就解决了。您可以通过 linking servTypes
和 minutess
使其工作。在您的特定示例数据中,它们的第一个字符足以识别,并且在两列中相同,因此您可以将 where left(servTypes, 1) = left(minutess, 1)
添加到您的查询中。
这对我来说似乎毫无意义地复杂,我不会推荐它,但这是文章和您的查询之间的区别,这就是您的查询在文章有效时无效的原因。