将列转换为行

时间:2017-03-20 04:26:45

标签: sql postgresql unpivot

我有一张表table1,如下所示

+----+------+------+------+------+------+
| id | loc  | val1 | val2 | val3 | val4 |
+----+------+------+------+------+------+
|  1 | loc1 |   10 | 190  | null |   20 |
|  2 | loc2 |   20 | null | 10   |   10 |
+----+------+------+------+------+------+

需要将val1和val4组合成一个新列val,每列都有一行,以便输出如下所示。

注意: - 我的数据我有val1到val30 - >即。每行30列,需要转换为行。

+----+------+--------+
| id | loc  |  val   |
+----+------+--------+
|  1 | loc1 |   10   |
|  1 | loc1 |   190  |
|  1 | loc1 |   null |
|  1 | loc1 |   20   |
|  2 | loc2 |   20   |
|  2 | loc2 |   null |
|  2 | loc2 |   10   |
|  2 | loc2 |   10   |
+----+------+--------+

4 个答案:

答案 0 :(得分:1)

您可以使用cross join generate_series来实现此目的:

select
    id,
    loc,
    case x.i
        when 1 then val1 
        when 2 then val2
        . . .
    end as val
from t 
cross join generate_series(1, 4) x (i)

它只使用一次表格,可以轻松扩展以容纳更多列。

Demo

注意 :在接受的答案中,第一种方法多次读取表格(与未转用的列一样多次),第二种方法错误postgresql中没有UNPIVOT。

答案 1 :(得分:1)

您可以将横向连接用于变换列到行:

rootType

如果您希望使用动态添加列:

package com.holi.jackson;

import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonIgnoreType;
import com.fasterxml.jackson.annotation.JsonView;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.introspect.NopAnnotationIntrospector;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import com.jayway.jsonassert.JsonAssert;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static com.fasterxml.jackson.annotation.PropertyAccessor.FIELD;
import static com.fasterxml.jackson.databind.SerializationFeature.FAIL_ON_EMPTY_BEANS;
import static com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter.serializeAllExcept;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.jupiter.api.Assertions.assertEquals;

/**
 * Created by holi on 3/20/17.
 */
public class Jackson2SerializingFilteringTest {
    private final User bob = new User("bob", "123456", "bob@example.com");
    private final ObjectMapper jackson2 = new ObjectMapper();


    @BeforeEach
    void configure() {
        jackson2.registerModules(configuration());
        //write {} for empty bean
        jackson2.disable(FAIL_ON_EMPTY_BEANS);
        jackson2.setFilterProvider(serializeAll());
        jackson2.setVisibility(FIELD, Visibility.ANY);
    }

    private Module configuration() {
        return new SimpleModule() {
            @Override
            public void setupModule(SetupContext context) {
                context.insertAnnotationIntrospector(filterIdAsClassName());
            }
        };
    }

    private NopAnnotationIntrospector filterIdAsClassName() {
        return new NopAnnotationIntrospector() {
            @Override
            public Object findFilterId(Annotated ann) {
                return ann.getRawType().getName();
            }

            @Override
            public Version version() {
                return super.version();
            }
        };
    }

    private SimpleFilterProvider serializeAll() {
        SimpleFilterProvider filters = new SimpleFilterProvider();
        //serialize all if filter not found,rather than throws an exception
        filters.setFailOnUnknownId(false);
        return filters;
    }

    @Test
    void serializingAll() throws JsonProcessingException {
        String json = jackson2.writer().writeValueAsString(bob);

        JsonAssert.with(json)
                .assertThat("$[*]", hasSize(3))
                .assertEquals("name", bob.name)
                .assertEquals("password", bob.password)
                .assertEquals("mail", bob.mail);
    }

    @Test
    void serializingAllExceptIgnoredProperties() throws JsonProcessingException {
        @JsonIgnoreProperties({"name", "version"})
        class JSONRoot {
            String name = "jackson";
            String version = "2.0";
        }
        JSONRoot root = new JSONRoot();

        String json = jackson2.writer().writeValueAsString(root);

        assertEquals("{}", json);
    }

    @Test
    void serializingAllExceptIgnoredProperty() throws JsonProcessingException {
        class JSONRoot {
            String name = "jackson";
            @JsonIgnore
            String version = "2.0";
        }
        JSONRoot root = new JSONRoot();

        String json = jackson2.writer().writeValueAsString(root);

        JsonAssert.with(json)
                .assertThat("$[*]", hasSize(1))
                .assertEquals("name", root.name);
    }

