如何取消透视多个列并从任一列中排除值?
Posted
技术标签:
【中文标题】如何取消透视多个列并从任一列中排除值?【英文标题】:How can I unpivot multiple columns and exclude values from either column? 【发布时间】:2016-01-18 23:08:59 【问题描述】:我有一个表,其中包含一个id
和两个产品列product
和product_other
。 product
列可能有一个有效的产品名称、单词“其他”,或者是空白的,因为它来自源。如果product
为“其他”,则product_other
应具有有效的产品名称,否则可能为空白或随机包含有效的产品名称。
我需要将所有有效的产品名称拉到一个列中,并排除空白和“其他”条目。到目前为止,我已经尝试了两种方法,UNION
方法如下:
SELECT DISTINCT * FROM
(
SELECT id
, COALESCE(NULLIF(NULLIF(product, 'other'), ''), 'UNKNOWN') AS product
FROM myTable
UNION
SELECT id
, COALESCE(NULLIF(product_other, ''), 'UNKNOWN') AS product
FROM myTable
) k
ORDER BY id
这会生成所有行,包括 product
的“UNKNOWN”值和同一 product_other
的有效产品名称 id
,但它应该只提供有效名称(如果有的话)。
我使用的另一种方法是下面的CASE WHEN
方法:
SELECT id
, CASE COALESCE(NULLIF(product, ''), 'UNKNOWN')
WHEN 'other' THEN COALESCE(NULLIF(product_other, ''), 'UNKNOWN')
ELSE COALESCE(NULLIF(product_other, ''), 'UNKNOWN')
END AS product
FROM myTable
ORDER BY id
然而,这个仅生成了一个有效product
的列表(如果可用)或product_other
(当product
为“其他”或空白时)。它排除了存在有效 product
product 和 product_other 值的情况。
另一种看待它的方式是,如果您 SELECT id, count(*) FROM (
either 查询为 k ) GROUP BY id
,则在第一种情况下,无论一个是否为“UNKNOWN”,都会有行数为 2,而第二个将始终每个 id
只有 1 行。
所以,myTable
看起来像这样:
id product product_other
------ --------- ---------------
155535 OTC COM
155536 OTC
155537 other COM
155538
我希望查询结果如下所示:
id product
------ ---------
155535 OTC
155535 COM
155536 OTC
155537 COM
155538 UNKNOWN
谢谢。
【问题讨论】:
【参考方案1】:试试这个:
CREATE TABLE #temp (id int , product varchar(10), product_other VARCHAR(10))
INSERT INTO #temp
VALUES(155535,'OTC','COM'),
(155536, '' ,'OTC'),
(155537,'other','COM'),
(155538,'','')
SELECT id
, CASE WHEN COALESCE(NULLIF(product, ''),NULLIF(product_other, '')) = 'other' AND NULLIF(product_other, '') IS NOT NULL THEN product_other
WHEN COALESCE(NULLIF(product, ''),NULLIF(product_other, '')) IS NULL AND NULLIF(product_other, '') IS NULL THEN 'UNKNOWN'
ELSE COALESCE(NULLIF(product, ''),NULLIF(product_other, '')) END AS product
FROM #temp
UNION
SELECT id
,CASE WHEN COALESCE(NULLIF(product_other, ''),NULLIF(product, '')) = 'other' AND NULLIF(product, '') IS NOT NULL THEN product_other
WHEN COALESCE(NULLIF(product_other, ''),NULLIF(product, '')) IS NULL AND NULLIF(product, '') IS NULL THEN 'UNKNOWN'
ELSE COALESCE(NULLIF(product_other, ''),NULLIF(product, '')) END AS product
FROM #temp;
结果:
所以本质上是这样的逻辑:
SELECT id
, CASE WHEN COALESCE(NULLIF(product, ''),NULLIF(product_other, '')) = 'other' AND NULLIF(product_other, '') IS NOT NULL THEN product_other
WHEN COALESCE(NULLIF(product, ''),NULLIF(product_other, '')) IS NULL AND NULLIF(product_other, '') IS NULL THEN 'UNKNOWN'
ELSE COALESCE(NULLIF(product, ''),NULLIF(product_other, '')) END AS product
FROM myTable
UNION
SELECT id
,CASE WHEN COALESCE(NULLIF(product_other, ''),NULLIF(product, '')) = 'other' AND NULLIF(product, '') IS NOT NULL THEN product_other
WHEN COALESCE(NULLIF(product_other, ''),NULLIF(product, '')) IS NULL AND NULLIF(product, '') IS NULL THEN 'UNKNOWN'
ELSE COALESCE(NULLIF(product_other, ''),NULLIF(product, '')) END AS product
FROM myTable;
【讨论】:
通过一些小改动,这非常适合我的情况。有时,使用大量代码流处理每种情况比将数据转出更有意义。 很高兴能帮上忙。【参考方案2】:SELECT *
FROM myTable
UNPIVOT(product_name FOR product_type IN (product, product_other)) u
WHERE
u.product_name NOT IN ('', 'other');
SQLFiddle
【讨论】:
这个删除了像 155538 这样只有一个空白的条目,但需要将它们转换为 'UNKNOWN'。此外,SQLFiddle 对我来说似乎坏了,但它可能只是这台计算机的体系结构阻止它完全加载。以上是关于如何取消透视多个列并从任一列中排除值?的主要内容,如果未能解决你的问题,请参考以下文章