SQL 2014 - 使用CASE语句将行合并为单行,多列

时间:2017-07-11 16:09:02

标签: sql tsql case sql-server-2014

使用T-SQL的SQL Server 2014。

在我们的数据库中,客户遇到问题(!),并且针对客户分配的每个问题在我查询的表格中都有一个单独的行。

我希望为每个问题创建一行(以及其他一些信息),但目前,我的每个CASE语句都创建了一行。

所以输出是这样的(我已经改变了一些标题名称,所以它们适合这里):

Prod    Date        Time    Cust    Lname   Fname   Street 1          S2    City            Zip     Email               CSI     Action  Dog Prog    TourHeadsets
Tosca   08-Apr-17   2:30 PM 122253  Smith   Michael 33 Rodeo Drive    NULL  Beverley Hills  90210   msmith@email.com    NULL    NULL    0   None    0   1
Tosca   08-Apr-17   2:30 PM 122253  Smith   Michael 33 Rodeo Drive    NULL  Beverley Hills  90210   msmith@email.com    NULL    NULL    0   Large   0   0
Tosca   08-Apr-17   2:30 PM 122253  Smith   Michael 33 Rodeo Drive    NULL  Beverley Hills  90210   msmith@email.com    NULL    NULL    0   None    2   0
Tosca   08-Apr-17   2:30 PM 125634  Brown   Sarah   22 Victory Drive  NULL  Beverley Hills  90210   sbrown@email.com    NULL    NULL    0   Large   0   0
Tosca   08-Apr-17   2:30 PM 125634  Brown   Sarah   22 Victory Drive  NULL  Beverley Hills  90210   sbrown@email.com    NULL    NULL    0   None    2   0
Tosca   08-Apr-17   2:30 PM 125634  Brown   Sarah   22 Victory Drive  NULL  Beverley Hills  90210   sbrown@email.com    NULL    NULL    0   None    0   2

但是我喜欢这个(在同一行的不同列中有4个CASE语句的结果):

Prod Date       Time    Cust    Lname   Fname   Street 1         S2  City   Zip Email   CSI Action  Dog Prog    Tour    Headsets
Tosca   08-Apr-17   2:30 PM 122253  Smith   Michael 33 Rodeo Drive   NULL   Beverley Hills  90210   msmith@email.com    NULL    NULL    0   Large print 2   1
Tosca   08-Apr-17   2:30 PM 125634  Brown   Sarah   22 Victory Drive NULL   Beverley Hills  90210   sbrown@email.com    NULL    NULL    0   Large print 2   2

新手的任何帮助?! (关于代码的任何其他反馈也非常受欢迎。我对此非常陌生。)以下是我用来实现这一目标的代码:

USE impresario
    SELECT 
    g.description AS 'Production'
    ,CONVERT(varchar,f.perf_dt,106) AS 'Date'
    ,FORMAT(CAST(f.perf_dt AS DATETIME),'h:mm tt') AS 'Time'
    ,a.customer_no AS 'Customer'
    ,b.lname AS 'Last name'
    ,b.fname AS 'First name'
    ,c.street1 AS 'Street 1'
    ,c.street2 AS 'Street 2'
    ,c.city AS 'City'
    ,c.postal_code AS 'Postal code'
    ,d.address
    ,a.notes AS 'CSI notes' 
    ,e.notes AS 'Action notes'
    ,CASE h.id
       WHEN 14 THEN '1'
       WHEN 15 THEN '2'
       ELSE '0'
       END
       AS 'Dogs'
    ,CASE h.id
       WHEN 16 THEN 'Large print'
       WHEN 17 THEN 'Braille'
       ELSE 'None'
       END
       AS 'Programmes'
    ,CASE h.id
       WHEN 18 THEN '1'
       WHEN 19 THEN '2'
       ELSE '0'
       END
       AS 'Touch tour'
    ,CASE h.id
       WHEN 20 THEN '1'
       WHEN 21 THEN '2'
       ELSE '0'
       END
       AS 'Headsets'
      FROM T_CUST_ACTIVITY a
      JOIN T_CUSTOMER b ON b.customer_no=a.customer_no
      JOIN T_ADDRESS c ON c.customer_no=a.customer_no
      JOIN T_EADDRESS d ON d.customer_no=a.customer_no
      JOIN T_ISSUE_ACTION e ON e.activity_no=a.activity_no
      JOIN T_PERF f ON f.perf_no=a.perf_no
      JOIN T_INVENTORY g ON g.inv_no=f.prod_season_no
      JOIN TR_ACTION h ON h.id=e.action
      WHERE a.activity_type=21 --'Access requirements' from TR_CUST_ACTIVITY_TYPE
      AND c.primary_ind='Y' --Primary addresses only
      AND d.primary_ind='Y' --Primary emails only
      AND e.action IN 
      (
       14 --Dog x1
      ,15 --Dog x2
      ,16 --Programme (large print)
      ,17 --Programme (braille)
      ,18 --Touch tour x1
      ,19 --Touch tour x2
      ,20 --Headset x1
      ,21 --Headset x2
      )
      ORDER BY f.perf_dt, a.customer_no ASC

3 个答案:

答案 0 :(得分:0)

当遇到这类问题时,我会这样做 - 使用子查询或CTE对要组合的项目进行分组。如果没有关于数据模型和边缘情况的更多细节,很难确切地知道您需要什么。 (@CuriousKid在他的评论中给出了一些关于这些案例的提示。)但我对最常见的案例做了假设。

