SQL如何控制分组列

时间:2014-07-01 11:09:53

标签: sql

我已经创建了一个查询。在该查询中,有一些表连接到另一个表 table.I m直接获取列ContactId,FirstName,LastName,CreatedOn的值。 对于paymnettype列,我正在解析P.new_name中的值(值类似于'Credit Card - 2014-06-29')。对于paymenttype,'Credit Card'和'Miles Point'有2种类型的值

我在该查询中的主要目的是获得每个联系人的航班预订利润的总和,这就是为什么我要按除totalamount列之外的所有列对表进行分组 聚合函数work.I m按paytype对表进行分组,因为我必须这样做,否则它会按预期给出错误。

问题在于,如果联系人在两种付款方式中进行了预订,那么contactid将显示在两列中。

我希望将其显示在一列中,在查询中像往常一样获取总和并在paymenttype列中写入“all”。 这是可能的。如果是的话,任何关于我如何做到这一点的想法。

另外我应该提一下,我会在SSRS中使用该查询,所以解决SSRS方面问题的任何想法都会对我有帮助

   Select C.ContactId,C.FirstName,C.LastName,C.CreatedOn,

     LTRIM(RTRIM(left(P.new_name ,(CHARINDEX('-',P.new_name)-1))))) as paymenttype, 

     SUM(F.new_totalamounttl) as totalamount

     From Contact C 

     left join  SalesOrder S on C.ContactId=S.ContactId
     left join new_flightreservation F on S.SalesOrderId=F.new_salesorderid 
     left join new_payment P on F.new_paymentid=P.new_paymentId 

     where 
     (LTRIM(RTRIM(left(P.new_name ,(CHARINDEX('-',P.new_name)-1))))) IN 
     ( CASE @paymenttype WHEN 'all'
      THEN  (LTRIM(RTRIM(left(P.new_name ,(CHARINDEX('-',P.new_name)-1)))))
      ELSE @paymenttype END )

      GROUP BY C.ContactId,C.FirstName,C.LastName,C.CreatedOn,

       (LTRIM(RTRIM(left(P.new_name ,(CHARINDEX('-',P.new_name)-1)))))

3 个答案:

答案 0 :(得分:2)

我认为通过将其分为两部分,您可以获得相当优雅的解决方案。第一部分处理PaymentType,第二部分基于此进行分组/求和。

SELECT
    ContactId
    ,FirstName
    ,LastName
    ,CreatedOn
    ,SUM(subamount) totalamount
    ,paymenttype
FROM
(
    Select 
        C.ContactId
        ,C.FirstName
        ,C.LastName
        ,C.CreatedOn
        ,@paymenttype as paymenttype
        ,CASE
            WHEN @paymenttype = ‘all’ THEN F.new_totalamounttl
            WHEN @paymenttype = LTRIM(RTRIM(LEFT(P.new_name ,(CHARINDEX('-',P.new_name)-1))))) THEN F.new_totalamounttl
        ELSE 0 END as subamount
    From
        Contact C 
        left join  SalesOrder S 
            on C.ContactId=S.ContactId
        left join new_flightreservation F 
            on S.SalesOrderId=F.new_salesorderid 
        left join new_payment P 
            on F.new_paymentid=P.new_paymentId 
) sub
GROUP BY
     ContactId
     ,FirstName
     ,LastName
     ,CreatedOn
     ,paymenttype

答案 1 :(得分:1)

注意事项:这个解决方案非常难看,但我认为它有效(可能性能很差)。我还在考虑一种更好的方法。

让我们将解析与连接隔离开来,这样完整的查询将更容易理解;我们也会将Contact放在一边,因为最后可以加入任何ContactId值以获取完整的Contact详细信息。请注意,既没有分组也没有汇总功能:

Select 

S.ContactId,
LTRIM(RTRIM(left(P.new_name ,(CHARINDEX('-',P.new_name)-1)))) as paymenttype, 
F.new_totalamounttl as totalamount

From 

SalesOrder S
left join new_flightreservation F on S.SalesOrderId=F.new_salesorderid 
left join new_payment P on F.new_paymentid=P.new_paymentId 

上面的子查询“生成”(虽然没有具体化)每个预订每个订单每行订单一行,并解析付款名称(如果您的数据库已规范化,这将是不必要的)。由于每个订单属于一个联系人,因此也是每次联系。

现在我们按@paymenttype过滤:

