[英]Get SQL records matching multiple lines conditions
我有一个带有 SQLServer 2012 的表(为展示而简化):
父 ID | 瓦尔 |
---|---|
11111 | 1 |
11111 | 2 |
22222 | 1 |
22222 | 2 |
22222 | 3 |
33333 | 1 |
在这里小提琴: http://sqlfiddle.com/#!18/67a210/1
我正在使用带有参数@filterIds
的 SP,其中包含类似1, 2, 3
的字符串(注意分隔符是逗号和空格)。
我需要一个请求来获取具有相同ParentId
的所有行,该 ParentId 的Val
的所有值都是@filtersIds
。
如果@filtersId
为1, 2, 3
,则结果必须为 22222,因为它是唯一具有 Val = 1、Val = 2 和 Val = 3 的行。
如果@filtersId
为1, 2
,则结果必须为 11111 和 22222,因为它们都有 Val = 1 和 Val = 2 的行。
如果@filtersId
是1, 4
,则根本没有结果,因为没有 Val = 1 和 Val = 4 的 ParentId。
我尝试了一些 JOIN 但对于这样一个简单的请求似乎过于复杂。 有没有我没有想到的快速简便的解决方案?
您可以构建一个筛选表并查找所有不符合筛选条件的 parentID 值。
Note that you can bypass the first step (where I build the filter list cteFilter from values in the data) using the function STRING_SPLIT if your SQL is new enough, but I showed the version you'll need for older SQL.
另请注意,使用与字符串过滤器匹配的 integer 值会出现一个不寻常的问题 - 您可以使值与预期过滤器值的一部分匹配,即如果您的过滤器是“100、250”,您需要采取措施确保值25 不匹配。 在过滤器字符串和从值生成的字符串周围添加分隔符将允许您仅测试完全匹配。
感谢您在 Fiddle 中提供示例数据,它使您更容易回答您的问题。
DECLARE @Filter nvarchar(50) = '1, 2, 3';
--DECLARE @Filter nvarchar(50) = '1, 2';
create table #Sample(parentId int not null, Val int not null)
insert into #Sample(parentId, Val)
values (11111, 1), (11111, 2), (22222, 1), (22222, 2), (22222, 3), (33333, 1)
;with cteVals as ( --Don't apply functions more than necessary
SELECT DISTINCT Val FROM #Sample
), cteFilter as (--NOTE: For QL Server 2016 (13.x) and later, use string_split to generate this list!
SELECT Val --Otherwise, build a list by finding all Val values in your filter string
FROM cteVals --Next line is complicated to insure matching start and end values
--even if values are of different lengths, we don't want 25 to match filter '100, 250'!
WHERE CHARINDEX(CONCAT(', ', FORMAT(Val, '#'),', '), CONCAT(', ', @Filter, ', ')) > 0
)SELECT DISTINCT parentId --Find all of the ParentIDs
FROM #Sample as S
WHERE NOT EXISTS ( --That don't have any filter requirements ...
SELECT * FROM cteFilter as F
WHERE NOT EXISTS ( --such that the filter
SELECT * FROM #Sample as S2 --isn't in the sample data
WHERE S2.Val = F.Val --matching the filter value
AND S2.parentId = S.parentId --and also matching the parentID in question
)
)
DROP TABLE #Sample
编辑:感谢 Joe Celko,我使用了他的文章https://www.red-gate.com/simple-talk/databases/sql-server/t-sql-programming-sql-server/divided-we-stand-the -sql-of-relational-division/对我的解决方案进行故障排除,该解决方案最初不起作用
这是一个带有余数的关系除法的例子。 有许多解决方案。
通常比其他答案(双重嵌套的NOT EXISTS
)更有效的实现是加入输入列表,按ParentId
分组,并确保您有与输入列表中的行一样多的匹配项。
您应该将数据作为表值参数传递。 作为一种技巧,您可以使用STRING_SPLIT
转换为表变量,但如果可能的话,我建议您不要这样做。
让我们假设您有一个表格参数@input
:
CREATE TYPE dbo.IntList TABLE (Value int PRIMARY KEY /* must be unique */);
然后您可以执行以下操作:
DECLARE @count int = (SELECT COUNT(*) FROM @input);
SELECT
t.ParentID
FROM MyTable t
JOIN @input i ON i.Value = t.val
GROUP BY
t.ParentID
HAVING COUNT(*) = @count;
您可能还想看看其他关系除法技术。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.