Счетчик SQL по каждой дате с несколькими полями даты - PullRequest
0 голосов
/ 18 декабря 2018

У меня есть следующая таблица и запрос, который не дает правильного результата.

В таблице JOB есть даты открытия, завершения и закрытия.

Теперь мне нужно получить счетчик Open,Завершенные и закрытые задания между выбранной группой дат по каждой дате и местоположению.

Пожалуйста, помогите мне получить результат, как показано в приведенном ниже ожидаемом результате

+-------+-----------+------------+-----------+----------+
| JOB_id| DateOpen  | DateFinish | DateClose | Location |
+-------+-----------+------------+-----------+----------+
|   100 | 16-Dec-18 | 18-Dec-18  | 19-Dec-18 | A        |
|   101 | 16-Dec-18 | 18-Dec-18  | 19-Dec-18 | A        |
|   102 | 17-Dec-18 | 19-Dec-18  | 20-Dec-18 | C        |
|   103 | 10-Dec-18 | 11-Dec-18  | 16-Dec-18 | D        |
|   104 | 17-Dec-18 | 19-Dec-18  | 18-Dec-18 | E        |
+-------+-----------+------------+-----------+----------+

Запрос:

SELECT count(DateOpen) as Opened,
       count(DateFinish) as Finised,
      count(DateClose) as Closed,
      (DateOpen) as Date 
FROM JOBS
WHERE DateOpen BETWEEN '12/16/2018' AND DATEADD(DAY, 1, '12/17/2018')
group by DateOpen

Ожидаемый результат:

+-----------+------+----------+--------+----------+
|   Date    | Open | Finished | Closed | Location |
+-----------+------+----------+--------+----------+
| 16-Dec-18 |    2 |        0 |      0 | A        |
| 16-Dec-18 |    0 |        0 |      1 | D        |
| 17-Dec-18 |    1 |        0 |      0 | C        |
| 17-Dec-18 |    1 |        0 |      0 | E        |
+-----------+------+----------+--------+----------+

Ответы [ 9 ]

0 голосов
/ 18 декабря 2018

Попробуйте это:

    DECLARE @MinDate DATE = '12/16/2018',
            @MaxDate DATE = '12/17/2018'


    DECLARE @DateTable TABLE (DateOpen DATETIME)

    INSERT INTO @DateTable
    SELECT  TOP (DATEDIFF(DAY, @MinDate, @MaxDate) + 1)
            Date = DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, @MinDate)
    FROM    sys.all_objects a
            CROSS JOIN sys.all_objects b;

    ;with cte
    As
    (
        SELECT DISTINCT d.DateOpen, 
        SUM(CASE WHEN j.DateOpen =d.DateOpen THEN 1 ELSE 0 END) OVER(partition by d.DateOpen,Location) As [Open]
        ,SUM(CASE WHEN j.DateFinish =d.DateOpen THEN 1 ELSE 0 END) OVER(partition by d.DateOpen,Location) As [Finished]
        ,SUM(CASE WHEN j.DateClose =d.DateOpen THEN 1 ELSE 0 END) OVER(partition by d.DateOpen,Location) As [Closed]
        ,Location
        FROM @DateTable d
        CROSS JOIN JOBS j   
    )

    Select * from cte where [Open]>0 or Finished>0 or Closed>0
    Order by DateOpen,Location
0 голосов
/ 18 декабря 2018

Попробуйте это

WITH CTE AS
(
SELECT *
FROM
(
SELECT Location
FROM T
GROUP BY Location
) L CROSS APPLY
(
  SELECT DateOpen
  FROM T
  WHERE DateOpen BETWEEN '2018-12-16' AND '2018-12-18'
) D
GROUP BY Location, DateOpen
),
 F AS
(
SELECT *,
       (SELECT COUNT(1) FROM T WHERE Location = CTE.Location AND DateOpen = CTE.DateOpen) [Open],
       (SELECT COUNT(1) FROM T WHERE Location = CTE.Location AND DateFinish = CTE.DateOpen)[Finish],
       (SELECT COUNT(1) FROM T WHERE Location = CTE.Location AND DateClose = CTE.DateOpen) [Close]
FROM CTE
)
SELECT DateOpen,
       [Open],
       [Finish],
       [Close],
       Location
FROM F
WHERE [Open] > 0
      OR
      [Finish] > 0
      OR
      [Close] > 0
ORDER BY DateOpen

Возвращает:

+---------------------+------+--------+-------+----------+
|      DateOpen       | Open | Finish | Close | Location |
+---------------------+------+--------+-------+----------+
| 16/12/2018 00:00:00 |    2 |      0 |     0 | A        |
| 16/12/2018 00:00:00 |    0 |      0 |     1 | D        |
| 17/12/2018 00:00:00 |    1 |      0 |     0 | C        |
| 17/12/2018 00:00:00 |    1 |      0 |     0 | E        |
+---------------------+------+--------+-------+----------+

