【问题标题】:SQL - how to transpose only some row values into column headers without pivotSQL - 如何仅将某些行值转置为列标题而不使用数据透视
【发布时间】:2018-11-09 20:18:56
【问题描述】:

我有一个类似这样的表:

stud_ID | first_name | last_name | email | col_num | user_value
1         tom          smith              50         Retail
1         tom          smith              60         Product
2         Sam          wright             50         Retail
2         Sam          wright             60         Sale 

但需要将其转换为:(基本上将 'col_num' 转置为列标题并将 50 更改为函数,将 60 更改为部门)

 stud_ID | first_name | last_name | email | Function | Department
    1         tom          smith              Retail    Product
    2         Sam          wright             Retail    Sale     

不幸的是,Pivot 在我的系统中不起作用,请问是否有其他方法可以做到这一点?

到目前为止我的代码(抱歉,列表太长了):

SELECT c.person_id_external as stu_id,
  c.lname,
  c.fname,
  c.mi,
  a.cpnt_id,
  a.cpnt_typ_id,
  a.rev_dte,
  a.rev_num,
  cp.cpnt_title AS cpnt_desc,
  a.compl_dte,
  a.CMPL_STAT_ID,
  b.cmpl_stat_desc,
  b.PROVIDE_CRDT,
  b.INITIATE_LEVEL1_SURVEY,
  b.INITIATE_LEVEL3_SURVEY,
  a.SCHD_ID,
  a.TOTAL_HRS,
  a.CREDIT_HRS,
  a.CPE_HRS,
  a.CONTACT_HRS,
  a.TUITION,
  a.INST_NAME,
  --a.COMMENTS,
  a.BASE_STUD_ID,
  a.BASE_CPNT_TYP_ID,
  a.BASE_CPNT_ID,
  a.BASE_REV_DTE,
  a.BASE_CMPL_STAT_ID,
  a.BASE_COMPL_DTE,
  a.ES_USER_NAME,
  a.INTERNAL,
  a.GRADE_OPT,
  a.GRADE,
  a.PMT_ORDER_TICKET_NO,
  a.TICKET_SEQUENCE,
  a.ORDER_ITEM_ID,
  a.ESIG_MESSAGE,
  a.ESIG_MEANING_CODE_ID,
  a.ESIG_MEANING_CODE_DESC,
  a.CPNT_KEY,
  a.CURRENCY_CODE,
  c.EMP_STAT_ID,
  c.EMP_TYP_ID,
  c.JL_ID,
  c.JP_ID,
  c.TARGET_JP_ID,
  c.JOB_TITLE,
  c.DMN_ID,
  c.ORG_ID,
  c.REGION_ID,
  c.CO_ID,
  c.NOTACTIVE,
  c.ADDR,
  c.CITY,
  c.STATE,
  c.POSTAL,
  c.CNTRY,
  c.SUPER,
  c.COACH_STUD_ID,
  c.HIRE_DTE,
  c.TERM_DTE,
  c.EMAIL_ADDR,
  c.RESUME_LOCN,
  c.COMMENTS,
  c.SHIPPING_NAME,
  c.SHIPPING_CONTACT_NAME,
  c.SHIPPING_ADDR,
  c.SHIPPING_ADDR1,
  c.SHIPPING_CITY,
  c.SHIPPING_STATE,
  c.SHIPPING_POSTAL,
  c.SHIPPING_CNTRY,
  c.SHIPPING_PHON_NUM,
  c.SHIPPING_FAX_NUM,
  c.SHIPPING_EMAIL_ADDR,
  c.STUD_PSWD,
  c.PIN,
  c.PIN_DATE,
  c.ENCRYPTED,
  c.HAS_ACCESS,
  c.BILLING_NAME,
  c.BILLING_CONTACT_NAME,
  c.BILLING_ADDR,
  c.BILLING_ADDR1,
  c.BILLING_CITY,
  c.BILLING_STATE,
  c.BILLING_POSTAL,
  c.BILLING_CNTRY,
  c.BILLING_PHON_NUM,
  c.BILLING_FAX_NUM,
  c.BILLING_EMAIL_ADDR,
  c.SELF_REGISTRATION,
  c.SELF_REGISTRATION_DATE,
  c.ACCESS_TO_ORG_FIN_ACT,
  c.NOTIFY_DEV_PLAN_ITEM_ADD,
  c.NOTIFY_DEV_PLAN_ITEM_MOD,
  c.NOTIFY_DEV_PLAN_ITEM_REMOVE,
  c.NOTIFY_WHEN_SUB_ITEM_COMPLETE,
  c.NOTIFY_WHEN_SUB_ITEM_FAILURE,
  c.LOCKED,
  c.PASSWORD_EXP_DATE,
  c.SECURITY_QUESTION,
  c.SECURITY_ANSWER,
  c.ROLE_ID,
  c.IMAGE_ID,
  c.GENDER,
  c.PAST_SERVICE,
  c.LST_UNLOCK_TSTMP,
  c.MANAGE_SUB_SP,
  c.MANAGE_OWN_SP,
  d.col_num,
  d.user_value

