2014-10-03 123 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