简体   繁体   English

将虚拟/占位符数据合并到SQL查询中

[英]Merging dummy/placeholder data into a SQL query

In our SQL Server 2016 database we have a Payments table which records monthly payments made by our customers, but as they do not necessarily pay every month we may have missing month data. 在我们的SQL Server 2016数据库中,我们有一个Payments表,记录了我们客户每月付款,但因为他们不一定每月支付我们可能丢失的月数据。

I now need to insert the missing monthly payment data (ie a zero payment) for each customer for an SSRS report because the business wants to see every month on the report to assess customer payment frequency. 我现在需要为每个客户插入缺少的每月支付数据(即零支付)以获取SSRS报告,因为企业希望在报告中每月查看以评估客户支付频率。

So in the SQL statement below, I first create a table variable and insert a row for each month and a zero payment amount. 因此,在下面的SQL语句中,我首先创建一个表变量,并为每个月插入一行和零支付金额。 Then I've created some sample payment data with customer Id, month paid and the amount. 然后我创建了一些样本支付数据,包括客户ID,月支付金额和金额。 What I then need to do is end up with a result that has 12 entries for each customer, one for each month, showing either the payment made that month or 0. 我当时需要做的是最终得到的结果是每个客户有12个条目,每个月一个,显示当月付款或0。

-- Dummy monthly payment data to use for missing months
DECLARE @DummyPayments TABLE
(
    MonthNumber INT,
    Payment MONEY
)

INSERT INTO @DummyPayments 
select 1,0 union
select 2,0 union
select 3,0 union
select 4,0 union
select 5,0 union
select 6,0 union
select 7,0 union
select 8,0 union
select 9,0 union
select 10,0 union
select 11,0 union
select 12,0

-- This (much simplified) data would come from our Payments table
DECLARE @CustomerPayments TABLE
(
    CustomerID INT,
    MonthNumber INT,
    Payment MONEY
)

-- Example customer 1 made payment in months 1,3,6,9
insert into @CustomerPayments values(1,1,100);
insert into @CustomerPayments values(1,3,120);
insert into @CustomerPayments values(1,6,140);
insert into @CustomerPayments values(1,9,95);

-- Example customer 2 made payment in months 2,5,10,12    
insert into @CustomerPayments values(2,2,80);
insert into @CustomerPayments values(2,5,90);
insert into @CustomerPayments values(2,10,130);
insert into @CustomerPayments values(2,12,105);

-- Now I want to join real payments with dummy/missing payments
-- to get payment data for each month in the year.
with cust as
(
    select distinct CustomerID 
    from @CustomerPayments
)
select * from @CustomerPayments cp
union
select c.CustomerID, 
(select dp.MonthNumber
 from @DummyPayments dp 
 where dp.MonthNumber not in (select cp.MonthNumber from @CustomerPayments cp where cp.CustomerID = c.CustomerID)),
 0
from cust c

When I run it I get an error 当我运行它时,我收到一个错误

Subquery returned more than 1 value. 子查询返回的值超过1。 This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression. 当子查询跟随=,!=,<,<=,>,> =或子查询用作表达式时,不允许这样做。

I thought doing this with a union would work and I understand the error is telling me I'm getting too many results in each sub-query but short of using a cursor I can't work out how to do this. 我认为用联盟做这件事会起作用,我理解错误告诉我在每个子查询中得到的结果太多但是使用游标时我不知道如何做到这一点。 Perhaps I'm over complicating it but if anyone can help me out I'd appreciate it. 也许我过于复杂,但如果有人能帮助我,我会很感激。

Use cross join to generate the rows and then left join to bring in the existing results: 使用cross join生成行,然后left join以引入现有结果:

select c.customerid, dp.monthnumber, coalesce(cp.payment, 0) as payment
from (select distinct customerid from @customerpayments cp
     ) c cross join
     @dummypayments dp left join
     @customerpayments cp
     on cp.customerid = c.customerid and
        cp.monthnumber = dp.monthnumber;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM