2012-04-06 35 views
6

Mã dưới đây trả về số lượng vé đã giải quyết và số vé đã mở trong một khoảng thời gian (khoảng thời gian là YYYY, WW) sẽ quay trở lại một số ngày nhất định. Ví dụ: nếu @NoOfDays là 7:Tạo đường xu hướng từ tập dữ liệu SQL

giải quyết | mở | tuần | năm | khoảng thời gian

56 | 30 | 13 | 2012 | 2012, 13

237 | 222 | 14 | 2012 | 2012, 14

'đã giải quyết' và 'mở' được vẽ đồ thị trên đường (y) trong khoảng thời gian (x). Tôi muốn thêm một cột 'xu hướng' khác sẽ trả về một con số mà khi được vẽ theo thời gian, sẽ là một đường xu hướng (hồi quy tuyến tính đơn giản). I do muốn sử dụng cả hai bộ giá trị làm một nguồn dữ liệu cho xu hướng.

Đây là mã tôi có:

SELECT a.resolved, b.opened, a.weekClosed AS week, a.yearClosed AS year, 
    CAST(a.yearClosed as varchar(5)) + ', ' + CAST(a.weekClosed as varchar(5)) AS period 
FROM 
    (SELECT TOP (100) PERCENT COUNT(DISTINCT TicketNbr) AS resolved, { fn WEEK(date_closed) } AS weekClosed, { fn YEAR(date_closed) } AS yearClosed 
    FROM v_rpt_Service 
    WHERE (date_closed >= DateAdd(Day, DateDiff(Day, 0, GetDate()) - @NoOfDays, 0)) 
    GROUP BY { fn WEEK(date_closed) }, { fn YEAR(date_closed) }) AS a 
LEFT OUTER JOIN 
    (SELECT TOP (100) PERCENT COUNT(DISTINCT TicketNbr) AS opened, { fn WEEK(date_entered) } AS weekEntered, { fn YEAR(date_entered) 
    } AS yearEntered 
    FROM v_rpt_Service AS v_rpt_Service_1 
    WHERE  (date_entered > = DateAdd(Day, DateDiff(Day, 0, GetDate()) - @NoOfDays, 0)) 
    GROUP BY { fn WEEK(date_entered) }, { fn YEAR(date_entered) }) AS b ON a.weekClosed = b.weekEntered AND a.yearClosed = b.yearEntered 
ORDER BY year, week 

Edit:

Theo serc.carleton.edu/files/mathyouneed/best_fit_line_dividing.pdf, có vẻ như tôi muốn phá vỡ các dữ liệu trong một nửa, sau đó tính trung bình. Sau đó, tôi cần phải tìm dòng phù hợp nhất, và sử dụng độ dốc và y-đánh chặn để tính toán các giá trị cần thiết để trở lại trong 'xu hướng' sử dụng y = mx + b?

Tôi biết điều này là rất có thể trong SQL, tuy nhiên, chương trình tôi chèn SQL vào có những hạn chế về những gì tôi có thể làm.

Dấu chấm màu đỏ và màu xanh lam là các số tôi đang quay lại (mở và giải quyết). Tôi cần trả về một giá trị cho mỗi giai đoạn trong 'xu hướng' để tạo ra đường màu tím. (Hình ảnh này là giả thuyết)

Hypothetical Chart

+0

Đây có phải là MS SQLServer hoặc cho RDBMS khác không? –

+0

MS SQLServer là chính xác. –

Trả lời

1

I figured it out. Tôi chia dữ liệu thành nhiều bảng dẫn xuất và truy vấn phụ, về cơ bản chia dữ liệu làm đôi. Đây là công thức của tôi để có được mỗi giá trị:

*(each row is a week)* 
y1 = average of data first half 
y2 = average of data second half 
x1 = 1/4 of number of weeks 
x2 = 3/4 of number of weeks 
m = (y1-y2)/(x1-x2) 
b = y2 - (m * x2) 
trend = (m * row_number) + b 

Và đây là mã (rất bẩn) SQL của tôi:

