将行转为多列

Not*_*tMe 22 oracle oracle-11g pivot linked-server

我有一个 SQL Server 实例,它具有到 Oracle 服务器的链接服务器。Oracle 服务器上有一个名为的表,PersonOptions其中包含以下数据:

???????????????????????
? PersonID ? OptionID ?
???????????????????????
?        1 ? A        ?
?        1 ? B        ?
?        2 ? C        ?
?        3 ? B        ?
?        4 ? A        ?
?        4 ? C        ?
???????????????????????
Run Code Online (Sandbox Code Playgroud)

我需要对这些数据进行透视,因此结果是:

????????????????????????????????????????????
? PersonID ? OptionA ? Option B ? Option C ?
????????????????????????????????????????????
?        1 ?       1 ?        1 ?          ?
?        2 ?         ?          ?        1 ?
?        3 ?         ?        1 ?          ?
?        4 ?       1 ?          ?        1 ?
????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

有什么建议?

Tar*_*ryn 22

有几种方法可以执行此数据转换。您可以访问该PIVOT函数,那么这将是最简单的,但如果没有,那么您可以使用聚合函数和CASE.

聚合/案例版本:

select personid,
  max(case when optionid = 'A' then 1 else 0 end) OptionA,
  max(case when optionid = 'B' then 1 else 0 end) OptionB,
  max(case when optionid = 'C' then 1 else 0 end) OptionC
from PersonOptions
group by personid
order by personid;
Run Code Online (Sandbox Code Playgroud)

参见SQL Fiddle with Demo

静态枢轴:

select *
from
(
  select personid, optionid
  from PersonOptions
) src
pivot
(
  count(optionid)
  for optionid in ('A' as OptionA, 'B' OptionB, 'C' OptionC)
) piv
order by personid
Run Code Online (Sandbox Code Playgroud)

参见SQL Fiddle with Demo

动态版本:

如果您有已知数量的值,则上述两个版本效果很好,但如果您的值未知,那么您将需要实现动态 sql 并且在 Oracle 中您可以使用一个过程:

CREATE OR REPLACE procedure dynamic_pivot_po(p_cursor in out sys_refcursor)
as
    sql_query varchar2(1000) := 'select personid ';

    begin
        for x in (select distinct OptionID from PersonOptions order by 1)
        loop
            sql_query := sql_query ||
                ' , min(case when OptionID = '''||x.OptionID||''' then 1 else null end) as Option_'||x.OptionID;

                dbms_output.put_line(sql_query);
        end loop;

        sql_query := sql_query || ' from PersonOptions group by personid order by personid';
        dbms_output.put_line(sql_query);

        open p_cursor for sql_query;
    end;
/
Run Code Online (Sandbox Code Playgroud)

然后你返回结果,你将使用:

variable x refcursor
exec dynamic_pivot_po(:x)
print x
Run Code Online (Sandbox Code Playgroud)

所有版本的结果都相同:

| PERSONID | OPTIONA | OPTIONB | OPTIONC |
------------------------------------------
|        1 |       1 |       1 |       0 |
|        2 |       0 |       0 |       1 |
|        3 |       0 |       1 |       0 |
|        4 |       1 |       0 |       1 |
Run Code Online (Sandbox Code Playgroud)


bil*_*nkc 10

这在 SQL Server 语法中是等效的。根据我对 Oracle 文档的阅读,NULLIFPIVOT似乎与它们的 SQL Server 亲属具有相同的格式。挑战将是需要静态的数据透视表,除非您像 Itzik演示的那样使查询动态化,但我不知道是否可以将其转换为 P/SQL

WITH PersonOptions(PersonID, OptionId) AS
(
    SELECT 1, 'A'
    UNION ALL SELECT 1, 'B'
    UNION ALL SELECT 2, 'C'
    UNION ALL SELECT 3, 'B'
    UNION ALL SELECT 4, 'A'
    UNION ALL SELECT 4, 'C'
)
SELECT
    P.PersonId
,   NULLIF(P.A, 0) AS OptionA
,   NULLIF(P.B, 0) AS OptionB
,   NULLIF(P.C, 0) AS OptionC
FROM
    PersonOptions  PO
    PIVOT 
    (
        COUNT(PO.OptionId)
        FOR OPtionId IN (A, B, C)
    )  P;
Run Code Online (Sandbox Code Playgroud)


a1e*_*x07 6

我更喜欢手动透视查询,但您也可以使用PIVOT

SELECT PersonID,
MAX(CASE WHEN OptionId ='A' THEN 1 END) AS OptionA,
MAX(CASE WHEN OptionId ='B' THEN 1 END) AS OptionB, 
MAX(CASE WHEN OptionId ='C' THEN 1 END) AS OptionC
FROM PersonOptions
GROUP BY PersonID
Run Code Online (Sandbox Code Playgroud)

  • 我自己认为与我使用的方法相比,`PIVOT` 语法更加复杂。但是,我知道他们都给出了相同的结果,我同意其他人可能会认为相反。 (2认同)