如何取消透视多个列并从任一列中排除值?

Posted

技术标签:

【中文标题】如何取消透视多个列并从任一列中排除值?【英文标题】:How can I unpivot multiple columns and exclude values from either column? 【发布时间】:2016-01-18 23:08:59 【问题描述】:

我有一个表,其中包含一个id 和两个产品列productproduct_otherproduct 列可能有一个有效的产品名称、单词“其他”,或者是空白的,因为它来自源。如果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 productproduct_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 对我来说似乎坏了,但它可能只是这台计算机的体系结构阻止它完全加载。

以上是关于如何取消透视多个列并从任一列中排除值?的主要内容,如果未能解决你的问题,请参考以下文章

BigQuery - 选择多个列并希望排除两个双嵌套列

如何取消透视多列数据?

BigQuery - 如何取消嵌套多个数组,并从一列分配值?

将日期列取消透视到 Oracle 中复杂查询的单个列

PL/SQL:循环遍历 XML 列并从重复元素中提取值

从行创建/透视列并创建透视后,我想在 SQL 中新创建的列中添加不同列的值