2013-02-22 36 views
6

Tôi có một bảng (T1) với các cột sau: bộ phận, ngày tháng, tổng số. Điều tôi muốn đạt được là bán bộ phận mỗi tháng trong một năm kể từ ngày bắt đầu và lùi lại 1 năm. Có thể truy vấn sau sẽ hiển thị tốt hơn những gì tôi muốn đạt được.Thêm hàng giả vào kết quả truy vấn

-- Create the table T1 
    CREATE TABLE [dbo].[T1](
    [department] [nvarchar](50) NULL, 
    [dateofsale] [datetime] NULL, 
    [totalsales] [decimal](18, 5) NULL 
    ) ON [PRIMARY] 

-- Add some data 
    INSERT [dbo].[T1] ([department], [dateofsale], [totalsales]) VALUES (N'0001', CAST(0x0000A29B00000000 AS DateTime), CAST(200.00000 AS Decimal(18, 5))) 
    INSERT [dbo].[T1] ([department], [dateofsale], [totalsales]) VALUES (N'0001', CAST(0x0000A27D00000000 AS DateTime), CAST(300.00000 AS Decimal(18, 5))) 
    INSERT [dbo].[T1] ([department], [dateofsale], [totalsales]) VALUES (N'0001', CAST(0x0000A29C00000000 AS DateTime), CAST(200.00000 AS Decimal(18, 5))) 

-- The query 
    declare @dataBegin datetime 
    declare @dataEnd datetime 
    set @dataEnd = '21/12/2013' 
    set @dataBegin = DATEADD(month,-11, @dataEnd) - (DAY(@dataEnd)-1) 
    set @dataEnd = DATEADD(month,1, @dataEnd) - (DAY(@dataEnd)) 
    SELECT department,SUM(totalsales) AS totsales, MONTH(dateofsale) as month, YEAR(dateofsale) as year 
    FROM T1 
    WHERE dateofsale >= @dataBegin AND dateofsale< @dataEnd 
    GROUP BY department,MONTH(dateofsale), YEAR(dateofsale) 
    ORDER BY department,MONTH(dateofsale), YEAR(dateofsale) 

Với các dữ liệu thêm vào trước kết quả của truy vấn sẽ được như sau:

department /totsales/ month /year 
    0001/ 300.00000 /11 /2013 
    0001/ 400.00000 /12 /2013 

Vấn đề là tôi muốn cũng là tháng mà có một giá trị không như Tổng lượng bán. Vì vậy, kết quả phải:

department /totsales/ month /year 
0001/ 0 /1 /2013 
0001/ 0 /2 /2013 
0001/ 0 /3 /2013 
0001/ 0 /4 /2013 
0001/ 0 /5 /2013 
0001/ 0 /6 /2013 
0001/ 0 /7 /2013 
0001/ 0 /8 /2013 
0001/ 0 /9 /2013 
0001/ 0 /10 /2013 
0001/ 300.00000 /11 /2013 
0001/ 400.00000 /12 /2013 

Làm thế nào tôi có thể làm điều đó?

Trả lời

1

Bạn có thể tạo hai truy vấn và UNION chúng hoặc để chế tạo các hàng bị thiếu, hãy sử dụng CTE. Tôi hiểu bạn có nghĩa là bạn không có dữ liệu trước tháng mười một.

WITH months 
AS 
( 
    SELECT 2013 as yr, 1 as mnth  
    UNION ALL 
    SELECT 2013 as yr, mnth+1 as mnth 
    FROM months 
    WHERE mnth < 12  
) select months.yr, months.mnth, department, isnull(totsales,0.00) as totsales 
from months 
left join sales on sales.yr = months.yr and sales.month = months.mnth 

Chỉ cần sử dụng hàm datepart để trích xuất tháng từ ngày bán hàng của bạn. Truy vấn trên chỉ nhằm cho bạn biết cách nhận được số tháng bạn không có trong dữ liệu của mình.

2

bạn có thể tạo một bảng tháng và làm một Left Tham gia với nó

SELECT * 
FROM Months M 
LEFT JOIN T1 T ON M.month = T.Month 
1

Con đường tôi đã quản lý để có được vòng vấn đề này khi tôi đã gặp phải nó là tạo ra một bảng tạm thời tạo ra tất cả các số ngày cần sau đó thực hiện một UNION giữa bảng tạm thời và truy vấn dữ liệu trong một tuyên bố chọn:

Chỉ
-- Create the table T1 
CREATE TABLE #T1(
[department] [nvarchar](50) NULL, 
[dateofsale] [datetime] NULL, 
[totalsales] [decimal](18, 5) NULL 
) ON [PRIMARY] 
-- Add some data 
INSERT #T1 ([department], [dateofsale], [totalsales]) VALUES (N'0001', CAST(0x0000A29B00000000 AS DateTime), CAST(200.00000 AS Decimal(18, 5))) 
INSERT #T1 ([department], [dateofsale], [totalsales]) VALUES (N'0001', CAST(0x0000A27D00000000 AS DateTime), CAST(300.00000 AS Decimal(18, 5))) 
INSERT #T1 ([department], [dateofsale], [totalsales]) VALUES (N'0001', CAST(0x0000A29C00000000 AS DateTime), CAST(200.00000 AS Decimal(18, 5))) 

--Solution Start 
DECLARE @dataBegin datetime 
DECLARE @dataEnd datetime 
DECLARE @CurrentDate DATETIME 
SET @dataEnd = '2013-12-23' 
SET @dataBegin = DATEADD(month,-11, @dataEnd) - (DAY(@dataEnd)-1) 
SET @dataEnd = DATEADD(month,1, @dataEnd) - (DAY(@dataEnd)) 

SET @CurrentDate = @dataBegin 

-- Create Temporary Table 
CREATE TABLE #calDate (calDate DATETIME) 

-- Populate Table 
INSERT INTO #calDate (calDate) 
    SELECT @CurrentDate 

WHILE DATEADD(MONTH, 1, @CurrentDate) <= @dataEnd 
BEGIN 
    INSERT INTO #calDate (calDate) 
     SELECT DATEADD(MONTH, 1, @CurrentDate) 
    SET @CurrentDate = DATEADD(MONTH, 1, @CurrentDate) 
END 

-- Query Data 
SELECT 
    department 
    , sum(totsales) 
    , month 
    , year 
FROM(
    SELECT '0001' as 'department',0 AS totsales, MONTH(calDate) as month, YEAR(calDate) as year FROM #calDate 
    UNION 
    SELECT department,SUM(totalsales) AS totsales, MONTH(dateofsale) as month, YEAR(dateofsale) as year 
    FROM #T1 
    WHERE dateofsale >= @dataBegin AND dateofsale< @dataEnd 
    GROUP BY department,MONTH(dateofsale), YEAR(dateofsale) 
)a 
GROUP BY department,month, year 
ORDER BY department,month, year 
DROP table #calDate 
DROP table #T1 

vấn đề với trên là bộ phận được cứng mã hóa trong bảng tạm thời tạo ra, có thể được thông qua như là tham số mặc dù.

2

Bạn không cần mô phỏng các hàng bị thiếu, chỉ nhận được giá trị phù hợp cho nó.

Lưu ý: dữ liệu cần phải được xoay vòng không chỉ theo Năm tháng mà theo bộ phận. Nếu không, bạn sẽ nhận được giá trị NULL

-- Create the table T1 
    DECLARE @T1 TABLE(
    [department] [nvarchar](50) NULL, 
    [dateofsale] [datetime] NULL, 
    [totalsales] [decimal](18, 5) NULL 
    ) 

-- Add some data 
    INSERT @T1([department], [dateofsale], [totalsales]) VALUES (N'0001', CAST(0x0000A29B00000000 AS DateTime), CAST(200.00000 AS Decimal(18, 5))) 
    INSERT @T1([department], [dateofsale], [totalsales]) VALUES (N'0001', CAST(0x0000A27D00000000 AS DateTime), CAST(300.00000 AS Decimal(18, 5))) 
    INSERT @T1([department], [dateofsale], [totalsales]) VALUES (N'0001', CAST(0x0000A29C00000000 AS DateTime), CAST(200.00000 AS Decimal(18, 5))) 
    INSERT @T1([department], [dateofsale], [totalsales]) VALUES (N'0003', CAST(0x0000A29C00000000 AS DateTime), CAST(100.00000 AS Decimal(18, 5))) 
-- The query 
DECLARE @dataBegin DATETIME 
DECLARE @dataEnd DATETIME 

SET @dataEnd = '20140101' 
SET @dataBegin = DATEADD(month, - 11, @dataEnd) - (DAY(@dataEnd) - 1) 
SET @dataEnd = DATEADD(month, 1, @dataEnd) - (DAY(@dataEnd)); 

WITH Months (
    MonthNr 
    ,Year 
    ,Department 
    ) 