Демо

0 голосов
/ 18 декабря 2018

Вы можете вытащить все даты открытия, окончания и закрытия в одном столбце, а затем присоединиться к своей таблице вакансий с помощью:

DECLARE @date1 AS DATE = '2018-12-16';
DECLARE @date2 AS DATE = '2018-12-17';

WITH dates(date) AS (
    SELECT DateOpen FROM jobs
    UNION
    SELECT DateFinish FROM jobs
    UNION
    SELECT DateClose FROM jobs
)
SELECT dates.date
     , Location
     , COUNT(CASE WHEN dates.date = DateOpen THEN 1 END) AS Opened
     , COUNT(CASE WHEN dates.date = DateFinish THEN 1 END) AS Finished
     , COUNT(CASE WHEN dates.date = DateClose THEN 1 END) AS Closed
FROM dates
LEFT JOIN jobs ON dates.date IN (DateOpen, DateFinish, DateClose)
WHERE dates.date BETWEEN @date1 AND @date2
GROUP BY dates.date
       , Location

Результат:

| date       | Location | Opened | Finished | Closed |
|------------|----------|--------|----------|--------|
| 16/12/2018 | A        | 2      | 0        | 0      |
| 16/12/2018 | D        | 0      | 0        | 1      |
| 17/12/2018 | C        | 1      | 0        | 0      |
| 17/12/2018 | E        | 1      | 0        | 0      |

Демона БД Fiddle

0 голосов
/ 18 декабря 2018

Вы можете попробовать, используя unpivot, посмотреть, как производительность

with cols_to_rows
  as (
      select *
        from t
      unpivot(col for val in (dateopen,datefinish,dateclose))m 
      )
select col
       ,location 
       ,count(case when val='dateopen' then 1 end)   as open1
       ,count(case when val='datefinish' then 1 end) as finish
       ,count(case when val='dateclose' then 1 end)  as close1
  from cols_to_rows
where col between cast('2018-12-16' as date)
  and cast('2018-12-17' as date)
group by col,location,val
order by col,location


| 10/12/2018 00:00:00 | D | 1 | 0 | 0 |
| 11/12/2018 00:00:00 | D | 0 | 1 | 0 |
| 16/12/2018 00:00:00 | A | 2 | 0 | 0 |
| 16/12/2018 00:00:00 | D | 0 | 0 | 1 |
| 17/12/2018 00:00:00 | C | 1 | 0 | 0 |
| 17/12/2018 00:00:00 | E | 1 | 0 | 0 |
| 18/12/2018 00:00:00 | A | 0 | 2 | 0 |
| 18/12/2018 00:00:00 | E | 0 | 0 | 1 |
| 19/12/2018 00:00:00 | A | 0 | 0 | 2 |
| 19/12/2018 00:00:00 | C | 0 | 1 | 0 |
| 19/12/2018 00:00:00 | E | 0 | 1 | 0 |
| 20/12/2018 00:00:00 | C | 0 | 0 | 1 |

Вот ссылка на dbfiddle

https://dbfiddle.uk/?rdbms=sqlserver_2012&fiddle=1ca0c0180a4d31d6e112e9f3b1b99715

0 голосов
/ 18 декабря 2018
DECLARE @startDate DATETIME = '12/16/2018'
DECLARE @endDate DATETIME = '12/17/2018'

SELECT 
  count(CASE when DateOpen BETWEEN @startDate AND @endDate THEN 1 end) as Opened,
  count(CASE when DateFinish BETWEEN @startDate AND @endDate THEN 1 end) as Finised,
  count(CASE when DateClose BETWEEN @startDate AND @endDate THEN 1 end) as Closed,
  DateOpen as Date,
  Location
FROM JOBS
WHERE DateOpen BETWEEN @startDate AND @endDate
group by DateOpen, Location
0 голосов
/ 18 декабря 2018

Вы можете попробовать следующий код, используя функцию SUM, которая суммирует состояние процессов на введенные даты:

SELECT Convert(date1,DateOpen) as Date,
       sum(case
            when DateOpen = Convert(date1,DateOpen) then 1
            else 0
           end) as Open,
       sum(case
            when DateFinish = Convert(date1,DateOpen) then 1
            else 0
           end) as Finished,
      sum(case
            when DateClose = Convert(date1,DateOpen) then 1
            else 0
           end) as Closed,
      Location