    @Test
    void serializingAllExceptIgnoredType() throws JsonProcessingException {
        @JsonIgnoreType
        class Ignored {
        }
        class JSONRoot {
            Ignored ignored = new Ignored();
        }

        String json = jackson2.writer().writeValueAsString(new JSONRoot());

        assertEquals("{}", json);
    }

    @Test
    void serializingMixInAnnotations() throws JsonProcessingException {
        jackson2.addMixIn(User.class, ExcludingMail.class);

        String json = jackson2.writer().writeValueAsString(bob);

        JsonAssert.with(json)
                .assertThat("$[*]", hasSize(2))
                .assertEquals("name", bob.name)
                .assertEquals("password", bob.password);
    }

    @Test
    void serializingUseFiltersToExcludingProperties() throws JsonProcessingException {
        String json = jackson2.writer(excludes("password")).writeValueAsString(bob);

        JsonAssert.with(json)
                .assertThat("$[*]", hasSize(2))
                .assertEquals("name", bob.name)
                .assertEquals("mail", bob.mail);
    }

    @Test
    void serializingRootTypePropertiesOnly() throws JsonProcessingException {
        String json = jackson2.writerFor(Contactable.class).writeValueAsString(bob);

        JsonAssert.with(json)
                .assertThat("$[*]", hasSize(1))
                .assertEquals("mail", bob.mail);
    }

    @Test
    void serializingViewPropertiesOnly() throws JsonProcessingException {
        String json = jackson2.writerWithView(Public.class).writeValueAsString(bob);

        JsonAssert.with(json)
                .assertThat("$[*]", hasSize(2))
                .assertEquals("name", bob.name)
                .assertEquals("mail", bob.mail);
    }

    private SimpleFilterProvider excludes(String... propertyNames) {
        SimpleFilterProvider filters = serializeAll();
        filters.addFilter(User.class.getName(), serializeAllExcept(propertyNames));
        return filters;
    }


    private class User implements Contactable {
        final String name;
        @JsonView(Privacy.class)
        String password;
        @JsonView(Public.class)
        final String mail;

        public User(String name, String password, String mail) {
            this.name = name;
            this.password = password;
            this.mail = mail;
        }

        public String getMail() {
            return mail;
        }
    }

    @interface Public {
    }

    @interface Privacy {
    }

    private interface Contactable {
        String getMail();
    }

    @JsonIgnoreProperties("mail")
    private class ExcludingMail {
    }
}

请查看此链接以获取更多详细信息:Columns to rows

答案 2 :(得分:0)

我确信这是一种比这更优雅的方法。

SELECT * FROM (
select id, loc, val1 as val from #t a
UNION ALL
select id, loc, val2 as val from #t a
UNION ALL
select id, loc, val3 as val from #t a
UNION ALL
select id, loc, val4 as val from #t a
) x
order by ID

这是我尝试使用unpivot,但无法获取空值,也许是为空值执行连接?无论如何我还是会尝试

SELECT *
FROM (
SELECT * FROM #t
) main
UNPIVOT (
    new_val 
    FOR val IN (val1, val2, val3, val4) 
) unpiv

答案 3 :(得分:0)

根据用户需要,它不适用于postgress。看到评论中提到它。

我正在寻找一种处理" NULL"

的方法
select p.id,p.loc,CASE WHEN p.val=0 THEN NULL ELSE p.val END AS val
from 
(
    SELECT id,loc,ISNULL(val1,0) AS val1,ISNULL(val2,0) AS val2,ISNULL(val3,0) AS val3,ISNULL(val4,0) AS val4
    FROM Table1
)T
unpivot
(
  val
  for locval in(val1,val2,val3,val4)
)p

Test

<强> 编辑:

我方面的最佳解决方案:

select a.id,a.loc,ex.val
from (select 'val1' as [over] union all select 'val2' union all select 'val3'
        union all select 'val1' ) pmu
cross join (select id,loc from Table1) as a
left join
Table1 pt
unpivot
(
 [val]
 for [over] in (val1, val2, val3, val4)
) ex
on pmu.[over] = ex.[over] and
   a.id = ex.id

Test