SELECT  *
FROM    (
    Select 

    S.ContactId,
    LTRIM(RTRIM(left(P.new_name ,(CHARINDEX('-',P.new_name)-1)))) as paymenttype, 
    F.new_totalamounttl as totalamount

    From

    SalesOrder S
    left join new_flightreservation F on S.SalesOrderId=F.new_salesorderid 
    left join new_payment P on F.new_paymentid=P.new_paymentId 
) AS x

WHERE 

@paymenttype = x.paymenttype OR @paymenttype = 'all'

-- alternatively in some databases (rather ugly, but concise):
-- @paymenttype IN (x.paymenttype, 'all')

这反过来被视为一个匿名视图(我将在下面的评论中称之为“A”)在下一个查询中,有两个分支:第一个将收集其支付类型完全相同的行(即没有其他类型的付款);另一个分支将收集其他行(每个订单的不同付款类型)。这次我们已经汇总了已支付的金额。

-- 1st branch
SELECT  y.ContactId, y.paymenttype, SUM(y.totalamount) AS totalamount
FROM    (
    -- the view A
    SELECT  *
    FROM    (
        Select 

        S.ContactId,
        LTRIM(RTRIM(left(P.new_name ,(CHARINDEX('-',P.new_name)-1)))) as paymenttype, 
        F.new_totalamounttl as totalamount

        From

        SalesOrder S
        left join new_flightreservation F on S.SalesOrderId=F.new_salesorderid 
        left join new_payment P on F.new_paymentid=P.new_paymentId 
    ) AS x

    WHERE 

    x.paymenttype = @paymenttype OR @paymenttype = 'all'
) AS y

WHERE 

NOT EXISTS (
    SELECT  *
    FROM    (
        -- the view A (again)
        SELECT  *
        FROM    (
            Select 

            S.ContactId,
            LTRIM(RTRIM(left(P.new_name ,(CHARINDEX('-',P.new_name)-1)))) as paymenttype, 
            F.new_totalamounttl as totalamount

            From

            SalesOrder S
            left join new_flightreservation F on S.SalesOrderId=F.new_salesorderid 
            left join new_payment P on F.new_paymentid=P.new_paymentId 
        ) AS x

        WHERE 

        x.paymenttype = @paymenttype OR @paymenttype = 'all'

    ) AS y1

    WHERE   y.ContactId = y1.ContactId
        AND y.paymenttype <> y1.paymenttype
)

GROUP BY y.ContactId, y.paymenttype

UNION ALL

-- 2nd branch
SELECT  y.ContactId, 'all' AS paymenttype, SUM(y.totalamount) AS totalamount
FROM    (
    -- the view A
    SELECT  *
    FROM    (
        Select 

        S.ContactId,
        LTRIM(RTRIM(left(P.new_name ,(CHARINDEX('-',P.new_name)-1)))) as paymenttype, 
        F.new_totalamounttl as totalamount

        From

        SalesOrder S
        left join new_flightreservation F on S.SalesOrderId=F.new_salesorderid 
        left join new_payment P on F.new_paymentid=P.new_paymentId 
    ) AS x

    WHERE 

    x.paymenttype = @paymenttype OR @paymenttype = 'all'
) AS y

WHERE 

EXISTS (
    SELECT  *
    FROM    (
        -- the view A (again)
        SELECT  *
        FROM    (
            Select 

            S.ContactId,
            LTRIM(RTRIM(left(P.new_name ,(CHARINDEX('-',P.new_name)-1)))) as paymenttype, 
            F.new_totalamounttl as totalamount

            From

            SalesOrder S
            left join new_flightreservation F on S.SalesOrderId=F.new_salesorderid 
            left join new_payment P on F.new_paymentid=P.new_paymentId 
        ) AS x

        WHERE 

        x.paymenttype = @paymenttype OR @paymenttype = 'all'

    ) AS y1

    WHERE   y.ContactId = y1.ContactId
        AND y.paymenttype <> y1.paymenttype
)

GROUP BY y.ContactId

现在到最后查询,恢复Contact详细信息。上面的查询被视为匿名视图以简化连接:

Select C.ContactId,C.FirstName,C.LastName,C.CreatedOn,
    z.paymenttype, z.totalamount

