Sql 如何避免在不使用primarykey的情况下在联接中填充多行?

Sql 如何避免在不使用primarykey的情况下在联接中填充多行?,sql,tsql,join,left-join,Sql,Tsql,Join,Left Join,我有一个这样的疑问 SELECT DISTINCT TOP (100) PERCENT , a.Type, a.Period, s.SiteCode, s.Name AS SiteName, s.StreetAddress, ......... FROM dbo.Anal AS a INNER JOIN dbo.TankSystems AS ts ON a.TankSystemId = ts.TankSystemId INNER JOIN dbo.Sites AS s ON

我有一个这样的疑问

SELECT DISTINCT TOP (100) PERCENT ,
 a.Type,
 a.Period,
 s.SiteCode,
 s.Name AS SiteName,
 s.StreetAddress,

 .........
FROM dbo.Anal AS a 
INNER JOIN  dbo.TankSystems AS ts ON a.TankSystemId = ts.TankSystemId 
INNER JOIN dbo.Sites AS s ON ts.SiteId = s.SiteId 

Where s.SiteId=@SiteId
上述查询按预期返回结果。例:3排

我有另一个表,列为tankid,tank number,siteid,grade,diameter。 我想用左/内联接返回tanknumber

如果我加上,

INNER/LEFt JOIN dbo.Tanks AS tt ON s.SiteId =tt.SiteId 
结果是三倍的。比方说,如果我在tanktable中有3个特定siteid的条目,我会得到9行结果。 我的问题是,除了siteid之外,我没有任何其他列来限制加入

我怎样才能避免它呢?

试试这个

SELECT DISTINCT TOP (100) PERCENT ,
 a.Type,
 a.Period,
 s.SiteCode,
 s.Name AS SiteName,
 s.StreetAddress,
 s.CityOrLocal,
 tanks= STUFF((
 SELECT ', ' + [tank number] 
   FROM  dbo.Tanks tt 
   where tt.SiteId = s.SiteId  
   FOR XML PATH, TYPE).value(N'.[1]', N'varchar(max)'), 1, 2, '')   
FROM dbo.Analyses AS a 
INNER JOIN  dbo.TankSystems AS ts ON a.TankSystemId = ts.TankSystemId 
INNER JOIN dbo.Sites AS s ON ts.SiteId = s.SiteId 

Where s.SiteId=@SiteId

您需要连接到Tanks中的另一(附加)列,或者需要将Tanks折叠到每个siteid的一行

您选择哪一个在很大程度上取决于需求是什么。假设储罐在一个场地上列出储罐,每个场地都有一个塑料储罐和一个金属储罐,这就是为什么每个场地有两排储罐。两个储罐由同一制造商制造。您需要储罐制造商的ID。这意味着无论选择哪种类型的油箱,都可以添加以下连接条件:

AND tt.TankType = 'plastic'
查询现在丢弃了所有的金属罐,每个站点只剩下一个塑料罐,结果没有翻倍(称为笛卡尔产品),并且通过塑料罐获得制造商名称

换言之,你想知道现场所有储罐的总容量(升),塑料加上金属。如果按站点id对容量进行分组和求和,则会得到站点id唯一的行:

INNER JOIN (SELECT siteid, sum(capacity) as sumcap FROM tanks GROUP BY siteid) tt
ON tt.siteid = s.siteid
你说过你想要坦克号,但是如果一个站点上有多个坦克号怎么办。。你要最低的油箱号吗?最高的?所有储罐编号的逗号分隔列表

INNER JOIN (SELECT siteid, min(tanknumber) as firsttank FROM tanks GROUP BY siteid) tt
ON tt.siteid = s.siteid

INNER JOIN (SELECT siteid, max(tanknumber) as lasttank FROM tanks GROUP BY siteid) tt
ON tt.siteid = s.siteid

INNER JOIN (SELECT siteid, string_agg(tanknumber, ',') as tanklist FROM tanks GROUP BY siteid) tt
ON tt.siteid = s.siteid
这些都是如何将坦克列表简化为单个siteid的示例,这是您必须做的事情;决定你想要什么,并向DB索取

避免使用不同的 通常没有什么好的理由。绝对不要使用它来挤压加入后出现的重复行的意外负载


不要让数据库准备两倍于它必须准备的行数量,然后运行一个昂贵的过程来过滤掉所有重复的行。相反,每当将一个新表添加到联接中时,当您看到行加倍时,请扪心自问,您真正想要从该新表中得到什么,或者限制它,这样你就只能得到你想要的,或者分组/聚合它,这样你想要的信息被压缩成单个标识符,而不会导致你的行加倍/三倍/etc向上

没有所谓的“左内联接”-它要么是“左(外)联接”,要么是“内联接”。您不能根据基表行和/或业务情况来说明需要哪些行。请在代码问题中给出一个--cut&paste&runnable代码;具有期望和实际输出的示例输入(包括逐字错误消息);标签和版本;清晰的说明和解释。这包括您能给出的最少代码,即您显示为OK的代码,由您显示为not OK的代码扩展。(调试基础。)在给出关系(ship)/关联或表(base或query result)时,请说明其中的一行根据其列值对业务状况的说明。查询时不需要约束(包括PKs和FKs)。在每个基表和查询结果中,了解一行对业务情况的描述是必要且充分的。这将为所有行返回相同的TankNumber。这是所有3行的TankNumber=1。它应该是TankNumber 1、2、3,但这只是您的标准s.SiteId=tt.siteidhm..是的。但要求如我所说..我无法更改架构..您使用的是哪种sql引擎和版本?mssql server 2012我理解。坦克有唯一的坦克编号。这是一个序列。1,2,3,4. 指现场的4个储罐。所有4种燃料都含有不同的燃料。所以我的要求是把油箱号改为1或2或3或4。容量或任何其他列不是唯一的。在该表中,只有主键和储罐编号是唯一的:(您似乎在说任何储罐编号都可以,所以根据我的示例选择最小值或最大值,或者如果每个站点都有储罐编号1(但不是每个站点都有储罐编号2,更不用说3或4),只需添加
和tt.tanknumber=1
。您并没有真正说明您想要从tanks表中获得什么其他信息,因此很难给出具体建议。您为什么要加入tanks表?什么是“我想要返回tanknumber”是什么意思?你想要最高的油箱号吗?油箱号列表?它们包含的不同燃油的数量?什么是“正确的”坦克编号的意思是?右=正确?右=左的对立面?请尽量记住,你知道你想要什么,只有你清楚地向我解释,我才能知道你想要什么;我看不懂Mind我已经在坦克表上添加了一张结果图片,带有siteid限制。你可以看到坦克编号列。它是如何在理想情况下,坦克1必须是纸浆,坦克2必须是超级坦克,坦克3必须是无铅坦克,所以你说坦克1总是储存纸浆,坦克2总是储存超级坦克,坦克3总是储存无铅坦克,但是坦克表不记录这一点?坦克表应该记录这一点,因为这是链接坦克中的东西和其他东西的过程的一部分在站点上。如果您确实想做出将此数据放入代码的可疑决定,请添加一个连接条件
和ProductName=CASE tt.TankNumber当1时,然后添加“纸浆”当2时,然后添加“超级”当3时,然后添加“无铅”结束