管道分隔串联期间格式化列标题(Oracle SQL)

时间:2016-04-19 15:58:54

标签: sql oracle concatenation alias sqlplus

概述我的任务是将Oracle数据库中的数据提取作为管道分隔的输出文本文件提供。我将使用SQLPlus在数据所在的服务器上执行此操作。通常,这项任务并不是我的经验,但这次,业务需要列标题存在。

考虑我需要输出的以下五列:

SELECT
    a.USER_NAME || '|'
    || a.LAST_NAME || '|'
    || a.FIRST_NAME || '|'
    || b.PRODUCT_PURCHASED || '|'
    || c.DATEPURCHASED
FROM ...
WHERE ... ;

此SQL工作正常,输出如下:

omnusruthius|ruthius|omnus|stackoverflow_prod|19-APR-16

但是,企业希望它看起来像:

USER_NM|LAST|FIRST|PROD|EFFECTIVE_DATE
omnusruthius|ruthius|omnus|stackoverflow_prod|19-APR-16

问题:所以这里的目标主要是输出带有自定义列标题(别名)的第一行,如上所示。所以我的第一个方法是尝试类似的东西:

    SELECT
    a.USER_NAME AS USER_NM || '|'
    || a.LAST_NAME AS LAST || '|'
    || a.FIRST_NAME AS FIRST || '|'
    || b.PRODUCT_PURCHASED AS PROD || '|'
    || c.DATEPURCHASED AS EFFECTIVE_DATE
    FROM ...
    WHERE ...

不幸的是,我收到了:

  

ORA-00923:未找到FROM关键字

我不确定这会有什么帮助,因为没有别名的原始SQL输出无论如何都不会在第一行显示列标题。请记住,这是通过命令行(SQLPlus),而不是Toad或其他一些RDMS。

然后我尝试了:

SELECT 
   'USER_NM', 'LAST', 'FIRST', 'PROD', 'EFFECTIVE_DATE' FROM DUAL
UNION ALL
SELECT
    a.USER_NAME || '|'
    || a.LAST_NAME || '|'
    || a.FIRST_NAME || '|'
    || b.PRODUCT_PURCHASED || '|'
    || c.DATEPURCHASED
FROM ...
WHERE ...

出现以下错误:

  

ORA-01789:查询块的结果列数不正确

我觉得这个解决方案非常接近,我在这里错过了什么?任何帮助将不胜感激!

编辑:只是给未来读者的一个注释,这里的两个答案都可以帮助您解决这个问题,但经过进一步的调整,我发现我们都在过度思考解决方案。我不打算提出新的解决方案,因为改变是微不足道的,但请考虑采取以下措施:

SELECT 'USER_NM|LAST|FIRST|PROD|EFFECTIVE_DATE' FROM DUAL;
SELECT a.USER_NAME AS USER_NM || '|'
|| a.LAST_NAME AS LAST || '|'
|| a.FIRST_NAME AS FIRST || '|'
|| b.PRODUCT_PURCHASED AS PROD || '|'
|| c.DATEPURCHASED AS EFFECTIVE_DATE
FROM ...
WHERE ...
ORDER BY ... ;

这里的关键是在SQL * Plus中使用分号。第一个SELECT语句完全独立于第二个;不需要UNION,因为第一个查询的输出会在第二个查询的输出之前立即自动显示。两者都可以有自己的规则,如果后一个查询要复杂得多,这一点尤其方便。我可以确认上述查询是否有效,我很惊讶我花了很长时间才实现这一目标...

2 个答案:

答案 0 :(得分:3)

连接时请确保标头是单个字符串。因为您将列中的值连接在一行上。

如果使用逗号分隔,正如您在问题中所做的那样,结果块也应该有5列,但情况并非如此。

SELECT 
   'USER_NM|LAST|FIRST|PROD|EFFECTIVE_DATE' FROM DUAL
UNION ALL
SELECT
    a.USER_NAME || '|'
    || a.LAST_NAME || '|'
    || a.FIRST_NAME || '|'
    || b.PRODUCT_PURCHASED || '|'
    || c.DATEPURCHASED
FROM ...
WHERE ...

编辑:列也可以排序。

SELECT 'USER_NM|LAST|FIRST|PROD|EFFECTIVE_DATE' FROM DUAL
UNION ALL
SELECT * FROM (
SELECT
    a.USER_NAME || '|'
    || a.LAST_NAME || '|'
    || a.FIRST_NAME || '|'
    || b.PRODUCT_PURCHASED || '|'
    || c.DATEPURCHASED
FROM ...
WHERE ...
ORDER BY DATEPURCHASED) --add any other columns needed

答案 1 :(得分:1)

由于您使用SQL * Plus标记了问题,因此您可以使用the PROMPT command生成标题,这样可以避免使用联合对结果进行排序的并发症:

PROMPT USER_NM|LAST|FIRST|PROD|EFFECTIVE_DATE

SELECT
a.USER_NAME AS USER_NM || '|'
|| a.LAST_NAME AS LAST || '|'
|| a.FIRST_NAME AS FIRST || '|'
|| b.PRODUCT_PURCHASED AS PROD || '|'
|| c.DATEPURCHASED AS EFFECTIVE_DATE
FROM ...
WHERE ...
ORDER BY ...

将标题从SQL中移出并进入客户端领域,它可以说属于它。这也适用于SQL Developer,其他客户端也可以做类似的事情。如果您从另一个客户端或JDBC或其他任何方面运行查询,它将无法工作;但是无论运行什么,查询都可以(也许应该)在这种情况下提供标题。

如果您还没有,您还可以考虑执行SET HEADING OFFSET PAGESIZE 0来抑制查询本身的列标题(尽管您已经说过你已经做过的事情了那);可能SET EMBED OFF,但我不认为除非你单独进行查询以生成标题行,否则需要这样做。