sql,case的时候再为

时间:2014-10-03 19:18:56

标签: sql case alias

经过大量搜索网络和Stackoverflow后,仍在寻找一种方法来使用ALIAS返回列而不产生新的行/行。

以下工作创建列“Sig_1_Emp”和“Sig_3_Staff”,但Sig_1_Emp和Sig_3_Staff的数据不在同一行,而是两行。

CASE
    WHEN VisitSignatures.order = 1 THEN Employees.last_name

    END AS Sig_1_Emp,

CASE
    WHEN VisitSignatures.order = 3 THEN Employees.last_name

    END AS Sig_3_Staff

那么,会不会像以后那样工作?

CASE WHEN VisitSignatures.order = 1 THEN Employees.last_name AS Sig_1_Emp
     WHEN VisitSignatures.order = 3 THEN Employees.last_name AS Sig_3_Staff
END

以下是完整查询:

Select 
CV.clientvisit_id, 
CV.program_id, 
CV.visittype, 
CV.non_billable, 
CV.rev_timein, 

CASE
    WHEN CVSig.ord = 1 THEN Employees.last_name
    ELSE Null
    END AS Sig_1_Emp,

CASE
    WHEN CVSig.ord = 3 THEN Employees.last_name
    ELSE Null
    END AS Sig_3_Staff

From CV 
Inner Join CVSig On CV.clientvisit_id = CVSig.clientvisit_id 
Inner Join EmpSig On CVSig.employeesignature_id = EmpSig.employeesignature_id 
Inner Join Employees On EmpSig.emp_id = Employees.emp_id 

Where 
CV.program_id In (121, 123)     
And CV.rev_timein >= @param1 
And CV.rev_timein <= DATEADD(d, 1, @param2)

结果样本:

+----------------+------------+-----------+------------+-----------+-------------+  
| clientvisit_id | program_id | visittype | rev_timein | sig_1_emp | sig_3_staff |
+----------------+------------+-----------+------------+-----------+-------------+  
| 1001           | 121        | M_Mgmnt   | 7/1/2014   |           | Nurse_Pat   |
| 1001           | 121        | M_Mgmnt   | 7/1/2014   | Doc_Sue   |             |
+----------------+------------+-----------+------------+-----------+-------------+

这就是我希望实现的目标:

+----------------+------------+-----------+------------+-----------+-------------+  
| clientvisit_id | program_id | visittype | rev_timein | sig_1_emp | sig_3_staff |
+----------------+------------+-----------+------------+-----------+-------------+  
| 1001           | 121        | M_Mgmnt   | 7/1/2014   | Doc_Sue   | Nurse_Pat   |
+----------------+------------+-----------+------------+-----------+-------------+

我为这种困惑道歉,并感谢您的耐心等待。 如果这不能澄清我的问题,请删除此帖子。

3 个答案:

答案 0 :(得分:2)

如果我正确理解您的问题,您可以尝试pivot您的结果。您可以将max聚合与case语句一起使用来执行此操作:

select 
    otherfields,
    max(CASE WHEN VisitSignatures.order = 1 
             THEN Employees.last_name END) AS Sig_1_Emp,
    max(CASE WHEN VisitSignatures.order = 3 
             THEN Employees.last_name END) AS Sig_3_Staff
from tables (VisitSignatures and Employees and others)
group by otherfields

无论您选择哪个其他字段,您都希望包含在group by条款中。

答案 1 :(得分:0)

  

寻找一种方法来使用ALIAS返回列而不产生新的行/行

您表达这个问题的方式是一个红旗,表示您可能无法理解有关数据库形式和功能的一些重要事项。

严格来说,SELECT查询会返回一个具有固有结构的结果集,与其显示方式无关。所以查询不会产生&#34;新行或新行,如果您按照这些条款考虑结果,您将经常遇到这种麻烦。我不打算在这里详细介绍,但我强烈建议您阅读关于关系模型和基于集合的思考。

