【问题标题】:Select and Inner Join Returning Duplicates选择和内连接返回重复项
【发布时间】:2021-09-24 20:30:09
【问题描述】:

我正在开发一个查询来打印有关用户旅行的报告。但是,此查询返回 4 行而不是 2 行。解释业务规则:用户创建旅行邀请并添加不同的目的地作为路线。用户必须定义​​路线的每个子公司必须为旅行支付的百分比。旅行可以有多个目的地,也可以只有一个。当我执行以下查询时:

Select Distinct sv.Description,
    st.Description,
    us.Code, us.Name,
    rt.Destination, rt.Description, rt.BeginDate, rt.FInishDate,
    rat.Percentage,
    fl.Code, fl.Name
FROM TravelSolicitation sv
INNER JOIN Situation st ON sv.IdSituation = st.Id
INNER JOIN Duser us ON sv.IdUser = us.Id
INNER JOIN Itinerary rt ON rt.IdSolicitation = sv.Id
INNER JOIN Apportionment rat ON rat.IdSolicitation = sv.Id
INNER JOIN Subsidiary fl ON rat.IdSubsidiary = fl.Id
WHERE sv.Id = 1

我得到以下结果:

SQL Output

我的问题: 考虑到分摊表,查询结果应该只显示 2 行,因为每个子公司的分摊是 80 和 20。如果我对 3 个子公司使用 3 个不同的分摊(即 50、30、20),查询结果将显示 9 行。我也尝试过使用 LEFT JOIN、RIGHT JOIN 和 OUTER JOIN,但它不起作用。

如何开发此查询以仅返回 2 行?

我的预期输出:

+----------+-------------+-----+------+------------+------+-----------+------------+------+---+------------+
| Travel 1 | Credit Test | 110 | Paul | Ny         | Work | BeginDate | FinishDate | 20.0 | 4 | City B Sub |
+----------+-------------+-----+------+------------+------+-----------+------------+------+---+------------+
| Travel 1 | Credit Test | 110 | Paul | Washington | Fun  | BeginDate | FinishDate | 80.0 | 2 | City A Sub |
+----------+-------------+-----+------+------------+------+-----------+------------+------+---+------------+

注意:我注意到 Apportionment INNER JOIN 生成了 4 行。其他 INNER JOINS 显然有效。我正在使用 SQL Server

MVCE 重现我的问题:

表格:

CREATE TABLE [Subsidiary] (
    [Id] bigint NOT NULL,
    [Code] varchar(4) NOT NULL,
    [Name] varchar(40) NOT NULL,
    CONSTRAINT [PK_Subsidiary_Id] PRIMARY KEY CLUSTERED
    (
        [Id] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, DATA_COMPRESSION=NONE) ON [PRIMARY]
 ) ON [PRIMARY]
 GO

CREATE TABLE [Apportionment] (
    [Id] bigint NOT NULL,
    [IdSubsidiary] bigint NOT NULL,
    [IdSolicitation] bigint NOT NULL,
    [Percentage] decimal(19,4) NOT NULL,
    CONSTRAINT [PK_Apportionment_Id] PRIMARY KEY CLUSTERED
    (
        [Id] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, DATA_COMPRESSION=NONE) ON [PRIMARY]
 ) ON [PRIMARY]
 GO

CREATE TABLE [Itinerary] (
   [Id] bigint NOT NULL,
   [IdSolicitation] bigint NOT NULL,
   [Destination] varchar(200) NULL,
   [Description] varchar(50) NOT NULL,
   [BeginDate] datetime NOT NULL,   
   [FInishDate] datetime NULL,
   [MultipleItinerary] bit NOT NULL,
   
   CONSTRAINT [PK_Itinerary_Id] PRIMARY KEY CLUSTERED
   (
     [Id] ASC
   )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, DATA_COMPRESSION=NONE) ON [PRIMARY]
 ) ON [PRIMARY]
 GO

 CREATE TABLE [Situation](
    [Id] bigint NOT NULL,
    [Name] varchar(40) NOT NULL,
    [Description] varchar(150) NOT NULL,
    [ValidateDate] smallint NOT NULL,
 CONSTRAINT [PK_Situation_Id] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

CREATE TABLE [TravelSolicitation] 
    ([Id] bigint IDENTITY(1,1) NOT NULL, 
    [IdSituation] bigint NOT NULL, 
    [IdUser] bigint NOT NULL, 
    [Description] varchar(150) NOT NULL, 
    [GoDate] datetime NOT NULL, 
    [BackDate] datetime NOT NULL, 

CONSTRAINT [PK_TravelSolicitation_Id] PRIMARY KEY CLUSTERED
   (
     [Id] ASC
   )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, DATA_COMPRESSION=NONE) ON [PRIMARY]
 ) ON [PRIMARY]
 GO

 CREATE TABLE [Duser] (
    [Id] bigint NOT NULL,
    [Code] varchar(10),
    [Name] varchar(70) NOT NULL,
    CONSTRAINT [PK_Duser_Id] PRIMARY KEY CLUSTERED
    (
        [Id] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, DATA_COMPRESSION=NONE) ON [PRIMARY]
 ) ON [PRIMARY]
 GO

外键:

ALTER TABLE Apportionment
ADD FOREIGN KEY (IdSubsidiary) REFERENCES Subsidiary(Id); 

ALTER TABLE Apportionment
ADD FOREIGN KEY (IdSolicitation) REFERENCES TravelSolicitation(Id); 

ALTER TABLE Itinerary
ADD FOREIGN KEY (IdSolicitation) REFERENCES TravelSolicitation(Id); 

ALTER TABLE TravelSolicitation
ADD FOREIGN KEY (IdSituation) REFERENCES Situation(Id); 

ALTER TABLE TravelSolicitation
ADD FOREIGN KEY (IdUser) REFERENCES Duser(Id); 

插入

INSERT INTO Duser (Id,Code,Name) VALUES (1,110,'Paul')

INSERT INTO Situation (Id,Name,Description,ValidateDate) VALUES (1,'Situation A','Credit Test',1)

INSERT INTO Subsidiary (Id,Code,Name) VALUES (1,'2','City A Sub');
INSERT INTO Subsidiary (Id,Code,Name) VALUES (2,'4','City B Sub');

INSERT INTO TravelSolicitation(IdSituation,IdUser,Description,GoDate,BackDate) VALUES (1,1,'Travel 1','20-10-2021','20-11-2021');

INSERT INTO Itinerary (Id,IdSolicitation,Destination,Description,BeginDate,FInishDate,MultipleItinerary) VALUES (1,1,'Washington','Fun','20-10-2021','10-11-2021',1)
INSERT INTO Itinerary (Id,IdSolicitation,Destination,Description,BeginDate,FInishDate,MultipleItinerary) VALUES (2,1,'NY','Work','10-11-2021','20-11-2021',1)

INSERT INTO Apportionment(Id,IdSubsidiary,IdSolicitation,Percentage) VALUES (1,1,1,80.0)
INSERT INTO Apportionment(Id,IdSubsidiary,IdSolicitation,Percentage) VALUES (2,2,1,20.0)

【问题讨论】:

  • 我编辑了问题以提及我用于构建应用程序的工具。
  • 根据问题指南,请不要发布代码、数据、错误消息等的图像 - 将文本复制或键入问题中。请保留将图像用于图表或演示渲染错误,无法通过文本准确描述的事情。
  • DISTINCT 无论如何是一种代码味道:您需要考虑您的联接做什么,以及它们中的任何一个是否应该是半联接(例如EXISTSIN)以及是否any 应该是预先聚合的连接或“每组前 1 个”连接。每个Apportionment 和多个TravelSolicitation 都有多个Subsidiary,因此您需要仔细考虑您真正想要的结果。在查询中盲目地抛出DISTINCT,希望重复的行会消失不是解决方案
  • @Charlieface 我真的不明白为什么 Inner Join Apportionment 以不同的 subsidiary 加入两个分配,因为 Apportionment 上的每个“IdSubsidiary”都不同。
  • @DaleK 专栏 status?

标签: sql sql-server tsql select inner-join


【解决方案1】:

只需在INNER JOIN Apportionment rat ON rat.IdSolicitation = sv.Id 上添加and rt.id = rat.id

由于您从不使用 rt.id 进行过滤,因此会导致您的结果返回 4 行。

Select Distinct sv.Description,
st.Description,
us.Code, us.Name,
rt.Destination, rt.Description, rt.BeginDate, rt.FInishDate,
rat.Percentage,
fl.Code, fl.Name
FROM TravelSolicitation sv
INNER JOIN Situation st ON sv.IdSituation = st.Id
INNER JOIN Duser us ON sv.IdUser=us.Id
INNER JOIN Itinerary rt ON rt.IdSolicitation = sv.Id 
INNER JOIN Apportionment rat ON rat.IdSolicitation = sv.Id and rt.id = rat.id
INNER JOIN Subsidiary fl ON rat.IdSubsidiary=fl.Id
WHERE sv.Id = 1

【讨论】:

  • 谢谢,我没有这样想。我正在尝试使用In,就像@Charlieface 说的那样。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-28
  • 2018-07-30
相关资源
最近更新 更多