使用 SQL 查询合并三个表并获得一个输出

Posted

技术标签:

【中文标题】使用 SQL 查询合并三个表并获得一个输出【英文标题】:Merge Three Tables and get one output using SQL query 【发布时间】:2020-03-26 18:31:47 【问题描述】:

我有以下候选表详细信息

Table_TraineeInfo

TraineeID     BatchId     Name           Mobile
--------------------------------------------------
243             45      demo201        9888562341
244             45      demo202        9888562342
246             45      demo204        9888562344

这是我的上述候选人的批次详细信息,在两个公用表中都有参考 id 45

Table_Batch_Lookup

 BatchId           BatchStartDate                 BatchEndDate
------------------------------------------------------------------------
  45             2019-11-27 00:00:00.000        2019-11-29 23:59:59.000

下面是我的Trainee出勤日志表,Table_TraineeInfo和Table_Attendance_Log之间的共同点是TraineeID

Table_Attendance_Log

TraineeID    BatchId    Attendance       Date      
------------------------------------------------------------
243           45        Present     2019-11-27 17:55:56.513 
243           45        Present     2019-11-28 17:58:06.220 
243           45        Absent      2019-11-29 18:00:56.820 
244           45        Present     2019-11-29 18:05:03.930 
246           45        Absent      2019-11-28 18:09:08.567 
246           45        Present     2019-11-29 18:09:08.567

我想要像下面这样的输出合并三个表,并使用 SQL 查询或可能的方式将一个输出作为批处理候选人出勤报告。

TraineeID    BatchId    Name             Mobile               2019-11-27          2019-11-28          2019-11-29       Score     
-----------------------------------------------------------------------------------------------------------------------------
  243           45      demo201          9888562341            Present             Present             Absent           3/2
  244           45      demo202          9888562342            No Record           No Record           Present          3/1
  246           45      demo204          9888562344            No Record           Absent              Present          3/1

我将解释上面的输出前四列将使用 Table_TraineeInfo 填充,接下来的数据将根据 Table_Batch_Lookup 中的 BatchStartDate 和 BatchEndDate 填充 出席和缺席将根据Table_Attendance_Log 出席者列表中没有可用的数据然后不填写任何记录,最后得分Present 将为1 值,满3 天。

【问题讨论】:

那么问题出在哪里?您肯定已经尝试过一些未能产生您需要的查询。 我没有得到实现输出的逻辑。 @MarkusDeibel 你需要动态 PIVOT 来实现你的输出。 问题与合并无关。我相信你已经习惯了简单的内部连接。您的问题是将日期值“旋转”到列中。我建议从 ***.com/questions/13372276/… 开始。 是的,任何与我的输出相关的样本或任何查询。 @mkRabbani 【参考方案1】:

我不确定它有多接近解决方案,但您可能需要动态枢轴。

请尝试以下:

CREATE TABLE Table_TraineeInfo (TraineeID  int,BatchId int,Name varchar(max),Mobile varchar(10))
INSERT INTO Table_TraineeInfo VALUES(243,             45  ,    'demo201' ,        '9888562341')
INSERT INTO Table_TraineeInfo VALUES(244,             45  ,    'demo202' ,        '9888562342')
INSERT INTO Table_TraineeInfo VALUES(246,             45  ,    'demo204' ,        '9888562344')

CREATE TABLE Table_Attendance_Log (TraineeID INT,   BatchId INT,   Attendance VARCHAR(10)  ,   l_date DATETIME)    
INSERT INTO Table_Attendance_Log VALUES (243,           45  ,      'Present'     ,'2019-11-27 17:55:56.513') 
INSERT INTO Table_Attendance_Log VALUES (243,           45  ,      'Present'     ,'2019-11-28 17:58:06.220') 
INSERT INTO Table_Attendance_Log VALUES (243,           45  ,      'Absent'      ,'2019-11-29 18:00:56.820') 
INSERT INTO Table_Attendance_Log VALUES (244,           45  ,      'Present'     ,'2019-11-29 18:05:03.930') 
INSERT INTO Table_Attendance_Log VALUES (246,           45  ,      'Absent'      ,'2019-11-28 18:09:08.567') 
INSERT INTO Table_Attendance_Log VALUES (246,           45  ,      'Present'     ,'2019-11-29 18:09:08.567')

CREATE TABLE Table_Batch_Lookup (BatchId   int    ,    BatchStartDate     DATETIME       ,     BatchEndDate DATETIME)
INSERT INTO Table_Batch_Lookup VALUES( 45  ,           '2019-11-27 00:00:00.000',        '2019-11-29 23:59:59.000')

