如何在TSQL中将行转换为列?

时间:2017-10-13 15:27:06

标签: sql-server tsql

脚本(如下所列)给出结果(见截图01)Screenshot 01 但结果需要显示为(见screenshot02)Screenshot02

work_date中的日期(参见屏幕截图01)需要显示为单独的日期列,work_hour中的小时数(见截图01)需要显示在单个日期列下。

DECLARE @01_STARTDATE VARCHAR(100);
DECLARE @02_ENDDATE VARCHAR(100);
DECLARE @STAFF INT;

SET @01_STARTDATE = '2017-07-06';
SET @02_ENDDATE = '2017-07-10';
SET @STAFF = 8;

SELECT   
    @01_STARTDATE + ' - ' + @02_ENDDATE AS [Date Range],
    SU.FIRST_NAME + ' ' + SU.LAST_NAME AS Staff,
    f.FACILITY_NAME AS Site_Name,
    P.PRJ_PROJECT_NAME AS Project_Name,
    R.PROJECT_TYPE_NAME AS Project_Type_Brownfield,
    '' AS Project_Type_VRP,
    st.work_hour, st.work_date
FROM 
    FAC_FACILITY AS f
INNER JOIN 
    GOV.PRJ_PROJECT AS P ON f.FACILITY_RID = p.FACILITY_RID
INNER JOIN 
    GOV.SYS_TIME_LOG AS ST ON ST.PRJ_PROJECT_RID = P.PRJ_PROJECT_RID
LEFT JOIN 
    SEC_USER AS SU ON SU.USER_RID = ST.USER_RID
LEFT JOIN 
    GOV.REF_PROJECT_TYPE AS R ON P.PROJECT_TYPE_RID = R.PROJECT_TYPE_RID
WHERE 
    ST.WORK_DATE BETWEEN CAST(@01_STARTDATE AS DATE) AND CAST(@02_ENDDATE AS DATE)
    AND ST.USER_RID = @STAFF        
    AND R.PROJECT_TYPE_RID = 3
GROUP BY 
    f.FACILITY_NAME, P.PRJ_PROJECT_NAME, SU.FIRST_NAME,
    st.work_date, SU.LAST_NAME, R.PROJECT_TYPE_NAME,
    st.work_hour

UNION ALL

SELECT   
    @01_STARTDATE + ' - ' + @02_ENDDATE AS [Date Range],
    SU.FIRST_NAME + ' ' + SU.LAST_NAME AS Staff,
    f.FACILITY_NAME AS Site_Name,
    P.PRJ_PROJECT_NAME AS Project_Name,
    '' AS Project_Type_Brownfield,
    R.PROJECT_TYPE_NAME AS Project_Type_VRP,
    st.work_hour, st.work_date
FROM
    FAC_FACILITY AS f
INNER JOIN 
    GOV.PRJ_PROJECT AS P ON f.FACILITY_RID = p.FACILITY_RID
INNER JOIN 
    GOV.SYS_TIME_LOG AS ST ON ST.PRJ_PROJECT_RID = P.PRJ_PROJECT_RID
LEFT JOIN 
    SEC_USER AS SU ON SU.USER_RID = ST.USER_RID
LEFT JOIN 
    GOV.REF_PROJECT_TYPE AS R ON P.PROJECT_TYPE_RID = R.PROJECT_TYPE_RID
WHERE 
    ST.WORK_DATE BETWEEN CAST(@01_STARTDATE AS DATE) AND CAST(@02_ENDDATE AS DATE)
    AND ST.USER_RID = @STAFF        
    AND R.PROJECT_TYPE_RID = 2
GROUP BY 
    f.FACILITY_NAME, P.PRJ_PROJECT_NAME, SU.FIRST_NAME,
    st.work_date, SU.LAST_NAME, R.PROJECT_TYPE_NAME,
    st.work_hour

UNION ALL

SELECT   
    @01_STARTDATE + ' - ' + @02_ENDDATE AS [Date Range],
    SU.FIRST_NAME + ' ' + SU.LAST_NAME AS Staff,
    g.grant_name AS Site_Name,
    '' AS project_name,
    '' AS Project_Type_Brownfield,
    '' AS Project_Type_VRP,
    st.work_hour, st.work_date
FROM
    (SELECT 
         SUM(work_hour) AS work_hour, user_rid,
         grant_rid, work_date
     FROM  
         GOV.SYS_TIME_LOG
     WHERE 
         WORK_DATE BETWEEN CAST(@01_STARTDATE AS DATE) AND CAST(@02_ENDDATE AS DATE)
         AND USER_RID = @STAFF        
         AND grant_rid = 1
     GROUP BY 
         grant_rid, user_rid, work_date) AS ST
LEFT JOIN 
    SEC_USER AS SU ON SU.USER_RID = ST.USER_RID
LEFT JOIN 
    SYS_GRANT AS G ON st.grant_rid = g.grant_rid
WHERE 
    ST.WORK_DATE BETWEEN CAST(@01_STARTDATE AS DATE) AND CAST(@02_ENDDATE AS DATE)
    AND ST.USER_RID = @STAFF        
    AND st.grant_rid = 1
GROUP BY 
    SU.FIRST_NAME, st.work_date, SU.LAST_NAME,
    G.Grant_name, st.work_hour;

1 个答案:

答案 0 :(得分:0)

有很多关于如何" 支持"输出,如你的第一个图像看起来像第二个。另外,因为您需要通过参数更改日期范围,所以需要采用" 动态sql "生成" 动态列名称"。

请注意,您不需要运行3个单独的查询来收集所需的信息,但是您应该等到查询的最后一刻以禁止输出值。理想情况下,您根本不会使用SQL执行此操作,但会在"表示层"中执行此操作。 (此查询看起来像是为报表设计的,大多数报表产品都支持数据的条件输出。)

如果你在select和group by子句中包含PROJECT_TYPE_RID,你可以使用像这样的case表达式来控制输出,它只是你的查询很多,并且使得一个数据集更容易实现:

    case when R.PROJECT_TYPE_RID = 1 then '' else Project_Name end  AS Project_Name,
    case when R.PROJECT_TYPE_RID = 3 then R.PROJECT_TYPE_NAME else '' end AS Project_Type_Brownfield,
    case when R.PROJECT_TYPE_RID = 2 then R.PROJECT_TYPE_NAME else '' end AS Project_Type_VRP,

但请注意,因为您想要使用PIVOT,所以在执行此轴之后,您将无法执行此类抑制这样的值。