Group By 语句中的重复列

Posted

技术标签:

【中文标题】Group By 语句中的重复列【英文标题】:Duplicate Columns in Group By Statement 【发布时间】:2012-09-05 14:41:30 【问题描述】:

我正在尝试将这个 Oracle Discoverer 创建的 SQL 脚本转换为可以从 Discoverer 外部运行的查询。当我尝试运行脚本时,出现以下错误:

SQL 语句无效,因为它包含以下重复的列名:LEAF_DETAILSLEAF_DETAILS_DESCRLEAF_DETAILSLEAF_DETAILS_DESCR。通过为列提供别名来更正语句。

我必须转换大约 100 个这样的脚本,因此我正在寻找一种方法来轻松修改此脚本输出,而无需重新构建每个脚本。有什么想法吗?

  SELECT O1890255.LEAF_DETAILS,
         O1890286.ACTIVITY,
         O1890258.LEAF_DETAILS_DESCR,
         O1890261.LEAF_DETAILS,
         O1890261.LEAF_DETAILS_DESCR,
         O1890286.BUSINESS_UNIT,
         O1890286.PROJECT_DESCR,
         O1890287.PROJECT_ID,
         O1890288.LEAF_DETAILS,
         O1890288.LEAF_DETAILS_DESCR,
         O1890287.SUB_PROJECT,
         O1890287.SYSTEM_SOURCE,
         O1890287.YEAR,
         SUM (O1890287.RESOURCE_AMT_BUD),
         SUM (O1890287.RESOURCE_AMT_ACT),
           (SUM (
               DECODE (O1890287.ACCOUNTING_PERIOD,
                       '8', O1890287.RESOURCE_AMT_ACT,
                       0)))
         - (SUM (
               DECODE (O1890287.ACCOUNTING_PERIOD,
                       '8', O1890287.RESOURCE_AMT_BUD,
                       0))),
         SUM (
            DECODE (O1890287.ACCOUNTING_PERIOD,
                    '8', O1890287.RESOURCE_AMT_BUD,
                    0)),
         SUM (
            DECODE (O1890287.ACCOUNTING_PERIOD,
                    '8', O1890287.RESOURCE_AMT_ACT,
                    0)),
         SUM (O1890287.RESOURCE_AMT_ACT - O1890287.RESOURCE_AMT_BUD)
    FROM WAREHOUSE.PPL_RPTD_COST_MGMT01JAN00 O1890255,
         WAREHOUSE.PPL_RPTD_ACTIVITY_BUDG O1890258,
         WAREHOUSE.PPL_RPTD_BUD_ITEMS01JAN00 O1890261,
         WAREHOUSE.PROJECT_DENORMAL_GEN O1890286,
         WAREHOUSE.PROJ_RES_DENORMAL_GEN O1890287,
         WAREHOUSE.SRC_TREE_VW O1890288
   WHERE     (    (O1890255.LEAF_DETAILS = O1890287.ACCOUNT)
              AND (O1890258.LEAF_DETAILS = O1890286.ACTIVITY)
              AND (O1890261.LEAF_DETAILS = O1890287.BUDGET_ITEM)
              AND (O1890286.PROJECT_ID = O1890287.PROJECT_ID)
              AND (O1890288.LEAF_DETAILS = O1890287.SRC))
         AND ( ( (   O1890255.LEAF_DETAILS LIKE '12011'
                  OR O1890255.LEAF_DETAILS = '10700')))
         AND (O1890287.ACTIVITY LIKE '000002F%')
         AND (    O1890287.SUB_PROJECT <> '897'
              AND O1890287.BUDGET_ITEM <> 'CAPBD'
              AND O1890287.SUB_PROJECT <> '896')
         AND (O1890261.LEAF_DETAILS NOT IN ('PLTIS', '14M00'))
         AND (O1890287.ACCOUNTING_PERIOD <= '8')
         AND (O1890287.YEAR = '2012')
         AND (O1890286.BUSINESS_UNIT LIKE '52110')
         AND (O1890287.ACCOUNTING_PERIOD NOT IN (998, 999))
         AND (O1890287.SYSTEM_SOURCE NOT IN ( ('PLT')))