FROM pa_cpnt_evthst a,
  pa_cmpl_stat b,
  pa_student c,
  pv_course cp,
  pa_stud_user d
WHERE a.cmpl_stat_id  = b.cmpl_stat_id
AND a.stud_id         = c.stud_id
AND cp.cpnt_typ_id(+) = a.cpnt_typ_id
AND cp.cpnt_id(+)     = a.cpnt_id
AND cp.rev_dte(+)     = a.rev_dte
AND a.CPNT_TYP_ID    != 'SYSTEM_PROGRAM_ENTITY'
AND c.stud_id = d.stud_id
AND d.col_num in ('10','30','50','60')

【问题讨论】:

  • 你可以用表面的条件聚合来做到这一点。

标签: sql oracle pivot


【解决方案1】:

我只会使用条件聚合:

select stud_ID, first_name, last_name, email,
       max(case when col_num = 50 then user_value end) as function,
       max(case when col_num = 60 then user_value end) as department
from t
group by stud_ID, first_name, last_name, email;

您的代码似乎与示例数据无关。但是,我确实注意到您使用的是 implicit 连接语法。您确实需要学习如何使用正确、明确、标准 JOIN 语法。

【讨论】:

  • 谢谢你的回答,戈登。很抱歉我的代码是一团糟,有点像 SQL 的新手。示例数据是一个简化表,因为我的实际表有太多字段。如果要将您的代码添加到我的代码中,是否需要将当前代码包装为临时表“t”,然后在底部添加您的代码?
  • @JakeB 。 . .你可以做with t as (<your query here>) 然后使用这个查询。
【解决方案2】:

我假设您有 Sql Server 2000 或 2003。在这种情况下您需要做的是创建一个带有一个光标的脚本。 这个光标将创建一个类似这样的文本: string var = "CREATE TABLE #Report (Col1 VARCHAR(20), Col2, VARCHAR(20), " + ColumnName

这样您就可以动态创建临时表,最后您需要选择临时表以准备好数据透视表。

如果你不熟悉游标,那就没那么容易了。

如果您的 'pivot' 列上只有几个值并且它们不会增长,您也可以执行以下操作:

Pivot using SQL Server 2000

【讨论】:

  • 感谢您的回复,安德烈斯。我对 SQL 还是很陌生,所以我现在将采用不太复杂的方法。 ;)
【解决方案3】:

我无法理解您的代码,因此我将假设示例数据中提到的表为 stud(因为 stud_id)。 所以这就是我认为可以做枢轴的工作。

SELECT  ISNULL(s1.stud_ID, s2.stud_id), 
        ISNULL(s1.first_name, s2.first_name), 
        ISNULL(s1.last_name, s2.last_name), 
        ISNULL(s1.email, s2.email), 
        s1.user_value as [Function], s2.user_value as Department
FROM stud s1 OUTER JOIN stud s2
ON s1.stud_ID = s2.stud_ID -- Assuming stud_ID is primary key, else join on all primary keys
AND s1.col_num = 50 AND s2.col_num = 60

解释:我只是想在这里模拟PIVOT 的作用。对于您想要的每一列,您在 JOIN 中创建一个新表,并将其限制为您的 col_num 列中的一个值。例如,如果 s1 中没有 50 的值,OUTER JOIN 将变为NULL,我们需要从 s2 中提取记录。

注意:如果您需要超过 2 个新列,则可以使用 COALESCE 代替 ISNULL

【讨论】:

  • 谢谢你,Sahil,对不起代码,我承认这不是最有效的方法!一定会给你的方法一试。
猜你喜欢
  • 2023-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多