如何按日期范围分组没有UNION

时间:2018-03-26 22:41:41

标签: sql sql-server tsql range union

我有这个T-SQL查询(SQL2012),之前定义了@START@END

DECLARE @WEEK SMALLINT
SET @WEEK = 7

WHILE @WEEK >= 0
BEGIN  

    SELECT @START= (SELECT DATEADD( wk, -1, @START ) ) 
    SELECT @END  = (SELECT DATEADD( wk, -1, @END   ) ) 

    SELECT
        Visits.idPatient,
        Visits.VDay,
        tblScheduledOrder.SDay
    FROM
        tblScheduledOrder
        LEFT OUTER JOIN
        (
            SELECT
                DATEPART( dw, VDate ) - 1 AS VDay,
                idPatient
            FROM
                tblVisits
            WHERE
                ( VDate >= @START ) AND
                ( VDate <= @END )
        ) AS Visits
            ON tblScheduledOrder.idPatient = Visits.idPatient 

    SELECT @WEEK = @WEEK - 1
END  

患者的“预定访问”有一个表格(患者时间表是每周一次,即访问应该在每个星期一进行)。 tblScheduledVisit由2个字段(tblScheduledOrder.idPatienttblScheduledOrder.SDay)组成。

实际访问次数存储在tblVisits,其中包含(tblVisits.VDatetblVisits.idPatient

我需要提供患者过去8周的清单,以及他们预定日期和实际日期之间的关系。

正如你所看到的,我做了几个选择然后我在应用程序中建立一个联合,这不是正确的方法,对吗?

--tblScheduledOrder--   ----tblVisits--------
|SDay   idPatient   |   |idPatient   VDate  | DATEPART(dw)
| 1       11        |   |11    #2018-3-18#  | 1
| 2       12        |   |12    #2018-3-19#  | 2
| 2       13        |   |13    #2018-3-20#  | 3
| 3       14        |   |14    #2018-3-20#  | 3
| 4       15        |   |15    #2018-3-21#  | 4
| 4       16        |   |16    #2018-3-22#  | 5
---------------------   |11    #2018-3-25#  | 1
                        |12    #2018-3-26#  | 2
                        |13    #2018-3-27#  | 3
                        |15    #2018-3-29#  | 5
                        |16    #2018-3-29#  | 5
                        ---------------------

实际结果

--First resultset-----
|idPati SDay    VDay |
|11     1       1    |
|12     2       2    |
|13     2       3    |
|14     3       3    |
|15     4       4    |
|16     4       5    |
--Second resulset-----
|11     1       1    |
|12     2       2    |
|13     2       3    |
|14     3       NULL |
|15     4       5    |
|16     4       5    |
----------------------

必填结果

--Single resultset-----
|idPati SDay    VDay |
|11     1       1    |
|12     2       2    |
|13     2       3    |
|14     3       3    |
|15     4       4    |
|16     4       5    |
|11     1       1    |
|12     2       2    |
|13     2       3    |
|14     3       NULL |
|15     4       5    |
|16     4       5    |
----------------------

3 个答案:

答案 0 :(得分:0)

我尝试了一个解决方案,但无法将我的结果与问题进行协调并停止。也许其他人可以更进一步。请参阅此SQL Fiddle

CREATE TABLE tblScheduledOrder
    (SDay int, idPatient int)
;

INSERT INTO tblScheduledOrder
    (SDay, idPatient)
VALUES
    (1, 11),
    (2, 12),
    (2, 13),
    (3, 14),
    (4, 15),
    (4, 16)
;


CREATE TABLE tblVisits
    (idPatient int, VDate date)
;

INSERT INTO tblVisits
    (idPatient, VDate)
VALUES
    (11, '2018-03-18'),
    (12, '2018-03-19'),
    (13, '2018-03-20'),
    (14, '2018-03-20'),
    (15, '2018-03-21'),
    (16, '2018-03-22'),
    (11, '2018-03-25'),
    (12, '2018-03-26'),
    (13, '2018-03-27'),
    (15, '2018-03-29'),
    (16, '2018-03-29')
;

查询1

declare @end as date
-- calculate "next" Monday
set @end = dateadd(d,-(datediff(d,0,getdate()) % 7)+7 ,cast(getdate() as date))
declare @start as date
set @start = dateadd(wk,-8,@end)
;with drange as (
  select @start as dt, datepart(dw,@start) dw
  union all
  select dateadd(d,1,dt) , datepart(dw,dateadd(d,1,dt))
  from drange
  where dateadd(d,1,dt) <= @end
  )
, p as (
  select 
         SDay
       , idPatient
       , dateadd(d,SDay-1,dateadd(d,-datediff(d,0,getdate()) % 7,cast(getdate() as date))) Ndate
  from tblScheduledOrder
  )  
select 
     dt, dw, p.Sday, vdate, ndate, coalesce(v.idpatient,p.idPatient) idpatient
from drange
left join tblVisits v on drange.dt = v.Vdate
left join p on drange.dt = p.Ndate
where drange.dw between 1 and 5
order by dt DESC, coalesce(v.idpatient,p.idPatient)

<强> Results

|         dt | dw |   Sday |      vdate |      ndate | idpatient |
|------------|----|--------|------------|------------|-----------|
| 2018-04-02 |  2 | (null) |     (null) |     (null) |    (null) |
| 2018-04-01 |  1 | (null) |     (null) |     (null) |    (null) |
| 2018-03-29 |  5 |      4 | 2018-03-29 | 2018-03-29 |        15 |
| 2018-03-29 |  5 |      4 | 2018-03-29 | 2018-03-29 |        15 |
| 2018-03-29 |  5 |      4 | 2018-03-29 | 2018-03-29 |        16 |
| 2018-03-29 |  5 |      4 | 2018-03-29 | 2018-03-29 |        16 |
| 2018-03-28 |  4 |      3 |     (null) | 2018-03-28 |        14 |
| 2018-03-27 |  3 |      2 | 2018-03-27 | 2018-03-27 |        13 |
| 2018-03-27 |  3 |      2 | 2018-03-27 | 2018-03-27 |        13 |
| 2018-03-26 |  2 |      1 | 2018-03-26 | 2018-03-26 |        12 |
| 2018-03-25 |  1 | (null) | 2018-03-25 |     (null) |        11 |
| 2018-03-22 |  5 | (null) | 2018-03-22 |     (null) |        16 |
| 2018-03-21 |  4 | (null) | 2018-03-21 |     (null) |        15 |
| 2018-03-20 |  3 | (null) | 2018-03-20 |     (null) |        13 |
| 2018-03-20 |  3 | (null) | 2018-03-20 |     (null) |        14 |
| 2018-03-19 |  2 | (null) | 2018-03-19 |     (null) |        12 |
| 2018-03-18 |  1 | (null) | 2018-03-18 |     (null) |        11 |
| 2018-03-15 |  5 | (null) |     (null) |     (null) |    (null) |
| 2018-03-14 |  4 | (null) |     (null) |     (null) |    (null) |
| 2018-03-13 |  3 | (null) |     (null) |     (null) |    (null) |
| 2018-03-12 |  2 | (null) |     (null) |     (null) |    (null) |
| 2018-03-11 |  1 | (null) |     (null) |     (null) |    (null) |
| 2018-03-08 |  5 | (null) |     (null) |     (null) |    (null) |
| 2018-03-07 |  4 | (null) |     (null) |     (null) |    (null) |
| 2018-03-06 |  3 | (null) |     (null) |     (null) |    (null) |
| 2018-03-05 |  2 | (null) |     (null) |     (null) |    (null) |
| 2018-03-04 |  1 | (null) |     (null) |     (null) |    (null) |
| 2018-03-01 |  5 | (null) |     (null) |     (null) |    (null) |
| 2018-02-28 |  4 | (null) |     (null) |     (null) |    (null) |
| 2018-02-27 |  3 | (null) |     (null) |     (null) |    (null) |
| 2018-02-26 |  2 | (null) |     (null) |     (null) |    (null) |
| 2018-02-25 |  1 | (null) |     (null) |     (null) |    (null) |
| 2018-02-22 |  5 | (null) |     (null) |     (null) |    (null) |
| 2018-02-21 |  4 | (null) |     (null) |     (null) |    (null) |
| 2018-02-20 |  3 | (null) |     (null) |     (null) |    (null) |
| 2018-02-19 |  2 | (null) |     (null) |     (null) |    (null) |
| 2018-02-18 |  1 | (null) |     (null) |     (null) |    (null) |
| 2018-02-15 |  5 | (null) |     (null) |     (null) |    (null) |
| 2018-02-14 |  4 | (null) |     (null) |     (null) |    (null) |
| 2018-02-13 |  3 | (null) |     (null) |     (null) |    (null) |
| 2018-02-12 |  2 | (null) |     (null) |     (null) |    (null) |
| 2018-02-11 |  1 | (null) |     (null) |     (null) |    (null) |
| 2018-02-08 |  5 | (null) |     (null) |     (null) |    (null) |
| 2018-02-07 |  4 | (null) |     (null) |     (null) |    (null) |
| 2018-02-06 |  3 | (null) |     (null) |     (null) |    (null) |
| 2018-02-05 |  2 | (null) |     (null) |     (null) |    (null) |

答案 1 :(得分:0)

Declare  @StartDate  DateTime  ='20180301' 
Declare  @EndDate  DateTime    ='20180330' 

DECLARE @NotVisitedPatients table ( idPatient Int  ,Sday INT , Vdate Date,Vday int ,WeekNumber INT )
DECLARE @WeekNumber table ( Id Int identity (1,1) ,WeekNumber INT )

INSERT INTO @WeekNumber
SELECT  distinct
DATEPART(Week ,V.[VDate])
FROM [dbo].[tblVisits] V 
inner  join [dbo].[tblScheduledOrder] S  on V.idPatient =  S.idPatient
where V.[VDate] between @StartDate and @EndDate 

declare @Total int = (select Max(Id) from  @WeekNumber)
declare @count  int =1
declare @week  int = 0 

WHILE (@Total >= @count)
BEGIN  
set  @week =(select WeekNumber from @WeekNumber where  id =@count)
print @week
INSERT INTO @NotVisitedPatients
           (idPatient
           ,Sday
           ,Vdate
           ,Vday
           ,WeekNumber)
select distinct  S.idPatient ,S.Sday ,null,null, @week from tblScheduledOrder S
where  S.idPatient  not in (select V.idPatient   from tblVisits V  
where DATEPART(Week ,V.[VDate]) = @week)
set @count =@count +1 
END

select  idPatient   ,Sday , Vdate,Vday  ,WeekNumber  from @NotVisitedPatients
Union 
SELECT  distinct S.idPatient
       ,S.Sday  
       ,V.[VDate]      
      , DATEPART(DW ,V.[VDate]) As VDay    
      , DATEPART(Week ,V.[VDate]) As WeekNumber
  FROM [dbo].[tblVisits] V 
  inner  join [dbo].[tblScheduledOrder] S  on V.idPatient =  S.idPatient
where V.[VDate] between @StartDate and @EndDate 

答案 2 :(得分:0)

问题是如何将这一切都集成到一个结果集中,不是吗?而不是使用应用程序,使用临时表来存储循环结果。然后让应用程序从临时表中获取它的数据。 (您可以使用常规表或#TempTable。您只需要一个位置来停放中间数据集。)

DECLARE @tblPlaceHolder TABLE (
  idPatient BIGINT,
  VDay TINYINT,
  SDay TINYINT,
  Week SMALLINT);

<Your existing loop code except add this:  >
  INSERT INTO @tblPlaceHolder (
    idPatient,
    VDay,
    SDay,
    Week)
  SELECT
    Visits.idPatient,
    Visits.VDay,
    tblScheduledOrder.SDay,
    @WEEK AS Week    --<-------Addition to SELECT
  FROM
    tblScheduledOrder
    LEFT OUTER JOIN....

<The rest of your loop code>

    SELECT @WEEK = @WEEK - 1
END  

SELECT 
  idPatient,
  SDay,
  VDay
FROM 
  @tblPlaceHolder
ORDER BY
  Week DESC, --Not needed in the result set. Just to sort by.
  SDay,
  idPatient;