2014-10-03 122 views
0

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

以下工作创建列“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 |    | 
+----------------+------------+-----------+------------+-----------+-------------+ 

而这正是我希望acheive:

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

我对此感到抱歉,谢谢你耐心等待。 如果这不能说明我的问题,请删除这篇文章。

+5

你不能给一个字段多个别名,所以底部'CASE'不起作用。一些示例数据和所需的输出将会很有帮助,同样,您使用的是哪个数据库? – 2014-10-03 19:21:20

+2

尝试运行它,看看会发生什么。 (破坏者:它不会工作) – Siyual 2014-10-03 19:21:43

+0

你似乎在寻找数据透视技术,但是你错过了一个重要的部分,聚合函数(通常是'MAX'):你的第一个代码片段应该是'SELECT MAX(CASE ... END) AS Sig_1_Emp,MAX(CASE ... END)AS Sig_3_staff,.... GROUP BY ...' – a1ex07 2014-10-03 19:27:01

回答

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行具有相同的价值认识,那么你就必须弄清楚选择或导出值的一些其他的方式,基于这样做行出现在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;我不认为在这种情况下,明确表示是否值得房地产(双关)。

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子句中包括。

0

寻找一种方式来使用别名,而不会产生一个新行/线

你措辞这个问题的方式返回列是红旗,上面写着你可能不理解一个关于数据库的形式和功能的一些重要的事情。

A SELECT严格来说,查询会返回一个结构集,该结果集具有固有结构,而与查询的显示方式无关。所以这个查询不会“产生”一个新行或一个新行,如果你用这些术语来考虑你的结果,你会经常遇到这种麻烦。在这里我不会详细讨论,但我强烈建议读一下关于关系模型和基于集合的思考。

你想在这里做两个不同的东西:

  1. 选择值仅基于您的表(VisitSignatures.order)的单个属性的结果集(Sig_1_EmpSig_1_Staff)的多个属性。
  2. 将多个行的聚合值合并为一行。

CASE表达是不是真的为了做任何的这些东西对自己的;它只是一个表达式,当你需要一个条件逻辑用于单列。您不能在多个列中使用函数或表达式。但是,你可以使用一个单独的表达式为每个条款:

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' | 
+-----------+-------------+ 

到目前为止,你只完成了第一个任务。第二,你必须使用聚合函数。您使用哪种功能取决于您想要执行的操作,但是如果要计算每列中的员工数量,则只需在CASE表达式中包含COUNT()函数。保持别名功能外(可能改变他们表示计数的东西)和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进行优化,并且速度非常快。这是你必须自己研究的东西。

如果你碰巧使用MySQL,请阅读:Case Expression vs Case Statement

+0

尽管这个答案非常详细,除非我只是错过了它,但我没有看到他们使用MySQL作为数据库的迹象,但是它非常针对该RDBMS。任何你为什么假设MySQL的原因? – Taryn 2014-10-03 21:15:27

+0

我通常坚持那个标签,一定有一个大脑放屁,并恢复到旧习惯。相应修改。谢谢你的收获。 – Air 2014-10-03 21:37:41