SELECT resolved_half1,resolved_half2,opened_half1,opened_half2, c.period, 
((SUM (resolved_half1) OVER() + SUM(opened_half1) OVER()) - (SUM(resolved_half2) OVER() + SUM(opened_half2) OVER()))/((COUNT(resolved_half1) OVER() + COUNT(opened_half1) OVER())/2) as y1, 
((SUM(resolved_half2) OVER() + SUM(opened_half2) OVER())/(COUNT(resolved_half2) OVER() + COUNT (opened_half2) OVER())) as y2, 
((COUNT(c.period) OVER())/4) as x1, 
(((COUNT(c.period) OVER())/4) * 3) as x2, 
((CAST(((SUM (resolved_half1) OVER() + SUM(opened_half1) OVER()) - (SUM(resolved_half2) OVER() + SUM(opened_half2) OVER()))/((COUNT(resolved_half1) OVER() + COUNT(opened_half1) OVER())/2) as float) - CAST(((SUM(resolved_half2) OVER() + SUM(opened_half2) OVER())/(COUNT(resolved_half2) OVER() + COUNT (opened_half2) OVER())) as float))/(CAST(((COUNT(c.period) OVER())/4) as float) - CAST((((COUNT(c.period) OVER())/4) * 3) as float))) as m, 
(CAST(((SUM(resolved_half2) OVER() + SUM(opened_half2) OVER())/(COUNT(resolved_half2) OVER() + COUNT (opened_half2) OVER())) as float) - (((CAST(((SUM (resolved_half1) OVER() + SUM(opened_half1) OVER()) - (SUM(resolved_half2) OVER() + SUM(opened_half2) OVER()))/((COUNT(resolved_half1) OVER() + COUNT(opened_half1) OVER())/2) as float) - CAST(((SUM(resolved_half2) OVER() + SUM(opened_half2) OVER())/(COUNT(resolved_half2) OVER() + COUNT (opened_half2) OVER())) as float))/(CAST(((COUNT(c.period) OVER())/4) as float) - CAST((((COUNT(c.period) OVER())/4) * 3) as float))) * (((COUNT(c.period) OVER())/4) * 3))) as b, 
((((CAST(((SUM (resolved_half1) OVER() + SUM(opened_half1) OVER()) - (SUM(resolved_half2) OVER() + SUM(opened_half2) OVER()))/((COUNT(resolved_half1) OVER() + COUNT(opened_half1) OVER())/2) as float) - CAST(((SUM(resolved_half2) OVER() + SUM(opened_half2) OVER())/(COUNT(resolved_half2) OVER() + COUNT (opened_half2) OVER())) as float))/(CAST(((COUNT(c.period) OVER())/4) as float) - CAST((((COUNT(c.period) OVER())/4) * 3) as float))) * (ROW_NUMBER() OVER(ORDER BY c.yearClosed,c.weekClosed))) + (CAST(((SUM(resolved_half2) OVER() + SUM(opened_half2) OVER())/(COUNT(resolved_half2) OVER() + COUNT (opened_half2) OVER())) as float) - (((CAST(((SUM (resolved_half1) OVER() + SUM(opened_half1) OVER()) - (SUM(resolved_half2) OVER() + SUM(opened_half2) OVER()))/((COUNT(resolved_half1) OVER() + COUNT(opened_half1) OVER())/2) as float) - CAST(((SUM(resolved_half2) OVER() + SUM(opened_half2) OVER())/(COUNT(resolved_half2) OVER() + COUNT (opened_half2) OVER())) as float))/(CAST(((COUNT(c.period) OVER())/4) as float) - CAST((((COUNT(c.period) OVER())/4) * 3) as float))) * (((COUNT(c.period) OVER())/4) * 3)))) as trend, 
ROW_NUMBER() OVER(ORDER BY c.yearClosed,c.weekClosed) as row 

