有這樣一個需求:表T_FUN_TASK為任務表,有字段(TASKID,TASKNAME),表T_FUN_LOGBOOK為日志表,有字段(LOGID,TASKID,LOGDATE),一個任務可持續多天,每天會記錄一條日志。在查詢表T_FUN_TASK時,需將任務表中的 LOGDATE 查詢出來作為一列 LOGDATES顯示。
T_FUN_TASK
T_FUN_LOGBOOK
查詢結果
此結果查詢方法可以用存儲過程輕松實現,這里我要介紹的是sqlserver FOR XML PATH語句的應用,在SQL Server中利用 FOR XML PATH 語句能夠把查詢的數據生成XML數據
且合並為一條數據,看以下示例:
SELECT LOGDATE FROM T_FUN_LOGBOOK WHERE TASKID=231 FOR XML PATH
結果為:
<row>
<logdate>2014-01-06T00:00:00</logdate>
</row>
<row>
<logdate>2014-01-07T00:00:00</logdate>
</row>
在前面的需求中,我是想要把這2條數據合並到一起且沒有XML標簽,條與條之間用下划線(_)分隔的,日期的格式也變為了2014/01/07的格式。下面來一步一步來完成需求。
首先,將日期格式轉化為需要的格式:
SELECT CONVERT(VARCHAR(100), LOGDATE, 111) FROM T_FUN_LOGBOOK WHERE TASKID=231 FOR XML PATH
結果變為:
<row>2014/01/06</row>
<row>2014/01/07</row>
可以發現,轉化字符卷的過程中,把logdate標簽給去掉了。現在我們要去掉<row>標簽:
SELECT CONVERT(VARCHAR(100), LOGDATE, 111) FROM T_FUN_LOGBOOK WHERE TASKID=231 FOR XML PATH('')
在PATH后面將一個空的字符卷作為參數傳遞,就可以去掉<row>標簽,結果:2014/01/062014/01/07。
現在兩條結果之間很難區分,需要用下划線將其分隔開來,方法是在CONVERT函數前面加上一個下划線:
SELECT '_'+CONVERT(VARCHAR(100), LOGDATE, 111) FROM T_FUN_LOGBOOK WHERE TASKID=231 FOR XML PATH('')
結果:_2014/01/06_2014/01/07。
在分析了FOR XML PATH語句之后,就來將這個查詢結果添加到對T_FUN_TASk的查詢結果中去。我的思路是先構建一個子查詢,然后查詢TASK表時LEFT JOIN這個子查詢:
SELECT T1.TASKID,'TASKNAME' AS TASKNAME,T2.LOGDATES FROM T_FUN_TASK T1 LEFT JOIN (SELECT TASKID, LOGDATES=(SELECT '_'+CONVERT(VARCHAR(100), LOGDATE, 111) FROM T_FUN_LOGBOOK WHERE TASKID=T1.TASKID FOR XML PATH('')) FROM T_FUN_LOGBOOK T1 GROUP BY TASKID) T2 ON T2.TASKID=T1.TASKID ORDER BY T1.TASKID ASC
運行以上SQL后得到的結果為:
發現LOGDATES值的第一個下划線應該去掉,於是修改SQL,應用 STUFF函數去掉第一個下划線:
SELECT T1.TASKID,'TASKNAME' AS TASKNAME,T2.LOGDATES FROM T_FUN_TASK T1 LEFT JOIN (SELECT TASKID, LOGDATES=STUFF((SELECT '_'+CONVERT(VARCHAR(100), LOGDATE, 111) FROM T_FUN_LOGBOOK WHERE TASKID=T1.TASKID FOR XML PATH('')),1,1,'') FROM T_FUN_LOGBOOK T1 GROUP BY TASKID) T2 ON T2.TASKID=T1.TASKID ORDER BY T1.TASKID ASC
將結果轉化為JSON 返回給前端之后,JS按照下划線分隔這個字段的值,即可以得到一個任務下面日志的填寫情況。