【问题标题】:Single SQL SELECT Returning multiple rows from one table row单个 SQL SELECT 从一个表行返回多行
【发布时间】:2010-10-27 15:15:45
【问题描述】:

我们有一个表格,格式如下:

ID,Value1,Value2,Value3
1,2,3,4

我们需要把它转换成。

ID,Name,Value
1,'Value1',2
1,'Value2',3
1,'Value3',4

在一个 SELECT 语句中(即没有 UNION)有没有一种聪明的方法?列名 Value1、Value2 和 Value3 是固定不变的。

数据库是oracle 9i。

【问题讨论】:

  • 你使用的是什么数据库服务器?
  • 是 1,2,3,4 列还是数据值?
  • 这与this问题非常相似
  • 我能想到的最聪明的方法是重新设计您的数据库,使其标准化:)

标签: sql oracle select plsql oracle9i


【解决方案1】:

试一试union

select ID, 'Value1' as Name, Value1 as Value from table_name union all
select ID, 'Value2', Value2 as Value from table_name union all
select ID, 'Value3', Value3 as Value from table_name

order by ID, Name

使用union all 意味着服务器不会执行distinct(这在union 操作中是隐含的)。它不应该对数据产生任何影响(因为您的 ID 应该完全不同),但它可能会加快速度。

【讨论】:

  • 很好,我就是这样做的——我喜欢 UNION ALL 优化。小错误——示例中没有值4。我想另一种方法是 unpivot,这取决于数据库是否支持此功能。
  • 使用'union all'绝对不会对输出产生任何影响,因为'Value1'、'Value2'和'Value3'都是不同的!但它会避免数据库无用地尝试使行唯一化。
  • @James:在我的答案发布后,对问题进行了编辑以添加该警告。
  • 问题从一开始就指定了一个 SELECT。只是说。
  • 问题是这将涉及对表的三次扫描,而最好的选择是只扫描一次。
【解决方案2】:

你可以这样做,但它并不漂亮:

SELECT id,'Value 1' AS name,value1 AS value FROM mytable
UNION
SELECT id,'Value 2' AS name,value2 AS value FROM mytable
UNION
SELECT id,'Value 3' AS name,value3 AS value FROM mytable

【讨论】:

    【解决方案3】:

    联合三个 select 语句应该可以解决问题:

    SELECT ID, 'Value1', Value1 AS Value
    FROM TABLE
    UNION
    SELECT ID, 'Value2', Value2 AS Value
    FROM TABLE
    UNION
    SELECT ID, 'Value3', Value3 AS Value
    FROM TABLE
    

    【讨论】:

      【解决方案4】:

      如果您使用的是 SQL Server 2005+,那么您可以使用 UNPIVOT

      CREATE TABLE #tmp ( ID int, Value1 int, Value2 int, Value3 int)
      
      INSERT INTO #tmp (ID, Value1, Value2, Value3) VALUES (1, 2, 3, 4)
      
      SELECT
          *
      FROM
          #tmp
      
      SELECT
          *
      FROM
          #tmp
      UNPIVOT
      (
          [Value] FOR [Name] IN (Value1, Value2, Value3)
      ) uPIVOT
      
      DROP TABLE #tmp
      

      【讨论】:

        【解决方案5】:

        对于 Sql Server,考虑 UNPIVOT 作为 UNION 的替代方案:

        SELECT id, value, colname
        FROM #temp t
        UNPIVOT (Value FOR ColName IN (value1,value2,value3)) as X
        

        这也将返回列名。我不确定 X 是做什么用的,但你不能忽略它。

        【讨论】:

          【解决方案6】:

          这适用于 Oracle 10g:

          select id, 'Value' || n as name,
                 case n when 1 then value1 when 2 then value2 when 3 then value3 end as value
          from (select rownum n
                from (select 1 from dual connect by level <= 3)) ofs, t
          

          我认为 Oracle 9i 有递归查询?无论如何,我很确定它有 CASE 支持,所以即使它没有递归查询,您也可以执行“(select 1 from dual union all select 2 from dual union all select 3 from dual) ofs”代替。对 Oracle 来说,滥用递归查询更为普遍。 (不过,使用联合生成行可以移植到其他数据库)

          【讨论】:

          • +1 用于单表扫描。 WRT 递归查询 - Oracle 从 7 开始就有分层查询,但只在 11gR2 中引入了递归 WITH 子句。
          【解决方案7】:

          正如其他人所建议的那样,UNION ALL 可能是您在 SQL 中的最佳选择。您可能还需要考虑在前端处理此问题,具体取决于您的具体要求。

          【讨论】:

            【解决方案8】:

            试试这个:

            CTE 创建一个包含 4 个值的临时表。您可以在任何数据库中按原样运行它。

            with TEST_CTE (ID) as
            
            (select * from (select '1' as a) as aa  union all
            select * from (select '2' as b) as bb  union all
            select * from (select '3' as c) as cc  union all
            select * from (select '4' as d) as dd )
            
            select a.ID, 'Value'|| a.ID, b.ID
            from TEST_CTE a, TEST_CTE b
            where b.ID = (select min(c.ID) from TEST_CTE c where c.ID > a.ID)
            

            这是结果集:

            1   Value1  2
            
            2   Value2  3
            
            3   Value3  4
            

            享受吧!

            一些事后的想法。

            ^^^ CTE 语法在 Oracle 中可能不同。我只能在 Teradata 中运行它。您可以将其替换为临时表或修复语法以使其与 Oracle 兼容。 select 语句是普通的普通 SQL,适用于任何数据库。

            ^^^ 还有一点要注意。如果 ID 字段是数字,您可能需要将其转换为 CHAR 以便与“值”连接。

            【讨论】:

            • 我刚刚在我的帖子中添加了一些 cmets。
            【解决方案9】:

            Oracle 的 CTE 语法可能不同(我在 Teradata 中运行它),但我只使用 CTE 提供测试数据,即 1 2 3 和 4。您可以使用临时表。实际的 select 语句是普通的普通 SQL,它适用于任何关系数据库。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2010-11-27
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多