注意,我拿出了不需要的连接并清理了一些可怕的格式。

 WITH actions AS
 (
    SELECT
      activity_no,
      MAX(CASE e.action WHEN 14 THEN '1' WHEN 15 THEN '2' ELSE null END) AS dogs,
      MAX(CASE e.action WHEN 16 THEN 'Large print' WHEN 17 THEN 'Braille' ELSE null END) AS programmes,
      MAX(CASE e.action WHEN 20 THEN '1'  WHEN 21 THEN '2' ELSE null END AS headsets
      MAX(CASE e.action WHEN 18 THEN '1' WHEN 19 THEN '2' ELSE null END) AS tt,
      LISTAGG(e.notes, ', ') as notes
    FROM T_ISSUE_ACTION e
    WHERE e.action IN (
       14 --Dog x1
      ,15 --Dog x2
      ,16 --Programme (large print)
      ,17 --Programme (braille)
      ,18 --Touch tour x1
      ,19 --Touch tour x2
      ,20 --Headset x1
      ,21 --Headset x2
    )
    GROUP BY activity_no
 )
 SELECT 
    g.description AS 'Production'
    ,CONVERT(varchar,f.perf_dt,106) AS 'Date'
    ,FORMAT(CAST(f.perf_dt AS DATETIME),'h:mm tt') AS 'Time'
    ,a.customer_no AS 'Customer'
    ,b.lname AS 'Last name'
    ,b.fname AS 'First name'
    ,c.street1 AS 'Street 1'
    ,c.street2 AS 'Street 2'
    ,c.city AS 'City'
    ,c.postal_code AS 'Postal code'
    ,d.address
    ,a.notes AS 'CSI notes' 
    ,e.notes AS 'Action notes'
    ,e.dogs AS 'Dogs'
    ,e.programmes AS 'Programmes'
    ,e.tt AS 'Touch tour'
    ,e.headset AS 'Headsets'
 FROM T_CUST_ACTIVITY a
 JOIN T_CUSTOMER b ON b.customer_no=a.customer_no
 JOIN T_ADDRESS c ON c.customer_no=a.customer_no  AND c.primary_ind='Y' --Primary addresses only
 JOIN T_EADDRESS d ON d.customer_no=a.customer_no   AND d.primary_ind='Y' --Primary emails only
 LEFT JOIN actions e ON e.activity_no=a.activity_no
 JOIN T_PERF f ON f.perf_no=a.perf_no
 JOIN T_INVENTORY g ON g.inv_no=f.prod_season_no
 WHERE a.activity_type=21 --'Access requirements' from TR_CUST_ACTIVITY_TYPE
 ORDER BY f.perf_dt, a.customer_no ASC

答案 1 :(得分:0)

您可以在cte中使用您的查询并使用row_number来获得以下结果:

;With Cte as (
    --your full query
), Cte2 as (
Select *, RowN = Row_Number() over(partition by Lname, Fname order by [Tour] desc)
    , [HeadSetsMax] = max(headsets) over(Partition by Lname, Fname)
    from Cte
    )
    Select * from Cte2 where RowN = 1

答案 2 :(得分:0)

我找到了一种方法来解决这个问题,使用MAX来对付每个CASE语句,这似乎有效:

USE impresario
SELECT 
g.description AS 'Production'
,CONVERT(varchar,f.perf_dt,106) AS 'Date'
,FORMAT(CAST(f.perf_dt AS DATETIME),'h:mm tt') AS 'Time'
,a.customer_no AS 'Customer'
,b.lname AS 'Last name'
,b.fname AS 'First name'
,c.street1 AS 'Street 1'
,c.street2 AS 'Street 2'
,c.city AS 'City'
,c.postal_code AS 'Postal code'
,d.address
,a.notes AS 'CSI notes' 
,e.notes AS 'Action notes'
,MAX(CASE h.id
   WHEN 14 THEN '1'
   WHEN 15 THEN '2'
   ELSE '0'
   END)
   AS 'Dogs'
,MAX(CASE h.id
   WHEN 16 THEN 'Large print'
   WHEN 17 THEN 'Braille'
   ELSE 'None'
   END)
   AS 'Programmes'
,MAX(CASE h.id
   WHEN 18 THEN '1'
   WHEN 19 THEN '2'
   ELSE '0'
   END)
   AS 'Touch tour'
,MAX(CASE h.id
   WHEN 20 THEN '1'
   WHEN 21 THEN '2'
   ELSE '0'
   END)
   AS 'Headsets'
  FROM T_CUST_ACTIVITY a
  JOIN T_CUSTOMER b ON b.customer_no=a.customer_no
  JOIN T_ADDRESS c ON c.customer_no=a.customer_no
  JOIN T_EADDRESS d ON d.customer_no=a.customer_no
  JOIN T_ISSUE_ACTION e ON e.activity_no=a.activity_no
  JOIN T_PERF f ON f.perf_no=a.perf_no
  JOIN T_INVENTORY g ON g.inv_no=f.prod_season_no
  JOIN TR_ACTION h ON h.id=e.action
  WHERE a.activity_type=21 --'Access requirements' from TR_CUST_ACTIVITY_TYPE
  AND c.primary_ind='Y' --Primary addresses only
  AND d.primary_ind='Y' --Primary emails only
  AND e.action IN 
  (
   14 --Dog x1
  ,15 --Dog x2
  ,16 --Programme (large print)
  ,17 --Programme (braille)
  ,18 --Touch tour x1
  ,19 --Touch tour x2
  ,20 --Headset x1
  ,21 --Headset x2
  )
  GROUP BY 
  g.description
  , f.perf_dt
  , a.customer_no
  , b.lname
  , b.fname
  , c.street1
  , c.street2
  , c.city
  , c.postal_code
  , d.address
  , a.notes
  , e.notes
  ORDER BY 
  f.perf_dt
  , a.customer_no ASC