SQL查询以在同一行中显示以前的和当前的数据

SQL查询以在同一行中显示以前的和当前的数据,sql,sql-server,Sql,Sql Server,我正在制作一份报告,在一行中显示当前数据和以前的数据。我有一个源表和一个当前数据表以及一个以前的数据表。两者的主键都是源表行和该行的特定数据。有三种情况: 以前的和当前的数据都相同。 其中它仅在上一个数据表中。 其中它仅在当前数据表中。 我需要哪种类型的连接覆盖所有3种情况,如果其中一种或另一种情况不存在,则显示null。下面是我当前的查询,它只能显示情况1和3。我的代码可能是一团糟,因为我只是刚刚开始使用连接。如果还需要什么,我会补充 select currentData.LineItem,

我正在制作一份报告,在一行中显示当前数据和以前的数据。我有一个源表和一个当前数据表以及一个以前的数据表。两者的主键都是源表行和该行的特定数据。有三种情况:

以前的和当前的数据都相同。 其中它仅在上一个数据表中。 其中它仅在当前数据表中。 我需要哪种类型的连接覆盖所有3种情况,如果其中一种或另一种情况不存在,则显示null。下面是我当前的查询,它只能显示情况1和3。我的代码可能是一团糟,因为我只是刚刚开始使用连接。如果还需要什么,我会补充

select currentData.LineItem,
       currentData.billing_rate,
       prevData.billing_rate,
       currentData.total,
       prevData.pastRate
from (select source.company_name,
             source.LineItem,
             isnull(curr.billing_rate,589.0) as billing_rate,
             curr.total
      from((select d.company_name,f.LineItem
            from dbo.companies as d,
                 dbo.LineItems as f) as source
            full join (select company_name,
                              category,subcategory,
                              LineItem,
                              billing_rate * unitCount as total,
                              isnull(billing_rate,589.0) as billing_rate
                       from dbo.currentData) as curr on source.company_name = curr.company_name
                                                    and source.LineItem = curr.LineItem )) as currentData
     full join (select source.company_name,
                       source.LineItem,
                       isnull(d.billing_rate,589.0) as billing_rate,
                       d.pastRate
                from ((select d.company_name,
                              f.LineItem
                       from dbo.companies as d,
                            dbo.LineItems as f) as source
                     full join (select company_name,
                                       LineItem,
                                       billed_rate * unitCount as pastRate,
                                       isnull(billing_rate,589.0) as billing_rate
                                from dbo.prevData) as d on source.company_name = d.company_name
                                                       and source.LineItem = d.LineItem)) as prevData on currentData.company_name = prevData.company_name
                                                                                                     and currentData.LineItem = prevData.LineItem
                                                                                                     and currentData.billing_rate = prevData.billing_rate
                                                                                                     and ((prevData.pastRate is not null) or (currentData.total is not null))
添加带有表的sql脚本以进行测试

-- ************************************** [dbo].[LineItems]
CREATE TABLE [dbo].[LineItems]
(
 [lineitem]    varchar(50) NOT NULL ,
 [subcategroy] varchar(50) NOT NULL ,
 [category]    varchar(50) NOT NULL ,
 CONSTRAINT [PK_lineitems] PRIMARY KEY CLUSTERED ([lineitem] ASC)
);
GO
-- ************************************** [dbo].[companies]
CREATE TABLE [dbo].[companies]
(
 [company_name] varchar(50) NOT NULL ,

 CONSTRAINT [PK_companies] PRIMARY KEY CLUSTERED ([company_name] ASC)
);
GO
-- ************************************** [dbo].[prevData]

CREATE TABLE [dbo].[prevData]
(
 [lineitem]     varchar(50) NOT NULL ,
 [company_name] varchar(50) NOT NULL ,
 [billing_rate] numeric(18,0) NOT NULL ,
 [bill_date]    datetime NOT NULL ,
 [unitCount]    numeric(18,0) NOT NULL ,


 CONSTRAINT [PK_prevdata] PRIMARY KEY CLUSTERED ([lineitem] ASC, [company_name] ASC, [billing_rate] ASC, [bill_date] ASC),
 CONSTRAINT [FK_25] FOREIGN KEY ([lineitem])  REFERENCES [dbo].[LineItems]([lineitem]),
 CONSTRAINT [FK_31] FOREIGN KEY ([company_name])  REFERENCES [dbo].[companies]([company_name])
);
GO


CREATE NONCLUSTERED INDEX [fkIdx_25] ON [dbo].[prevData] 
 (
  [lineitem] ASC
 )

GO

CREATE NONCLUSTERED INDEX [fkIdx_31] ON [dbo].[prevData] 
 (
  [company_name] ASC
 )

GO

-- ************************************** [dbo].[currentData]

CREATE TABLE [dbo].[currentData]
(
 [lineitem]     varchar(50) NOT NULL ,
 [company_name] varchar(50) NOT NULL ,
 [billing_rate] numeric(18,0) NOT NULL ,
 [unitCount]    numeric(18,0) NULL ,


 CONSTRAINT [PK_currentdata] PRIMARY KEY CLUSTERED ([lineitem] ASC, [company_name] ASC, [billing_rate] ASC),
 CONSTRAINT [FK_22] FOREIGN KEY ([lineitem])  REFERENCES [dbo].[LineItems]([lineitem]),
 CONSTRAINT [FK_28] FOREIGN KEY ([company_name])  REFERENCES [dbo].[companies]([company_name])
);
GO