FROM 
    (SELECT *, CAST(yearClosed as varchar(5)) + ', ' + CAST(weekClosed as varchar(5)) AS period 
    FROM (SELECT  TOP (100) PERCENT COUNT(DISTINCT TicketNbr) AS resolved_half1, { fn WEEK(date_closed) } AS weekClosed, { fn YEAR(date_closed) } AS yearClosed 
          FROM   v_rpt_Service 
     WHERE (date_closed >= DateAdd(Day, DateDiff(Day, 0, GetDate()) - (180), 0)) 

     GROUP BY { fn WEEK(date_closed) }, { fn YEAR(date_closed) }) AS a 
     LEFT OUTER JOIN 
     (SELECT TOP (100) PERCENT COUNT(DISTINCT TicketNbr) AS opened_half1, { fn WEEK(date_entered) } AS weekEntered, { fn YEAR(date_entered) 
     FROM v_rpt_Service AS v_rpt_Service_1 
     WHERE (date_entered > = DateAdd(Day, DateDiff(Day, 0, GetDate()) - (180), 0)) 
     GROUP BY { fn WEEK(date_entered) }, { fn YEAR(date_entered) }) AS b ON a.weekClosed = b.weekEntered AND a.yearClosed = b.yearEntered) as c 
     LEFT OUTER JOIN 
     (SELECT *, CAST(yearClosed as varchar(5)) + ', ' + CAST(weekClosed as varchar(5)) AS period 
     FROM (SELECT TOP (100) PERCENT COUNT(DISTINCT TicketNbr) AS resolved_half2, { fn WEEK(date_closed) } AS weekClosed, { fn YEAR(date_closed) } AS yearClosed 
     FROM v_rpt_Service 
     WHERE (date_closed >= DateAdd(Day, DateDiff(Day, 0, GetDate()) - (180/2), 0)) 
     GROUP BY { fn WEEK(date_closed) }, { fn YEAR(date_closed) }) AS d 
     LEFT OUTER JOIN 
     (SELECT TOP (100) PERCENT COUNT(DISTINCT TicketNbr) AS opened_half2, { fn WEEK(date_entered) } AS weekEntered, { fn YEAR(date_entered)} AS yearEntered 
     FROM v_rpt_Service AS v_rpt_Service_1 
     WHERE (date_entered > = DateAdd(Day, DateDiff(Day, 0, GetDate()) - (180/2), 0)) 
     GROUP BY { fn WEEK(date_entered) }, { fn YEAR(date_entered) }) AS e ON d.weekClosed = e.weekEntered AND d.yearClosed = e.yearEntered 
) as f ON c.yearClosed = f.yearClosed AND c.weekClosed = f.weekClosed AND c.weekEntered = f.weekEntered AND c.yearEntered = f.yearEntered AND c.period = f.period 
GROUP BY c.period, resolved_half1,resolved_half2,opened_half1,opened_half2,c.yearClosed,c.weekClosed 
ORDER BY row 

Mã này sử dụng một giá trị cứng mã hoá 180 ngày. Tôi vẫn cần phải có thể sử dụng một varibale để chọn số ngày (mà không nhận được một phân chia bởi 0 lỗi), và mã thực sự cần phải được làm sạch. Nếu ai đó có thể làm hai điều đó cho tôi (tôi không phải là giỏi nhất trong SQL), tiền thưởng là của họ.

Ảnh:

Chart

0

Tôi tin rằng điều này sẽ làm các trick - nếu không đăng một số dữ liệu mẫu thực tế và tôi sẽ xem liệu tôi có thể tinh chỉnh nó để sửa chữa nó:

DECLARE @noOfDays INT 
SET @noofdays = 180 

;WITH tickets AS 
(
SELECT DISTINCT 
DATENAME(YEAR,date_closed) + RIGHT('000' + CAST(DATEPART(WEEK,date_closed) AS VARCHAR(5)),3) as Period 
,ticket_nbr 
,1 as ticket_type --resolved 
FROM v_rpt_Service 
WHERE (date_closed >= DateAdd(Day, DateDiff(Day, 0, GetDate()) - @NoOfDays, 0)) 
UNION ALL 
SELECT DISTINCT 
DATENAME(YEAR,date_closed) + RIGHT('000' + CAST(DATEPART(WEEK,date_closed) AS VARCHAR(5)),3) as Period 
,ticket_nbr 
,0 as ticket_type --opened 
FROM v_rpt_Service 
WHERE (date_entered > = DateAdd(Day, DateDiff(Day, 0, GetDate()) - @NoOfDays, 0)) 
) 
,tickets2 AS 
(
SELECT 
Period 
,SUM(CASE WHEN ticket_type = 0 THEN 1 ELSE 0 END) as opened 
,SUM(CASE WHEN ticket_type = 1 THEN 1 ELSE 0 END) as closed 
FROM tickets 
GROUP BY 
Period 
) 
,tickets3 AS 
(
SELECT 
Period 
,row_number() OVER (ORDER BY period ASC) as row 
,opened 
,closed 
,COUNT(period) OVER() as base 
,SUM(opened) OVER() as [Sumopened] 
,SUM(opened * opened) OVER() as [Sumopened^2] 
,SUM(opened * closed) OVER() as [Sumopenedclosed] 
,SUM(closed) OVER() as [Sumclosed] 
,SUM(closed * closed) OVER() as [Sumclosed^2] 
,SUM(opened * closed) OVER() * COUNT(period) OVER() AS [nSumopenedclosed] 
,SUM(opened) OVER() * SUM(closed) OVER() AS [Sumopened*Sumclosed] 
,SUM(opened * opened) OVER() * COUNT(period) OVER() AS [nSumopened^2] 
,SUM(opened) OVER() * SUM(opened) OVER() as [Sumopened*Sumopened] 
FROM tickets2 
) 
--Formula for linear regression is Y = A + BX 
SELECT 
period 
,opened 
,closed 
,((1.0/base) * [Sumclosed]) - 
([Sumopenedclosed] - ([Sumopened*Sumclosed]/base))/([Sumopened^2] - ([Sumopened*Sumopened]/base)) *((1.0/base) * [Sumopened]) 
+ row * ([Sumopenedclosed] - ([Sumopened*Sumclosed]/base))/([Sumopened^2] - ([Sumopened*Sumopened]/base)) 
AS trend_point 
,((1.0/base) * [Sumclosed]) - 
([Sumopenedclosed] - ([Sumopened*Sumclosed]/base))/([Sumopened^2] - ([Sumopened*Sumopened]/base)) *((1.0/base) * [Sumopened]) AS A 
,([Sumopenedclosed] - ([Sumopened*Sumclosed]/base))/([Sumopened^2] - ([Sumopened*Sumopened]/base)) as B 
from tickets3 
3

Tôi đã quan tâm đến vấn đề này và tôi đã tìm ra cách tốt nhất để tìm kiếm một truy vấn phức tạp là định dạng lại nó bằng cách sử dụng phong cách và quy ước của riêng tôi. Tôi áp dụng chúng cho giải pháp của bạn, và kết quả là dưới đây. Tôi không biết nếu điều này sẽ có giá trị gì đối với bạn ...

  • Có một vài bit của mã mà tôi không tin là một phần của cú pháp MS T-SQL, chẳng hạn như ({fn xxx }WEEK(xxx) chức năng.
  • Mã này biên dịch, nhưng tôi không thể chạy vì tôi không có bảng dữ liệu được định cấu hình đúng cách.
  • Tôi đã tạo ra một loạt các thay đổi về mã hóa sẽ tốn nhiều thời gian để giải thích và tôi sẽ bỏ qua hầu hết điều đó. Thêm nhận xét nếu bạn muốn bất kỳ điều gì được giải thích.
  • Tôi đã ném vào rất nhiều khoảng trắng. Sự khác biệt giữa các mã dễ đọc và dễ đọc thường chỉ là sự nhận thức và sự nhạy cảm của kẻ thù, và bạn có thể ghét các quy ước của tôi.
  • Không chắc chắn về tập kết quả cuối cùng sẽ được (tức là cột có được trả lại)

Một số thêm ghi chú:

  • Truy vấn này sẽ không nhận được mặt hàng nhập vào một tuần nếu không có mục nào cũng đóng cửa trong tuần đó
  • Tuần có thể là một phần, ví dụ: không phải tất cả bảy ngày có thể có mặt (điều chỉnh @Interval để luôn bao gồm cả tuần đầy đủ - nhưng khoảng kỳ số lẻ?)
  • Nhân số giá trị (*) với 1.0 để chuyển đổi chúng thành phao sớm (tránh toán học và số nguyên cắt ngắn)
  • Made nó một CTE để cho phép các công thức trước đó được thay thế bằng biểu tượng trong các công thức sau (lúc này mọi thứ trở nên rất nhiều dễ đọc hơn)

Vì vậy, đây là những gì tôi đã đưa ra:

;WITH cte as (
select 
    c.period 
    ,resolved_half1 
    ,resolved_half2 
    ,opened_half1 
    ,opened_half2 
    ,row = row_number() over(order by c.yearClosed, c.weekClosed) 
    ,y1 = ((SUM(resolved_half1) + SUM(opened_half1)) - (SUM(resolved_half2) + SUM(opened_half2)))/((count(resolved_half1) + count(opened_half1))/2) 
    ,y2 = ((SUM(resolved_half2) + SUM(opened_half2))/(count(resolved_half2) + COUNT (opened_half2))) 
    ,x1 = ((count(c.period))/4) 
    ,x2 = (((count(c.period))/4) * 3) 
from (select 
      a.yearclosed 
     ,a.weekClosed 
     ,a.resolved_half1 
     ,b.yearEntered 
     ,b.weekEntered 
     ,b.opened_half1 
     ,cast(a.yearClosed as varchar(5)) + ', ' + cast(a.weekClosed as varchar(5)) period 
     from (-- Number of items per week that closed within @Interval 
       select 
       count(distinct TicketNbr) * 1.0 resolved_half1 
       ,datepart(wk, date_closed)  weekClosed 
       ,year(date_closed)    yearClosed 
       from v_rpt_Service 
       where date_closed >= @FullInterval 
       group by 
       datepart(wk, date_closed) 
       ,year(date_closed)) a 
     left outer join (-- Number of items per week that were entered within @Interval 
          select 
          count(distinct TicketNbr) * 1.0 opened_half1 
          ,datepart(wk, date_entered)  weekEntered 
          ,year(date_entered)    yearEntered 
          from v_rpt_Service 
          where date_entered >= @FullInterval 
          group by 
          datepart(wk, date_entered) 
          ,year(date_entered)) b 
      on a.weekClosed = b.weekEntered 
      and a.yearClosed = b.yearEntered) c 
    left outer join (select 
         d.yearclosed 
         ,d.weekClosed 
         ,d.resolved_half2 
         ,e.yearEntered 
         ,e.weekEntered 
         ,e.opened_half2 
         ,cast(yearClosed as varchar(5)) + ', ' + cast(weekClosed as varchar(5)) period 
        from (select 
          count(distinct TicketNbr) * 1.0 resolved_half2 
          ,datepart(wk, date_closed)  weekClosed 
          ,year(date_closed)    yearClosed 
          from v_rpt_Service 
          where date_closed >= @HalfInterval 
          group by 
          datepart(wk, date_closed) 
          ,year(date_closed)) d 
        left outer join (select 
             count(distinct TicketNbr) * 1.0 opened_half2 
             ,datepart(wk, date_entered)  weekEntered 
             ,year(date_entered)    yearEntered 
             from v_rpt_Service 
             where date_entered >= @HalfInterval 
             group by 
              datepart(wk, date_entered) 
              ,year(date_entered)) e 
         on d.weekClosed = e.weekEntered 
         and d.yearClosed = e.yearEntered) f 
    on c.period = f.period 
group by 
    c.period 
    ,resolved_half1 
    ,resolved_half2 
    ,opened_half1 
    ,opened_half2 
    ,c.yearClosed 
    ,c.weekClosed 
) 
SELECT 
    row 
    ,Period 
    ,x1 
    ,y1 
    ,x2 
    ,y2 
    ,m = ((y1 - y2)/(x1 - x2)) 
    ,b = (y2 - (((y1 - y2)/(x1 - x2)) * x2)) 
    ,trend = ((((y1 - y2)/(x1 - x2)) * (row)) + (y2 - (((y1 - y2)/(x1 - x2)) * x2))) 
from cte 
order by row 

Là một phụ lục, tất cả các truy vấn phụ "c" co uld được thay thế bằng một cái gì đó như sau, và "f" với một phiên bản hơi sửa đổi. Hiệu suất tốt hơn hoặc tệ hơn phụ thuộc vào kích thước bảng, lập chỉ mục và các yếu tố khác.

select 
    datepart(wk, date_closed) weekClosed 
    ,year(date_closed)   yearClosed 
    ,count (distinct case 
        when date_closed >= @FullInterval then TicketNbr 
        else null 
       end)   resolved_half1 
    ,count (distinct case 
        when date_entered >= @FullInterval then TicketNbr 
        else null 
       end)   opened_half1 
from v_rpt_Service 
where date_closed >= @FullInterval 
    or date_entered >= @FullInterval 
group by 
    datepart(wk, date_closed) 
    ,year(date_closed) 
Các vấn đề liên quan