GROUP BY O1890255.LEAF_DETAILS,
         O1890286.ACTIVITY,
         O1890258.LEAF_DETAILS_DESCR,
         O1890261.LEAF_DETAILS,
         O1890261.LEAF_DETAILS_DESCR,
         O1890286.BUSINESS_UNIT,
         O1890286.PROJECT_DESCR,
         O1890287.PROJECT_ID,
         O1890288.LEAF_DETAILS,
         O1890288.LEAF_DETAILS_DESCR,
         O1890287.SUB_PROJECT,
         O1890287.SYSTEM_SOURCE,
         O1890287.YEAR

【问题讨论】:

至少在 sqlfiddle 上,有重复的列只会显示其中之一;但是,添加别名将同时显示两者。看到这个小提琴sqlfiddle.com/#!4/4f184/6,你在运行这个查询时遇到任何错误吗? 【参考方案1】:

这会做你想做的事。这很丑陋,但它会完成工作。只需将查询粘贴到@query 变量中,然后按 F5;输出是您的新查询。您需要将任何单个撇号替换为两个撇号,才能将准确的查询放入变量中。

要自动清理一堆查询,您可以将其转换为 sproc,并通过查询文件向光标写入一些内容,将其文本拉入变量,将变量传递给 sproc 并将结果输出到新的文件。

Declare @query Varchar(Max),
        @columns Varchar(Max),
        @from Varchar(Max),
        @check Int = -1,
        @checkChar Varchar(1),
        @counter Int = 0,
        @newColumns Varchar(Max);;

Declare @indexes Table (tID Int Identity, indexLoc Int, indexChar Varchar(1))
Declare @colNames Table (tID Int, colName Varchar(512))

Set     @query = 
'SELECT O1890255.LEAF_DETAILS, O1890286.ACTIVITY, O1890258.LEAF_DETAILS_DESCR, O1890261.LEAF_DETAILS, O1890261.LEAF_DETAILS_DESCR, O1890286.BUSINESS_UNIT, O1890286.PROJECT_DESCR, O1890287.PROJECT_ID, O1890288.LEAF_DETAILS, O1890288.LEAF_DETAILS_DESCR, O1890287.SUB_PROJECT, O1890287.SYSTEM_SOURCE, O1890287.YEAR, SUM(O1890287.RESOURCE_AMT_BUD), SUM(O1890287.RESOURCE_AMT_ACT), ( SUM(DECODE(O1890287.ACCOUNTING_PERIOD,''8'',O1890287.RESOURCE_AMT_ACT,0)) )-( SUM(DECODE(O1890287.ACCOUNTING_PERIOD,''8'',O1890287.RESOURCE_AMT_BUD,0)) ), SUM(DECODE(O1890287.ACCOUNTING_PERIOD,''8'',O1890287.RESOURCE_AMT_BUD,0)), SUM(DECODE(O1890287.ACCOUNTING_PERIOD,''8'',O1890287.RESOURCE_AMT_ACT,0)), SUM(O1890287.RESOURCE_AMT_ACT-O1890287.RESOURCE_AMT_BUD)
FROM WAREHOUSE.PPL_RPTD_COST_MGMT01JAN00 O1890255, WAREHOUSE.PPL_RPTD_ACTIVITY_BUDG O1890258, WAREHOUSE.PPL_RPTD_BUD_ITEMS01JAN00 O1890261, WAREHOUSE.PROJECT_DENORMAL_GEN O1890286, WAREHOUSE.PROJ_RES_DENORMAL_GEN O1890287, WAREHOUSE.SRC_TREE_VW O1890288
WHERE ( ( O1890255.LEAF_DETAILS = O1890287.ACCOUNT ) AND ( O1890258.LEAF_DETAILS = O1890286.ACTIVITY ) AND ( O1890261.LEAF_DETAILS = O1890287.BUDGET_ITEM ) AND ( O1890286.PROJECT_ID = O1890287.PROJECT_ID ) AND ( O1890288.LEAF_DETAILS = O1890287.SRC ) ) AND ( (  ( O1890255.LEAF_DETAILS LIKE ''12011'' OR O1890255.LEAF_DETAILS = ''10700'' )  ) ) AND ( O1890287.ACTIVITY LIKE ''000002F%'' ) AND ( O1890287.SUB_PROJECT <> ''897'' AND O1890287.BUDGET_ITEM <> ''CAPBD'' AND O1890287.SUB_PROJECT <> ''896'' ) AND ( O1890261.LEAF_DETAILS NOT IN (''PLTIS'',''14M00'') ) AND ( O1890287.ACCOUNTING_PERIOD <= ''8'' ) AND ( O1890287.YEAR = ''2012'' ) AND ( O1890286.BUSINESS_UNIT LIKE ''52110'' ) AND ( O1890287.ACCOUNTING_PERIOD NOT IN (998,999) ) AND ( O1890287.SYSTEM_SOURCE NOT IN (( ''PLT'' )) )
GROUP BY O1890255.LEAF_DETAILS, O1890286.ACTIVITY, O1890258.LEAF_DETAILS_DESCR, O1890261.LEAF_DETAILS, O1890261.LEAF_DETAILS_DESCR, O1890286.BUSINESS_UNIT, O1890286.PROJECT_DESCR, O1890287.PROJECT_ID, O1890288.LEAF_DETAILS, O1890288.LEAF_DETAILS_DESCR, O1890287.SUB_PROJECT, O1890287.SYSTEM_SOURCE, O1890287.YEAR'