AS (
    SELECT MonthNr 
     ,Y.Year 
     ,D.department 
    FROM (
     VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12) 
     ) M(MonthNr) 
    CROSS JOIN (
     SELECT DISTINCT T.department 
     FROM @T1 T 
     ) D 
    CROSS JOIN (
     SELECT year 
     FROM (
      VALUES (2013) --insert as many years as you need 
      ) T(year) 
     ) Y 
    ) 
SELECT M.department 
    ,ISNULL(T.totsales, 0) totalSales 
    ,M.MonthNr month 
    ,M.year 
FROM Months M 
LEFT JOIN (
    SELECT department 
     ,SUM(totalsales) AS totsales 
     ,MONTH(dateofsale) AS month 
     ,YEAR(dateofsale) AS year 
    FROM @T1 
    WHERE dateofsale >= @dataBegin 
     AND dateofsale < @dataEnd 
    GROUP BY department 
     ,MONTH(dateofsale) 
     ,YEAR(dateofsale) 
    ) T ON T.month = M.MonthNr and T.department = M.Department 
ORDER BY department 
    ,M.MonthNr 
    ,M.Year 

Kết quả:

department  totalSales   month  year 
--------------- --------------------- ----------- ----------- 
0001   0.00000    1   2013 
0001   0.00000    2   2013 
0001   0.00000    3   2013 
0001   0.00000    4   2013 
0001   0.00000    5   2013 
0001   0.00000    6   2013 
0001   0.00000    7   2013 
0001   0.00000    8   2013 
0001   0.00000    9   2013 
0001   0.00000    10   2013 
0001   300.00000    11   2013 
0001   400.00000    12   2013 
0003   0.00000    1   2013 
0003   0.00000    2   2013 
0003   0.00000    3   2013 
0003   0.00000    4   2013 
0003   0.00000    5   2013 
0003   0.00000    6   2013 
0003   0.00000    7   2013 
0003   0.00000    8   2013 
0003   0.00000    9   2013 
0003   0.00000    10   2013 
0003   0.00000    11   2013 
0003   100.00000    12   2013 
0

Chèn một giá trị zero cho mỗi tháng hoặc ngày và từng bộ phận. Bây giờ dữ liệu của bạn rõ ràng và các truy vấn của bạn được đơn giản hóa.

Giả sử sự vắng mặt của dữ liệu ngụ ý giá trị bằng 0 không phải là một thực hành dữ liệu tốt.

1

Một trong những ứng dụng tuyệt vời cho bảng số:

-- Populate numbers table; keep this around, you'll find uses for it! 
;WITH 
    Pass0 as (select 1 as C union all select 1), --2 rows 
    Pass1 as (select 1 as C from Pass0 as A, Pass0 as B),--4 rows 
    Pass2 as (select 1 as C from Pass1 as A, Pass1 as B),--16 rows 
    Pass3 as (select 1 as C from Pass2 as A, Pass2 as B),--256 rows 
    Pass4 as (select 1 as C from Pass3 as A, Pass3 as B),--65536 rows 
    Pass5 as (select 1 as C from Pass4 as A, Pass4 as B),--4,294,967,296 rows 
    Tally as (select row_number() over(order by C) as Number from Pass5) 
select Number into dbo.Numbers from Tally where Number <= 1000000 


-- The query 
declare @dataBegin datetime 
declare @dataEnd datetime 
set @dataEnd = '2013-12-21' 
set @dataBegin = DATEADD(month,-11, @dataEnd) - (DAY(@dataEnd)-1) 
set @dataEnd = DATEADD(month,1, @dataEnd) - (DAY(@dataEnd)); 
with sales as (
    SELECT department,SUM(totalsales) AS totsales, MONTH(dateofsale) as month, YEAR(dateofsale) as year 
    FROM T1 
    WHERE dateofsale >= @dataBegin AND dateofsale< @dataEnd 
    GROUP BY department,MONTH(dateofsale), YEAR(dateofsale) 
), 
all_months as (
    select distinct department, Number as [month], 2013 as [year] 
    from T1 as t 
    cross join dbo.Numbers as n 
    where n.Number <= 12 
) 
select m.department, coalesce(s.totsales, 0), m.[month], m.[year] 
from all_months as m 
left join sales as s 
    on m.department = s.department 
    and m.[year] = s.[year] 
    and m.[month] = s.[month] 
ORDER BY m.department, m.[month], m.[year] 
Các vấn đề liên quan