CREATE NONCLUSTERED INDEX [fkIdx_22] ON [dbo].[currentData] 
 (
  [lineitem] ASC
 )

GO

CREATE NONCLUSTERED INDEX [fkIdx_28] ON [dbo].[currentData] 
 (
  [company_name] ASC
 )

GO

insert into dbo.companies values ('testcomp1')
insert into dbo.companies values ('testcomp2')
insert into dbo.companies values ('testcomp3')
insert into dbo.lineitems values ('testline','testsub','testcat')
insert into dbo.lineitems values ('testline1','testsub','testcat')
insert into dbo.lineitems values ('testline2','testsub','testcat')
insert into dbo.lineitems values ('testline3','testsub','testcat')
insert into dbo.currentData values ('testline','testcomp1',12,11)
insert into dbo.prevData values ('testline','testcomp1',12,getdate(),11)
insert into dbo.currentData values ('testline1','testcomp1',12,11)
insert into dbo.prevData values ('testline1','testcomp1',12,getdate(),11)
insert into dbo.currentData values ('testline3','testcomp1',12,11)
insert into dbo.prevData values ('testline2','testcomp1',12,getdate(),11)


我希望查询在同一行中显示所有行项目以及当前费率和/或以前的费率

我知道您需要所有公司的所有行项目,即使它们在两个数据表中都没有行

我认为这应该可以做到:

        curr.billing_rate * curr.unitCount as total, prev.billing_rate * prev.unitCount as pastRate

from dbo.lineitems as l 
left join dbo.companies as c on 1=1
left join dbo.currentData as curr on curr.lineitem=l.lineitem and curr.company_name=c.company_name
left join dbo.prevdata as prev on prev.lineitem=l.lineitem and prev.company_name=c.company_name
与公司的联接是常数1=1,因此每对公司名称lineitem对应一行m*n乘积

如果prevData为每个lineitem和company包含多行,则左侧连接可以替换为外部应用选择顶部1。。。或子查询。 如果prevData表是大100k+行,可能是一个排名函数


如果问题不是很清楚,我只能说这么多。

看看你的最终选择,你似乎需要5栏:

select currentData.LineItem,
       currentData.billing_rate,
       prevData.billing_rate,
       currentData.total,
       prevData.pastRate
from ...
其中,currentData.total计算为currentData.billing_rate*currentData.unitCount和prevData.pastRate的类似公式

样本数据 我已将表格中的公司排除在外,因为它不是您最终选择的一部分

declare @LineItems table
(
    [lineitem]    varchar(50) not null,
    [subcategory] varchar(50) not null,
    [category]    varchar(50) not null
);

declare @PrevData table
(
    [lineitem]     varchar(50) not null,
    [company_name] varchar(50) not null,
    [billing_rate] numeric(18,0) not null,
    [bill_date]    datetime not null,
    [unitCount]    numeric(18,0) not null
);

declare @CurrentData table
(
    [lineitem]     varchar(50) not null,
    [company_name] varchar(50) not null,
    [billing_rate] numeric(18,0) not null,
    [unitCount]    numeric(18,0) null
);

insert into @lineitems (lineitem, subcategory, category) values
('testline','testsub','testcat'),
('testline1','testsub','testcat'),
('testline2','testsub','testcat'),
('testline3','testsub','testcat');

insert into @currentData (lineitem, company_name, billing_rate, unitCount) values
('testline','testcomp1',12,11),
('testline1','testcomp1',12,11),
('testline3','testcomp1',12,11);

insert into @prevData (lineitem, company_name, billing_rate, bill_date, unitCount) values
('testline','testcomp1',12,getdate(),11),
('testline1','testcomp1',12,getdate(),11),
('testline2','testcomp1',12,getdate(),11);
解决方案 您已经找到了完整联接以保留联接中第一个表和第二个表中的所有行。使用coalesce函数,您将获得第一个NOTNULL值

后果
空格和换行符对于编写可读代码甚至任何语言(如英语)来说都是非常好的东西……请提供示例数据和所需结果。格式化该查询后,它看起来相当复杂。它还混合了ANSI-89和ANSI-92连接,这似乎很奇怪。@GordonLinoff添加了表和一些数据,以及我希望在使用完全连接时得到的数据。我希望看到很多合并。
select  coalesce(cd.lineitem, pd.lineitem) as 'lineitem',
        cd.billing_rate as 'curr_bill_rate',
        pd.billing_rate as 'prev_bill_rate',
        cd.billing_rate * cd.unitCount as 'curr_total',
        pd.billing_rate * pd.unitCount as 'prev_total'
from @CurrentData cd
full join @PrevData pd
    on  pd.lineitem = cd.lineitem
    and pd.company_name = cd.company_name
order by 'lineitem';
lineitem   curr_bill_rate  prev_bill_rate  curr_total  prev_total
---------- --------------- --------------- ----------- -----------
testline   12              12              132         132
testline1  12              12              132         132
testline2  NULL            12              NULL        132
testline3  12              NULL            132         NULL