Set     @from = Right(@query,Len(@query)-(CharIndex('FROM',@query)-1))
Set     @columns = Replace(Replace(Replace(@query,@from,''),'SELECT',''),' ','')

While   1 = 1
Begin
        Select  @check = Min(val)
        From   (Select  CharIndex(',',@columns,@check + 1) As val 
                Union
                Select  CharIndex('(',@columns,@check + 1)
                Union
                Select  CharIndex(')',@columns,@check + 1)) As n

        If  (@check = 0)
        Begin
                Break
        End

        Insert  @indexes
        Select  @check, Substring(@columns,@check,1)
End

Delete  i1
From    @indexes i1
Join    @indexes i2
        On  i1.tID = i2.tID+1
        And i1.indexChar = '('
        And i2.indexChar = '('

Delete  i1
From    @indexes i1
Join    @indexes i2
        On  i1.tID = i2.tID-1
        And i1.indexChar = ')'
        And i2.indexChar = ')'      

Declare @indexLoc Int,
        @indexChar Varchar(1)

Declare cur Cursor For      
Select  indexLoc,
        indexChar
From    @indexes;

Open    cur;
Fetch   Next 
From    cur
Into    @indexLoc,
        @indexChar

Select  @checkChar =   (Select  Top 1 indexChar
                        From    @indexes
                        Order   By tID)

While   @@Fetch_Status = 0
Begin
        If      @indexChar = '('
        Begin
                Set @counter = @counter + 1;
        End
        Else    If @indexChar = ')'
        Begin
                Set @counter = @counter - 1;
        End

        If      @counter > 0
        Begin
                Delete  i
                From    @indexes i
                Where   indexLoc = @indexLoc

                Set     @checkChar = @indexChar
        End

        Fetch   Next 
        From    cur
        Into    @indexLoc,
                @indexChar
End
Close   cur;
Deallocate cur;

With    buildBase As
(
        Select  0 As tID, 0 As indexLoc, ',' As indexChar
        Union   All
        Select  Row_Number() Over (Order By tID), indexLoc, indexChar
        From    @indexes
        Where   indexChar Not In ('(',')')
        Union   All
        Select  Count(1) + 1, Len(@columns), ','
        From    @indexes
        Where   indexChar Not In ('(',')')
),      seperateColumns As
(
        Select  Row_Number() Over (Order By i1.tID) as tID,
                Substring(@columns,i1.indexLoc + 1,i2.indexLoc-(i1.indexLoc+1)) As colName
        From    buildBase i1
        Join    buildBase i2
                On  i1.tID = i2.tID-1
),      newNames As
(
        Select  tID,
                Case
                When    colName Like '%(%'
                Then    colName + 
                        ' [Column' + Convert(Varchar(10),Row_Number() Over (Partition By    Case
                                                                                            When    colName like '%(%' Then 1
                                                                                            Else    0
                                                                                            End
                                                                            Order By tID)) + ']'
                Else    colName + 
                        ' [' + Right(colName,Len(colName)-CharIndex('.',colName)) + 
                        Convert(Varchar(10),Row_Number() Over ( Partition By    Right(colName,Len(colName)-CharIndex('.',colName))
                                                                Order By tID)) + ']'
                End     As colName
        From    seperateColumns
)
Insert  @colNames 
Select  tID, colName
From    newNames
Order   By tID

Select  @newColumns = COALESCE(@newColumns + ', ', '') + colName 
From    @colNames 
Order   By tID

Select  'SELECT ' + @newColumns + ' ' + @from

输出:

SELECT O1890255.LEAF_DETAILS [LEAF_DETAILS1], O1890286.ACTIVITY [ACTIVITY1], O1890258.LEAF_DETAILS_DESCR [LEAF_DETAILS_DESCR1], O1890261.LEAF_DETAILS [LEAF_DETAILS2], O1890261.LEAF_DETAILS_DESCR [LEAF_DETAILS_DESCR2], O1890286.BUSINESS_UNIT [BUSINESS_UNIT1], O1890286.PROJECT_DESCR [PROJECT_DESCR1], O1890287.PROJECT_ID [PROJECT_ID1], O1890288.LEAF_DETAILS [LEAF_DETAILS3], O1890288.LEAF_DETAILS_DESCR [LEAF_DETAILS_DESCR3], O1890287.SUB_PROJECT [SUB_PROJECT1], O1890287.SYSTEM_SOURCE [SYSTEM_SOURCE1], O1890287.YEAR [YEAR1], SUM(O1890287.RESOURCE_AMT_BUD) [Column1], SUM(O1890287.RESOURCE_AMT_ACT) [Column2], (SUM(DECODE(O1890287.ACCOUNTING_PERIOD,'8',O1890287.RESOURCE_AMT_ACT,0)))-(SUM(DECODE(O1890287.ACCOUNTING_PERIOD,'8',O1890287.RESOURCE_AMT_BUD,0))) [Column3], SUM(DECODE(O1890287.ACCOUNTING_PERIOD,'8',O1890287.RESOURCE_AMT_BUD,0)) [Column4], SUM(DECODE(O1890287.ACCOUNTING_PERIOD,'8',O1890287.RESOURCE_AMT_ACT,0)) [Column5], SUM(O1890287.RESOURCE_AMT_ACT-O1890287.RESOURCE_AMT_BUD)  [Column6] FROM WAREHOUSE.PPL_RPTD_COST_MGMT01JAN00 O1890255, WAREHOUSE.PPL_RPTD_ACTIVITY_BUDG O1890258, WAREHOUSE.PPL_RPTD_BUD_ITEMS01JAN00 O1890261, WAREHOUSE.PROJECT_DENORMAL_GEN O1890286, WAREHOUSE.PROJ_RES_DENORMAL_GEN O1890287, WAREHOUSE.SRC_TREE_VW O1890288  WHERE ( ( O1890255.LEAF_DETAILS = O1890287.ACCOUNT ) AND ( O1890258.LEAF_DETAILS = O1890286.ACTIVITY ) AND ( O1890261.LEAF_DETAILS = O1890287.BUDGET_ITEM ) AND ( O1890286.PROJECT_ID = O1890287.PROJECT_ID ) AND ( O1890288.LEAF_DETAILS = O1890287.SRC ) ) AND ( (  ( O1890255.LEAF_DETAILS LIKE '12011' OR O1890255.LEAF_DETAILS = '10700' )  ) ) AND ( O1890287.ACTIVITY LIKE '000002F%' ) AND ( O1890287.SUB_PROJECT <> '897' AND O1890287.BUDGET_ITEM <> 'CAPBD' AND O1890287.SUB_PROJECT <> '896' ) AND ( O1890261.LEAF_DETAILS NOT IN ('PLTIS','14M00') ) AND ( O1890287.ACCOUNTING_PERIOD <= '8' ) AND ( O1890287.YEAR = '2012' ) AND ( O1890286.BUSINESS_UNIT LIKE '52110' ) AND ( O1890287.ACCOUNTING_PERIOD NOT IN (998,999) ) AND ( O1890287.SYSTEM_SOURCE NOT IN (( 'PLT' )) )  GROUP BY O1890255.LEAF_DETAILS, O1890286.ACTIVITY, O1890258.LEAF_DETAILS_DESCR, O1890261.LEAF_DETAILS, O1890261.LEAF_DETAILS_DESCR, O1890286.BUSINESS_UNIT, O1890286.PROJECT_DESCR, O1890287.PROJECT_ID, O1890288.LEAF_DETAILS, O1890288.LEAF_DETAILS_DESCR, O1890287.SUB_PROJECT, O1890287.SYSTEM_SOURCE, O1890287.YEAR

【讨论】:

【参考方案2】:

位置而不是名称引用分组列,例如:

select col1, col2, sum(col3), col4
from table
group by 1, 2, 4;

仅供参考,此语法选项是 SQL 标准的一部分,适用于所有 SQL 数据库。

【讨论】:

【参考方案3】:

试试这个:

