Oracle SQL:SELECT 语句中的内联表?

Posted

技术标签:

【中文标题】Oracle SQL:SELECT 语句中的内联表?【英文标题】:Oracle SQL: inline table within a SELECT statement? 【发布时间】:2020-01-14 09:49:08 【问题描述】:

我正在配置一个将数据从系统 A 移动到系统 B 的集成工具。我提供了一个 SQL SELECT 语句,它针对系统 A 运行,该语句的输出决定了系统 B 中的更新内容。例如,要更新 Team 1 的国际销售数据:

SELECT
  'Team1_Int_Sales_Count' Code,
  count(*) Count,
  to_char(<integration tool date syntax>) Period
FROM
  Sales
JOIN
  ADozenMoreTables ON stuff
WHERE
  ADozenOpaqueFields IN ADozenOpaqueReferences
  AND Sales.Date BETWEEN <integration tool date syntax>
  AND Team = 'Team1'
  AND Sales.Type = 'International'

它使用返回的字段CodeValuePeriod 使用该值更新该期间的代码。 (字段由它们所在的顺序标识,而不是按名称。)

然后,对于Team 1的国内销售,我复制并粘贴了整个查询,并更改了代码和一个WHERE子句:

SELECT
  'Team1_Dom_Sales_Count' Code,
  <otherwise as above>
  AND Sales.Type = 'Domestic'

然后我为第 2 组和第 3 组再复制粘贴四次

SELECT
  'Team2_Int_Sales_Count' Code,
  <snip>
  AND Team = 'Team2'
  AND Sales.Type = 'International'

SELECT
  'Team2_Dom_Sales_Count' Code,
  <snip>
  AND Team = 'Team2'
  AND Sales.Type = 'Domestic'

SELECT
  'Team3_Int_Sales_Count' Code,
  <snip>
  AND Team = 'Team3'
  AND Sales.Type = 'International'

SELECT
  'Team3_Dom_Sales_Count' Code,
  <snip>
  AND Team = 'Team3'
  AND Sales.Type = 'Domestic'

完整的问题有一个 ~60 行的 SELECT 语句,具有 3x3x3 排列,所涉及的复制/粘贴量让我感到恐惧。

有没有什么方法可以编写一条 SQL SELECT 语句,该语句将逐步遍历所有排列而无需复制粘贴重复?在我看来,我会在一个临时表中内联创建排列,或者作为一个二维数组,查询可以返回代码和其他两个字段匹配的值:

       'Team1_Int_Sales_Count', 'Team1', 'International',
        'Team1_Dom_Sales_Count', 'Team1', 'Domestic',
        'Team2_Int_Sales_Count', 'Team2', 'International',
        'Team2_Dom_Sales_Count', 'Team2', 'Domestic',
        'Team3_Int_Sales_Count', 'Team3', 'International',
        'Team3_Dom_Sales_Count', 'Team3', 'Domestic'  Permutations

这里的约束是集成工具要求我为每个任务提供一个 SELECT 语句。我不能在它前面加上WITH 语句,或者声明函数,或者将复杂的查询作为视图存储在源数据库中,或者做任何有趣或好的事情。它是一个 Oracle ODBC 连接,所以它使用 Oracle SQL。

【问题讨论】:

【参考方案1】:

你似乎想要一个交叉连接。

SELECT t.team || ct.code code,
       t.team,
       ct.type
       FROM (SELECT '_Int_Sales_Count' code,
                    'International' type
                    FROM dual
             UNION ALL
             SELECT '_Dom_Sales_Count' code,
                    'Domestic' type
                    FROM dual) ct
            CROSS JOIN (SELECT 'Team1' team
                               FROM dual
                        UNION ALL
                        SELECT 'Team2' team
                               FROM dual
                        UNION ALL
                        SELECT 'Team3' team
                               FROM dual) t;

db<>fiddle

【讨论】:

【参考方案2】:

排列表可以这样构造:

SELECT
  Permutations.Code AS Code,
  COUNT(*) AS Count,
...
JOIN (SELECT * FROM (
        (SELECT 'Team1_Int_Sales_Count' AS Code, 'Team1' AS Team, 'International' AS Type FROM Dual),
  UNION (SELECT 'Team1_Dom_Sales_Count' AS Code, 'Team1' AS Team, 'Domestic'      AS Type FROM Dual),
  UNION (SELECT 'Team2_Int_Sales_Count' AS Code, 'Team2' AS Team, 'International' AS Type FROM Dual),
  UNION (SELECT 'Team2_Dom_Sales_Count' AS Code, 'Team2' AS Team, 'Domestic'      AS Type FROM Dual),
  UNION (SELECT 'Team3_Int_Sales_Count' AS Code, 'Team3' AS Team, 'International' AS Type FROM Dual),
  UNION (SELECT 'Team3_Dom_Sales_Count' AS Code, 'Team3' AS Team, 'Domestic'      AS Type FROM Dual)
)) AS Permutations
ON Permutations.Team = Sales.Team AND Permutations.Type = Sales.Type
WHERE...

【讨论】:

【参考方案3】:

我会这样做:

with 
  team as (select  level lv from dual connect by level <= 3)
, bas  as (select '_Int_Sales_Count' n_count, 'International' type from dual
       union all select '_Dom_Sales_Count' n_count, 'Domestic' type from dual)
, permutations as 
     ( select 'Team' || lv ||n_count   as code,  'Team' || lv as team, type from team join bas on (1=1))
select * from permutations

但有限制:

select 'Team' || lv ||n_count   as code,  'Team' || lv as team, type from
      (select  level lv from dual connect by level <= 3) team,
      (select '_Int_Sales_Count' n_count, 'International' type from dual
           union all select '_Dom_Sales_Count' n_count, 'Domestic' type from dual) bas  

【讨论】:

谢谢,但是这个集成工具的限制是第一个关键字必须是SELECT。也许我应该在问题中更清楚地说明这一点。

以上是关于Oracle SQL:SELECT 语句中的内联表?的主要内容,如果未能解决你的问题,请参考以下文章

sql的嵌套查询,把一次查询的结果做为表继续进一步查询;内联视图

如何写sql语句去掉oracle返回结果中的空值(NULL)

sql中的表值函数与标量值函数区别与用法

oracle语句,我想查询A表中的a字段下的值不等于B表中b的值的数据,

oracle怎么捕获表上的DML语句(不包括select)语句)

Oracle - 查询语句 - 多表关联查询