日期CTE

Declare @cols NVARCHAR(Max)='';
;With log_date AS (
SELECT BatchStartDate as l_date FROM Table_Batch_Lookup
UNION ALL
SELECT DATEADD(dd, 1, l_date)  FROM log_date AS ld , Table_Batch_Lookup AS tb  WHERE ld.l_date<DATEADD(dd, -1, tb.BatchEndDate)
)
SELECT @cols = COALESCE (@cols + ',[' + CONVERT(NVARCHAR,CONVERT(VARCHAR(10), l_Date, 111), 106) + ']','[' + CONVERT(NVARCHAR, l_Date, 106) + ']') FROM (SELECT DISTINCT CONVERT(VARCHAR(10), l_Date, 111) AS l_date FROM log_date) PV;

动态Pivot

Declare @totalScore INT =len(@cols) - len(replace(@cols, ',', ''))
CREATE TABLE #scoreTable (TraineeID int,Score Varchar(max))
INSERT INTO #scoreTable SELECT TraineeID,(CAST (@totalScore AS VARCHAR(10)) +'/'+CAST (SUM(CASE WHEN Attendance='Present' THEN 1 ELSE 0 END) AS VARCHAR(10)))AS Score from Table_Attendance_Log GROUP BY TraineeID;
--SELECT * from #scoreTable
DECLARE @query NVARCHAR(MAX); 
SET @query = 'SELECT t_info.TraineeID,t_batch.BatchId,t_info.Name,t_info.Mobile'+@cols+' ,s.Score FROM  Table_TraineeInfo AS t_info  JOIN       
              (SELECT * FROM 
             (
                 SELECT TraineeID,BatchId,Attendance,CONVERT(VARCHAR(10), l_Date, 111) AS l_date FROM Table_Attendance_Log
             ) x
             PIVOT 
             (
                 MAX(Attendance)
                 FOR l_Date IN (' + right(@cols, len(@cols)-1)+ ')
            ) p ) AS f_pv ON t_info.TraineeID=f_pv.TraineeID 
            JOIN Table_Batch_Lookup as t_batch ON t_batch.BatchId=t_info.BatchId
            JOIN #scoreTable AS s ON t_info.TraineeID=s.TraineeID
            WHERE t_batch.BatchId=45;
            ' ;    
EXEC SP_EXECUTESQL @query;

输出:



TraineeID   BatchId   Name       Mobile    2019/11/27   2019/11/28  2019/11/29  Score
    243         45   demo201    9888562341  Present     Present       Absent    3/2
    244         45   demo202    9888562342                            Present   3/1
    246         45   demo204    9888562344               Absent       Present   3/1

Demo

【讨论】:

批处理开始日期和批处理结束日期应该来自这个表Table_Batch_Lookup,你错过了一个表批处理查找表。 @FrustratedDeveloper 请编辑并更新您即将回答的答案。 @FrustratedDeveloper 我认为这行代码你必须从 table_batch_lookup 中带来日期:不要从日志表中带来日期 SELECT @cols = COALESCE (@cols + ',[' + CONVERT(NVARCHAR,CONVERT(VARCHAR( 10), l_Date, 111), 106) + ']','[' + CONVERT(NVARCHAR, l_Date, 106) + ']') FROM (SELECT DISTINCT CONVERT(VARCHAR(10), l_Date, 111) 作为 l_date FROM Table_Attendance_Log) PV 如果你想要table_batch_lookup 的日期,那么你可能需要CTELOOP 据我所知 no 没有某个时间一个用户可用,基于批处理开始日期和 BatchEnddate cols 值应该填写。 @FrustratedDeveloper【参考方案2】:

不可能创建一个具有不同列数和列的查询 名字。

解决方法是为dynamic SQL query 形成创建一个脚本。或者我可以用名为[day1],[day2],...,[dayN]...的列编写查询

如果BatchEndDate and BatchStartDate 之间总是相同的day's count

【讨论】:

去掉分数栏,去掉分数栏后可以得到吗? @Смирнов Евгений

以上是关于使用 SQL 查询合并三个表并获得一个输出的主要内容,如果未能解决你的问题,请参考以下文章

我们如何通过自定义消息和计数获得 MS Sql 查询的输出?

在 SQL 中将行显示为列

MySQL JOIN 2 个表并分别获取两个表的总和

SQL - 如何避免将三个查询合并为一个

跨表的 SQL VALUES 和 MAX

在 vue.js 客户端合并来自不同 graphql 解析器的数据以进行简单输出