SELECT O1890255.LEAF_DETAILS as LEAF_DETAILS1, O1890286.ACTIVITY, O1890258.LEAF_DETAILS_DESCR as LEAF_DETAILS_DESCR1 , O1890261.LEAF_DETAILS as LEAF_DETAILS2, O1890261.LEAF_DETAILS_DESCR as LEAF_DETAILS_DESCR2, O1890286.BUSINESS_UNIT, O1890286.PROJECT_DESCR, O1890287.PROJECT_ID, O1890288.LEAF_DETAILS as LEAF_DETAILS3, O1890288.LEAF_DETAILS_DESCR as LEAF_DETAILS_DESCR3, O1890287.SUB_PROJECT, O1890287.SYSTEM_SOURCE, O1890287.YEAR, SUM(O1890287.RESOURCE_AMT_BUD), SUM(O1890287.RESOURCE_AMT_ACT), ( SUM(DECODE(O1890287.ACCOUNTING_PERIOD,'8',O1890287.RESOURCE_AMT_ACT,0)) )-( SUM(DECODE(O1890287.ACCOUNTING_PERIOD,'8',O1890287.RESOURCE_AMT_BUD,0)) ), SUM(DECODE(O1890287.ACCOUNTING_PERIOD,'8',O1890287.RESOURCE_AMT_BUD,0)), SUM(DECODE(O1890287.ACCOUNTING_PERIOD,'8',O1890287.RESOURCE_AMT_ACT,0)), SUM(O1890287.RESOURCE_AMT_ACT-O1890287.RESOURCE_AMT_BUD)

FROM WAREHOUSE.PPL_RPTD_COST_MGMT01JAN00 O1890255, WAREHOUSE.PPL_RPTD_ACTIVITY_BUDG O1890258, WAREHOUSE.PPL_RPTD_BUD_ITEMS01JAN00 O1890261, WAREHOUSE.PROJECT_DENORMAL_GEN O1890286, WAREHOUSE.PROJ_RES_DENORMAL_GEN O1890287, WAREHOUSE.SRC_TREE_VW O1890288

WHERE ( ( O1890255.LEAF_DETAILS = O1890287.ACCOUNT ) AND ( O1890258.LEAF_DETAILS = O1890286.ACTIVITY ) AND ( O1890261.LEAF_DETAILS = O1890287.BUDGET_ITEM ) AND ( O1890286.PROJECT_ID = O1890287.PROJECT_ID ) AND ( O1890288.LEAF_DETAILS = O1890287.SRC ) ) AND ( (  ( O1890255.LEAF_DETAILS LIKE '12011' OR O1890255.LEAF_DETAILS = '10700' )  ) ) AND ( O1890287.ACTIVITY LIKE '000002F%' ) AND ( O1890287.SUB_PROJECT <> '897' AND O1890287.BUDGET_ITEM <> 'CAPBD' AND O1890287.SUB_PROJECT <> '896' ) AND ( O1890261.LEAF_DETAILS NOT IN ('PLTIS','14M00') ) AND ( O1890287.ACCOUNTING_PERIOD <= '8' ) AND ( O1890287.YEAR = '2012' ) AND ( O1890286.BUSINESS_UNIT LIKE '52110' ) AND ( O1890287.ACCOUNTING_PERIOD NOT IN (998,999) ) AND ( O1890287.SYSTEM_SOURCE NOT IN (( 'PLT' )) )

GROUP BY O1890255.LEAF_DETAILS, O1890286.ACTIVITY, O1890258.LEAF_DETAILS_DESCR, O1890261.LEAF_DETAILS, O1890261.LEAF_DETAILS_DESCR, O1890286.BUSINESS_UNIT, O1890286.PROJECT_DESCR, O1890287.PROJECT_ID, O1890288.LEAF_DETAILS, O1890288.LEAF_DETAILS_DESCR, O1890287.SUB_PROJECT, O1890287.SYSTEM_SOURCE, O1890287.YEAR

【讨论】:

以上是关于Group By 语句中的重复列的主要内容,如果未能解决你的问题,请参考以下文章

MySQL - 使用不在列表中的列对 Group By 语句排序 [重复]

sql语句中的group by啥意思

SQL group by 和 sum 基于其他列中的不同值(如果其他列中的值重复,则求和一次)

数据库中通过group by找出表中的重复数据

sqlserver中分区函数 partition by与 group by 区别 删除关键字段重复列

SELECT 列表不在 GROUP BY 子句中,并且包含非聚合列 [重复]