你想在这里做两件不同的事情:

  1. 为结果集(Sig_1_EmpSig_1_Staff)的多个属性选择值,仅基于表格的一个属性(VisitSignatures.order) 。
  2. 将值从多行聚合到一行。
  3. CASE表达式 1 并非真正设计为独立完成其中任何一项;它只是当你需要一个条件逻辑用于单个列时使用的表达式。您不能跨多个列使用函数或表达式。但是,您可以为每个子句使用单独的表达式:

    SELECT
      CASE sig.order WHEN 1 THEN emp.last_name END AS Sig_1_Emp,
      CASE sig.order WHEN 3 THEN emp.last_name END AS Sig_3_Staff
    FROM
      VisitSignatures AS sig
        JOIN
      Employees AS emp ON (...);
    

    请注意,我已将您的表别名化以使语句更清晰;您将填写您的加入条件和所需的任何WHERE条款。这将使你从以下(加入)表中获得:

    +-----------+---------------+
    | sig.order | emp.last_name |
    +-----------+---------------+
    | 1         | 'SMITH'       |
    | 1         | 'NGUYEN'      |
    | 3         | 'FIELDS'      |
    +-----------+---------------+
    

    到此结果集:

    +-----------+-------------+
    | Sig_1_Emp | Sig_3_Staff |
    +-----------+-------------+
    | 'SMITH'   | NULL        |
    | 'NGUYEN'  | NULL        |
    | NULL      | 'FIELDS'    |
    +-----------+-------------+
    

    到目前为止,您只完成了第一项任务。对于第二个,您必须使用聚合函数。您使用哪种功能取决于您想要做什么,但如果您想要计算每列中的员工数量,那么您需要做的就是在COUNT()表达式周围包含CASE函数。将别名保留在函数之外(并可能将其更改为指示计数的内容)和GROUP BY查询中请求的任何非聚合列,以获得类似的内容:

    SELECT
      other_columns,
      COUNT(CASE sig.order WHEN 1 THEN emp.last_name END) AS Num_Sig_1,
      COUNT(CASE sig.order WHEN 3 THEN emp.last_name END) AS Num_Sig_3
    FROM
      VisitSignatures AS sig
        JOIN
      Employees AS emp ON (...)
    GROUP BY other_columns;
    
    +-----+-----------+-----------+
    | ... | Num_Sig_1 | Num_Sig_3 |
    +-----+-----------+-----------+
    | ... | 2         | 1         |
    +-----+-----------+-----------+
    

    请注意,CASE表达式为您提供了中间结果集中的字符串 - 如果您只想计算非NULL值,这可能不是最有效的方法根据您使用的DBMS,进行操作。例如,在MySQL中执行此操作会更有效(为简洁起见,忽略额外的列/表):

    SELECT
      order = 1 AS Sig_1_Emp,
      order = 3 AS Sig_3_Staff
    FROM
      VisitSignatures;
    

    产:

    +-----------+-------------+
    | Sig_1_Emp | Sig_3_Staff |
    +-----------+-------------+
    | 1         | 0           |
    | 1         | 0           |
    | 0         | 1           |
    +-----------+-------------+
    

    您将使用SUM()代替COUNT()进行汇总,以获得与之前相同的结果。您还没有说过您正在使用哪个DBMS,但即使它不是MySQL,您也应该仔细考虑是否确实需要在中间结果集中使用这些姓氏。只要表格中没有太多行,但设计效率低下的查询很容易,但在将来会出现问题。

    另一方面,您的DBMS可能能够以引用该值的方式优化emp.last_name而不将其存储在中间表中,并且非常快。这是你必须自己研究的东西。

    1 如果您正在使用MySQL,请阅读:Case Expression vs Case Statement

答案 2 :(得分:0)

鉴于您对问题的更新,很明显您缺少的是具有适当聚合函数的GROUP BY子句。

请注意,在您的示例结果中,前四列(clientvisit_idprogram_idvisittyperev_timein)在两个示例行中都包含相同的值。如果您GROUP BY这四列,示例行将被分组为一行,因为它们的值相同。我不确定你为什么不在这里展示non_billable,但这个概念扩展到你想用来定义不同组的列数。

由于sig_1_empsig_3_staff列不用于分组,因此它们必须与one of the available aggregate functions一起使用,而不是列列表中的“裸”。在这种情况下,典型的做法是使用MIN()MAX(),这两个行都忽略NULL行,只返回多个值中的一个。当组中的所有值相等时,它们是等价的,否则它们会给出最小值或最大值。

如果您不自信地知道所有非NULL行具有相同的值,那么您将必须根据行执行的方式找出选择或派生值的其他方法。 not 出现在GROUP BY子句中,或者随意取任何值作为最大值或最小值进行比较。请记住,每种数据类型都可能有自己的比较规则。似乎不可取。

因此,请尝试将其添加到查询的末尾:

GROUP BY clientvisit_id, program_id, visittype, rev_timein, non_billable

并将CASE表达式包装起来:

MAX(CASE WHEN CVSig.ord = 1 THEN Employees.last_name END) AS Sig_1_Emp,
MAX(CASE WHEN CVSig.ord = 3 THEN Employees.last_name END) AS Sig_3_Staff

看看是否有诀窍(记住已经说过的警告)。如果您愿意,可以保留ELSE NULL,但如果没有任何案例属实,表达式将为NULL;在这种情况下,我不认为明确是值得的房地产(双关语)。