From Contact C
left join (
    -- 1st branch
    SELECT  y.ContactId, y.paymenttype, SUM(y.totalamount) AS totalamount
    FROM    (
        -- the view A
        SELECT  *
        FROM    (
            Select 

            S.ContactId,
            LTRIM(RTRIM(left(P.new_name ,(CHARINDEX('-',P.new_name)-1)))) as paymenttype, 
            F.new_totalamounttl as totalamount

            From

            SalesOrder S
            left join new_flightreservation F on S.SalesOrderId=F.new_salesorderid 
            left join new_payment P on F.new_paymentid=P.new_paymentId 
        ) AS x

        WHERE 

        x.paymenttype = @paymenttype OR @paymenttype = 'all'
    ) AS y

    WHERE 

    NOT EXISTS (
        SELECT  *
        FROM    (
            -- the view A (again)
            SELECT  *
            FROM    (
                Select 

                S.ContactId,
                LTRIM(RTRIM(left(P.new_name ,(CHARINDEX('-',P.new_name)-1)))) as paymenttype, 
                F.new_totalamounttl as totalamount

                From

                SalesOrder S
                left join new_flightreservation F on S.SalesOrderId=F.new_salesorderid 
                left join new_payment P on F.new_paymentid=P.new_paymentId 
            ) AS x

            WHERE 

            x.paymenttype = @paymenttype OR @paymenttype = 'all'

        ) AS y1

        WHERE   y.ContactId = y1.ContactId
            AND y.paymenttype <> y1.paymenttype
    )

    GROUP BY y.ContactId, y.paymenttype

    UNION ALL

    -- 2nd branch
    SELECT  y.ContactId, 'all' AS paymenttype, SUM(y.totalamount) AS totalamount
    FROM    (
        -- the view A
        SELECT  *
        FROM    (
            Select 

            S.ContactId,
            LTRIM(RTRIM(left(P.new_name ,(CHARINDEX('-',P.new_name)-1)))) as paymenttype, 
            F.new_totalamounttl as totalamount

            From

            SalesOrder S
            left join new_flightreservation F on S.SalesOrderId=F.new_salesorderid 
            left join new_payment P on F.new_paymentid=P.new_paymentId 
        ) AS x

        WHERE 

        x.paymenttype = @paymenttype OR @paymenttype = 'all'
    ) AS y

    WHERE 

    EXISTS (
        SELECT  *
        FROM    (
            -- the view A (again)
            SELECT  *
            FROM    (
                Select 

                S.ContactId,
                LTRIM(RTRIM(left(P.new_name ,(CHARINDEX('-',P.new_name)-1)))) as paymenttype, 
                F.new_totalamounttl as totalamount

                From

                SalesOrder S
                left join new_flightreservation F on S.SalesOrderId=F.new_salesorderid 
                left join new_payment P on F.new_paymentid=P.new_paymentId 
            ) AS x

            WHERE 

            x.paymenttype = @paymenttype OR @paymenttype = 'all'

        ) AS y1

        WHERE   y.ContactId = y1.ContactId
            AND y.paymenttype <> y1.paymenttype
    )

    GROUP BY y.ContactId
) AS z on C.ContactId=z.ContactId

答案 2 :(得分:1)

借鉴my previous (and hackish) answer的想法,我可以设计以下(甚至更简洁,但更简洁)解决方案:

SELECT  C.ContactId,C.FirstName,C.LastName,C.CreatedOn,

        CASE 
            WHEN (
                    COUNT(CASE x.paymenttype WHEN 'Credit Card' THEN 1 ELSE NULL END)
                  * COUNT(CASE x.paymenttype WHEN 'Miles Point' THEN 1 ELSE NULL END)
                 ) > 0 THEN 'all'
            WHEN COUNT(CASE x.paymenttype WHEN 'Credit Card' THEN 1 ELSE NULL END) > 0 THEN 'Credit Card'
            ELSE 'Miles Point'
        END AS paymenttype,

        SUM(F.new_totalamounttl) AS totalamount
FROM    
    Contact C
    left join SalesOrder S on C.ContactId=S.ContactId
    left join new_flightreservation F on S.SalesOrderId=F.new_salesorderid 
    left join (
        Select 
            P.new_paymentId,
            LTRIM(RTRIM(left(P.new_name ,(CHARINDEX('-',P.new_name)-1)))) as paymenttype, 
        From new_payment P 
    ) AS x on F.new_paymentid=x.new_paymentId

WHERE   @paymenttype = x.paymenttype OR @paymenttype = 'all'

        -- alternatively, for the RDBMS that allows it:
        -- @paymenttype IN (x.paymenttype, 'all')
GROUP BY C.ContactId,C.FirstName,C.LastName,C.CreatedOn

编辑:稍微简化了查询以避免一个额外的匿名视图