FROM JOBS
group by Location
UNION ALL  
SELECT Convert(date2,DateOpen) as Date,
       sum(case
            when DateOpen = Convert(date2,DateOpen) then 1
            else 0
           end) as Open,
       sum(case
            when DateFinish = Convert(date2,DateOpen) then 1
            else 0
           end) as Finished,
      sum(case
            when DateClose = Convert(date2,DateOpen) then 1
            else 0
           end) as Closed,
      Location
FROM JOBS
group by Location;

EDITED: date1 и date2 являются входными параметрами.

0 голосов
/ 18 декабря 2018

Вы можете использовать оператор case с суммой,

    SELECT  Convert(date,DateOpen) as Date ,      
           sum(case when DateOpen =DateOpen then 1 else 0 end) as Opened,
           sum(case when DateFinish=DateOpen then 1 else 0 end) as Finised,
           sum(case when DateClose=DateOpen then 1 else 0 end) as Closed,
           Location

    FROM JOBS
    WHERE DateOpen BETWEEN '12/16/2018' AND DATEADD(DAY, 1, '12/17/2018')
    group by Convert(date,DateOpen),Location

    UNION

    SELECT  Convert(date,DateClose) as Date ,      
           sum(case when DateOpen =DateClose then 1 else 0 end) as Opened,
           sum(case when DateFinish=DateClose then 1 else 0 end) as Finised,
           sum(case when DateClose=DateClose then 1 else 0 end) as Closed,
           Location

    FROM JOBS
    WHERE DateClose BETWEEN '12/16/2018' AND DATEADD(DAY, 1, '12/16/2018')
    group by Convert(date,DateClose),Location
0 голосов
/ 18 декабря 2018

Во-первых, я бы порекомендовал вам прекратить хранить даты в виде текста и использовать правильные типы данных.

Чтобы сделать то, что вам нужно, составьте список всех дат и местоположений, выбрав каждый из столбцов дат и местоположенияи объединить их в один результат (первый cte - allDates).Затем нам нужен отдельный список (второй cte - агрегированный) для выбора и подсчета количества строк в вашей таблице, которые соответствуют текущим значениям даты / местоположения.

Вот полное решение:

declare @JOBS table(JOB_ID int, DateOpen varchar(10), DateFinish varchar(10), DateClose varchar(10), Location varchar(5))
insert into @JOBS values
(   100, '16-Dec-18', '18-Dec-18', '19-Dec-18', 'A'),
(   101, '16-Dec-18', '18-Dec-18', '19-Dec-18', 'A'),
(   102, '17-Dec-18', '19-Dec-18', '20-Dec-18', 'C'),
(   103, '10-Dec-18', '11-Dec-18', '16-Dec-18', 'D'),
(   104, '17-Dec-18', '19-Dec-18', '18-Dec-18', 'E')

;with allDates as (
select convert(date, DateOpen) as [Date], Location from @JOBS
union
select convert(date, DateFinish), Location from @JOBS
union
select convert(date, DateClose), Location from @JOBS
),
aggregated as (
    select [Date], Location
    from allDates
    group by [Date], Location
)
select
    a.Date
    , (select count(*) from @JOBS where a.[Date] = DateOpen and a.Location = Location) [Open]
    , (select count(*) from @JOBS where a.[Date] = DateFinish and a.Location = Location) Finished
    , (select count(*) from @JOBS where a.[Date] = DateClose and a.Location = Location) Closed
    , Location
from aggregated a
where a.Date between '20181216' and '20181217'
0 голосов
/ 18 декабря 2018

Вы можете использовать следующий запрос для желаемого набора результатов.

select coalesce(t1.date, t2.date, t3.date) as date, t1.Opened, t2.Finished, t3.Closed,
coalesce(t1.location, t2.location, t3.location) as location
from
(SELECT Convert(date,DateOpen) as Date ,count(JobID) as Opened, location      
FROM JOBS
WHERE DateOpen BETWEEN '12/16/2018' AND DATEADD(DAY, 1, '12/17/2018')
group by Convert(date,DateOpen), location 
) t1
Full join 
(SELECT Convert(date,DateFinish) as Date ,count(JobID) as Finished, location      
FROM JOBS
WHERE DateFinish BETWEEN '12/16/2018' AND DATEADD(DAY, 1, '12/17/2018')
group by Convert(date,DateFinish), location 
) t2  ON(t1.date = t2.date and t1.location = t2.location)
FULL JOIN
(SELECT Convert(date,DateClose) as Date ,count(JobID) as Closed, location      
FROM JOBS
WHERE DateClose BETWEEN '12/16/2018' AND DATEADD(DAY, 1, '12/17/2018')
group by Convert(date,DateClose), location 
) t3  ON(t2.date = t3.date and t2.location = t3.location)
...