将列选择为行以进行导出

时间:2013-02-28 15:31:39

标签: sql-server select unpivot

我有一个名为'transactions'的数据库表,其中有多列。对于每个事务行,我需要从指定列表中生成每列一行的导出

交易表

ID, DoNotEmail, DoNotMail, DoNotPhone, DoNotSMS
1000, true,    false,      true,       true

以下规则需要适用。

设置DoNotEmail然后输出'DNE'

设置DoNotMail然后输出'DNM'

设置DoNotPhone然后输出'DNP'

设置DoNotSMS然后输出'DNS'

导出需要看起来像:

ID, Suppressions
1000,  DNE
1000,  DNP
1000,  DNS

我真的很困惑,我能让它工作的唯一方法是将每个列插入两个临时表的插入语句非常可怕。 Urgh。

请问这可能吗?

感谢您的帮助。

的Darren

P.S。抱歉格式化。

5 个答案:

答案 0 :(得分:6)

如果您只有四列,这可能会有效:

SELECT id, 
       'DNE' AS Suppressions 
FROM   transactions 
WHERE  donotemail = 'true' 
UNION ALL 
SELECT id, 
       'DNM' AS Suppressions 
FROM   transactions 
WHERE  donotmail = 'true' 
UNION ALL 
SELECT id, 
       'DNP' AS Suppressions 
FROM   transactions 
WHERE  donotphone = 'true' 
UNION ALL 
SELECT id, 
       'DNS' AS Suppressions 
FROM   transactions 
WHERE  donotsms = 'true' 

SQL Fiddle Demo

答案 1 :(得分:6)

另一种可写方式是:

SELECT id,
  case col 
    when 'DoNotEmail' then 'DNE'
    when 'DoNotMail' then 'DNM'
    when 'DoNotPhone' then 'DNP'
    when 'DoNotSMS' then 'DNS'
  end Suppressions
FROM 
(
  SELECT t.ID,
    s.col,
    CASE s.col
      WHEN 'DoNotEmail' THEN DoNotEmail
      WHEN 'DoNotMail' THEN DoNotMail
      WHEN 'DoNotPhone' THEN DoNotPhone
      WHEN 'DoNotSMS' THEN DoNotSMS
    END AS DATA
  FROM Transactions t
  CROSS JOIN 
  (
    SELECT 'DoNotEmail' AS col
    UNION ALL SELECT 'DoNotMail'
    UNION ALL SELECT 'DoNotPhone'
    UNION ALL SELECT 'DoNotSMS'
  ) s
) s
where data = 'true';

请参阅SQL Fiddle with Demo

由于您使用的是SQL Server,因此可以实现UNPIVOT功能:

select id,
  case col 
    when 'DoNotEmail' then 'DNE'
    when 'DoNotMail' then 'DNM'
    when 'DoNotPhone' then 'DNP'
    when 'DoNotSMS' then 'DNS'
  end Suppressions
from Transactions
unpivot
(
  value 
  for col in ([DoNotEmail], [DoNotMail], [DoNotPhone], [DoNotSMS])
) piv
where value = 'true'

请参阅SQL Fiddle with Demo

答案 2 :(得分:4)

这将在SQL Server 2008或更高版本中有效。如果需要,可以将其修改为在SQL Server 2005上运行。

select T1.ID,
       T2.Name
from Transactions as T1
  cross apply (values (DoNotEmail, 'DNE'), 
                      (DoNotMail,  'DNM'), 
                      (DoNotPhone, 'DNP'), 
                      (DoNotSMS,   'DNS')
              ) as T2(Value, Name)
where T2.Value = 'true' 

答案 3 :(得分:1)

四个记录表上的CROSS JOIN可以节省四次扫描表。 bluefeet首先发布了一个答案(+1)。以下是使用Oracle的类似版本。

SELECT id, Suppressions FROM
(
  SELECT id, 
     CASE 
        WHEN Col = 1 AND donotemail = 'true' THEN 'DNE'
        WHEN Col = 2 AND donotmail  = 'true' THEN 'DNM'
        WHEN Col = 3 AND donotphone = 'true' THEN 'DNP'
        WHEN Col = 4 AND donotsms   = 'true' THEN 'DNS'
        ELSE NULL
     END Suppressions 
  FROM Transactions
  CROSS JOIN (SELECT Level Col FROM dual CONNECT BY Level <=4)
)
WHERE Suppressions IS NOT NULL;

SQL Fiddle

答案 4 :(得分:0)

select ID, 'DNE' as 'Suppressions'
from transactions
where DoNotEmail = 'true'
UNION ALL
select ID, 'DNM' as 'Suppressions'
from transactions
where DoNotMail = 'true'
UNION ALL
select ID, 'DNS' as 'Suppressions'
from transactions
where DoNotPhone = 'true'
UNION ALL
select ID, 'DNE' as 'Suppressions'
from transactions
where DoNotSMS = 'true'
order by ID