【问题标题】:How to transpose dynamically in Oracle如何在 Oracle 中动态转置
【发布时间】:2015-12-15 15:39:08
【问题描述】:

这是我的桌子

Equipmentid    Application   Value
===========    ===========   =====
k001              THK         True
k001              BHK         False
k001              KHK         True

这是我的预期:

Equipmentid    THK   BHK    KHK
===========    ===   ===    ===
k001           True  False  True

我正在尝试使用max decode使用普通的转置Oracle,但最后需要提到AS [tablename],我想根据行名动态创建行到列,这个数据库将涉及很多应用程序。谢谢大家

【问题讨论】:

  • 您可能在这里误用了数据库。检索数据并在您的客户端执行,无论是 PL/SQL 还是任何其他 OCI 方法。
  • @MaheswaranRavisankar,这是我从数据库中得到的视图,没有机会解决这个问题?
  • 您需要动态构造 SQL 语句。像stackoverflow.com/questions/32451072/… 这样的东西要复杂得多,而且这意味着您必须读取一次数据,构建查询,然后再次读取数据,效率并不高。
  • 嗨@JustinCave,我从视图中得到了这个数据库,我需要用应用程序对每个设备ID 进行分类,即真假。我需要插入大约 3000 台设备。
  • 如果您希望列的数量和名称是动态的,则需要动态 SQL。如果您希望不同行的列数和名称不同,那么,是的,您需要多个查询。如果要为表中存在的任何application 创建列,可以动态创建单个SQL 语句

标签: sql oracle oracle11g transpose


【解决方案1】:

您好,请尝试使用 PIVOT,

WITH x(equipment_id, application, VALUE ) 
     AS (SELECT 'k001', 'THK', 'TRUE' FROM DUAL UNION ALL
         SELECT 'k001', 'BHK', 'FALSE' FROM DUAL UNION ALL
         SELECT 'k001', 'KHK', 'TRUE' FROM DUAL  UNION ALL
         SELECT 'k002', 'KHK', 'FALSE' FROM DUAL UNION ALL
         SELECT 'k002', 'THK', 'FALSE' FROM DUAL UNION ALL
         SELECT 'k002', 'BHK', 'FALSE' FROM DUAL )

  SELECT * FROM
(
  SELECT equipment_id, value, application
  FROM x
)
PIVOT
(
  MAX(value)
  FOR application IN ('THK', 'BHK', 'KHK')
) order by equipment_id;

或者,如果你想拥有动态列,你可以在 IN 子句中使用子查询,然后使用 PIVOT XML,但结果将是 XML 类型,我不知道如何提取值。(只是说)如果你想要了解有关如何使用 pl/sql 动态执行此操作的更多信息。 Read here.Here's the source

  SELECT * FROM
(
  SELECT equipment_id, value, application
  FROM x
)
PIVOT XML
(
  MAX(value)
  FOR application IN (SELECT DISTINCT application from x)
) order by equipment_id;

【讨论】:

  • 嗨@brenners1302,我有大约3000台设备,这意味着我需要一件一件做吗?
  • 然后在 FOR application IN ('THK', 'BHK', 'KHK') 中,我需要在这里提到很多应用程序吗? ..
  • 我的错,我在没有完全理解您的问题的情况下回答,如果您手动列出所有应用程序,似乎会出现很多问题。我只假设只有三个应用程序
  • @brenner1302,是的,如果只有 3 个应用程序,那么确定我可以使用您的代码,但这涉及很多应用程序。 :(
  • @Kedai Ezbakr,我可以使用子查询,以便它可以具有动态应用程序,但结果将是 XML 类型,我不知道如何将其转换为对您有用的东西。
【解决方案2】:

试试这个。

SELECT EQUIPMENTID,
max(case  when  APPLICATION = 'THK' then VALUE end) as "THK",
max(case  when  APPLICATION = 'BHK' then VALUE end) as "BHK",
max(case  when  APPLICATION = 'KHK' then VALUE end) as "KHK"
FROM [tablename]
group by EQUIPMENTID;

【讨论】:

  • 嗨@MikhailovValentine,这是我以前做的,但是如果我有更多的50个应用程序,我需要写长代码吗?
【解决方案3】:

在这种情况下,您可以left join

SELECT t1.Equipmentid, t2.Value AS 'THK', t3.Value AS 'BHK', t4.Value AS 'KHK' FROM TABLE t1
     LEFT JOIN (SELECT Equipmentid, Value FROM TABLE WHERE Application = 'THK') AS t2 ON (t1.Equipmentid = t2.Equipmentid)
     LEFT JOIN (SELECT Equipmentid, Value FROM TABLE WHERE Application = 'BHK') AS t3 ON (t1.Equipmentid = t3.Equipmentid)
     LEFT JOIN (SELECT Equipmentid, Value FROM TABLE WHERE Application = 'KHK') AS t4 ON (t1.Equipmentid = t4.Equipmentid)

虽然可以解决。但在我看来,这种方法并不好。希望对你有所帮助

【讨论】:

  • 嗨@dean,谢谢你的回复,但为了你的信息,我每个设备ID都有很多应用程序。
  • 然后我建议您使用 brenners 的答案,但不要插入 FOR 语句 1 by 1 ...尝试将其替换为 FOR application IN (' + @ColumnName + '))
  • @ColumnName 可以声明为 SELECT @ColumnName= ISNULL(@ColumnName + ',','') + QUOTENAME(Value) FROM (SELECT DISTINCT Value FROM TABLE Where Equipmentid = 'k001')
  • 非常感谢您的帮助,但是稍后这个数据库将涉及 3000 个 id ,我需要把所有 id 都放在那里吗?
  • sry 迟来的回复...通过使用 IN(@variable) @variable 已经选择了您在表中拥有的所有可能的应用程序...因此您并不需要真正关心何时您添加新的或删除的应用程序
猜你喜欢
  • 2012-12-18
  • 1970-01-01
  • 1970-01-01
  • 2012-10-15
  • 2016-01-18
  • 1970-01-01
  • 2011-12-05
  • 2022-08-18
  • 1970-01-01
相关资源
最近更新 更多