Sql server 基于存储搜索参数的SQL Server动态搜索

Sql server 基于存储搜索参数的SQL Server动态搜索,sql-server,tsql,sql-server-2012,Sql Server,Tsql,Sql Server 2012,我必须创建一个动态搜索。搜索条件存储在表中,存储的记录有一个主表。结构如下: --Main Table. This table stores records of a user. Basically we store files in this table. Each file is associated with a single city. DECLARE @Records TABLE( [RecordId] INT IDENTITY(1,1), [FileName] VARCHAR(100

我必须创建一个动态搜索。搜索条件存储在表中,存储的记录有一个主表。结构如下:

--Main Table. This table stores records of a user. Basically we store files in this table. Each file is associated with a single city.
DECLARE @Records TABLE(
[RecordId] INT IDENTITY(1,1),
[FileName] VARCHAR(100),
[OwnerId] INT,
[CityId] INT
)
INSERT INTO @Records
SELECT 'A', 100, 101 UNION
SELECT 'B', 100, 102 UNION
SELECT 'C', 100, 103 UNION
SELECT 'D', 100, 104

--The next table is used to associate a file with multiple friends.
DECLARE @FriendRecords TABLE
(
[Id] INT IDENTITY(1,1),
[RecordId] INT,
[FriendId] INT
)
INSERT INTO @FriendRecords
SELECT 1, 201 UNION --File '1' is associated with 'FriendId' 201
SELECT 1, 202 UNION --File '1' is associated with 'FriendId' 202
SELECT 2, 201 UNION --File '2' is associated with 'FriendId' 201
SELECT 3, 202       --File '3' is associated with 'FriendId' 202

--The following table is used to create a criteria for user.
DECLARE @Criteria TABLE
(
[CriteriaId] INT IDENTITY(1,1),
[CriteriaName] VARCHAR(50),
[OwnerId] INT
)
INSERT INTO @Criteria
SELECT 'SampleCriteria', 100 --Criteria created by user 100

--The following table is used to store cities that needs to be searched in 'Records' table for owner of criteriaId '1'.
DECLARE @CriteriaCities TABLE(
[CriteriaCityId] INT IDENTITY(1,1),
[CriteriaId] INT, 
[CityId] INT
)
INSERT INTO @CriteriaCities
SELECT 1, 101 UNION
SELECT 1, 102 UNION
SELECT 1, 103 

--The following table is used to store friend that needs to be searched in 'FriendsRecords' table for owner of criteriaId '1'.
DECLARE @CriteriaFriend TABLE(
[CriteriaCityId] INT IDENTITY(1,1),
[CriteriaId] INT, 
[FriendId] INT
)
INSERT INTO @CriteriaFriend
SELECT 1, 202;

基本上,用户可以创建一个条件(@criteriatable)并存储搜索参数(@CriteriaCities和@CriteriaFriend tables)。要求是根据存储的条件获取文件。我正在查找的查询应该返回@records表中的记录,该表的cityID为101、102和103FriendId“201”。结果仅为@Records表中的“C”。如果我在所有表上创建一个左连接,我也会得到ownerId“100”的其他记录。如果我在表中包含一个内部联接,那么如果@CriteriaCities或@CriteriaFriend表中没有条件条目,我就不会得到任何记录。根据链接表(@CriteriaCities,@CriteriaFriend)中存在的记录在主表中搜索记录的查询应该是什么?如果搜索参数未存储在这些表中,则不应在这些表之间创建联接。

我不确定您是否完全理解了您的逻辑,因为根据我的评论,您的问题没有什么意义,但如果我遵循您所述的规则,您可以使用以下
select
语句获取数据。我不确定您将如何通过您正在搜索的标准,因为您尚未解释您的流程的这一部分是如何工作的:

-- Count the records in each criteria table.
declare @CriteriaCitiesCount int = (select count(1) from @CriteriaCities);
declare @CriteriaFriendCount int = (select count(1) from @CriteriaFriend);


select *
from @Records r
    left join @CriteriaCities cc
        on(r.CityId = cc.CityId)
    left join @FriendRecords f
        on(r.RecordId = f.RecordId)
    left join @CriteriaFriend cf
        on(f.FriendId = cf.FriendId)
where (@CriteriaCitiesCount = 0        -- Only return records where we aren't filtering,
        or cc.CityId is not null       -- Or we are filtering and we get a match.
        )
    and (@CriteriaFriendCount = 0
        or cf.FriendId is not null
        );

我不确定您是否完全理解了您的逻辑,因为根据我的评论,您的问题不太合理,但如果我按照您所述的规则行事,您可以使用以下
select
语句获取数据。我不确定您将如何通过您正在搜索的标准,因为您尚未解释您的流程的这一部分是如何工作的:

-- Count the records in each criteria table.
declare @CriteriaCitiesCount int = (select count(1) from @CriteriaCities);
declare @CriteriaFriendCount int = (select count(1) from @CriteriaFriend);


select *
from @Records r
    left join @CriteriaCities cc
        on(r.CityId = cc.CityId)
    left join @FriendRecords f
        on(r.RecordId = f.RecordId)
    left join @CriteriaFriend cf
        on(f.FriendId = cf.FriendId)
where (@CriteriaCitiesCount = 0        -- Only return records where we aren't filtering,
        or cc.CityId is not null       -- Or we are filtering and we get a match.
        )
    and (@CriteriaFriendCount = 0
        or cf.FriendId is not null
        );

对不起,我无法理解您的输出。 为什么您应该只获取文件名C

试一试

;With CTE as
(
select cc.CityId,cf.FriendId    
from @Criteria C
inner join @CriteriaCities CC
on c.CriteriaId=cc.CriteriaId
inner join @CriteriaFriend CF  
on c.CriteriaId=cf.CriteriaId
where c.OwnerId=@ownerid
)

select *
from @Records R
inner join @FriendRecords FR
on r.RecordId=fr.RecordId
where EXISTS(
select cityid from cte c where r.CityId=c.cityid and c.FriendId=fr.FriendId
)

对不起,我无法理解您的输出。 为什么您应该只获取文件名C

试一试

;With CTE as
(
select cc.CityId,cf.FriendId    
from @Criteria C
inner join @CriteriaCities CC
on c.CriteriaId=cc.CriteriaId
inner join @CriteriaFriend CF  
on c.CriteriaId=cf.CriteriaId
where c.OwnerId=@ownerid
)

select *
from @Records R
inner join @FriendRecords FR
on r.RecordId=fr.RecordId
where EXISTS(
select cityid from cte c where r.CityId=c.cityid and c.FriendId=fr.FriendId
)

为什么这是一个如此复杂的过程?这种设计的原因是什么?另外,在您的示例中,如果您正在搜索
101
CityID
102
103
201
FriendID
,那么这不匹配文件
a
B
,而不是
C
?即使按照脚本使用
202
FriendID
。您将与
A
C
匹配。您是如何将文件
C
作为输出的?为什么这是一个如此复杂的过程?这种设计的原因是什么?另外,在您的示例中,如果您正在搜索
101
CityID
102
103
201
FriendID
,那么这不匹配文件
a
B
,而不是
C
?即使按照脚本使用
202
FriendID
。您将与
A
C
匹配。您是如何将文件
C
作为输出的?是的。你说得对。FriendId“202”将给出A和C。我的错误。我只是创建了临时表并混合了实际值。无论如何,根据您的回答,如果“@CriteriaFriend”表中没有[OwnerId]100的记录,结果将为空。而我的要求是“如果“@CriteriaFriend”表中没有记录,请不要创建联接。“@CriteriaCities”表也是如此。虽然我不得不做一些调整,但效果不错。谢谢!是的。你是对的。FriendId”202“会给A和C.我的错误。我只是创建了临时表并混合了实际值。无论如何,根据您的回答,如果“@CriteriaFriend”表中没有[OwnerId]100的记录,结果将为空。而我的要求是“如果“@CriteriaFriend”表中没有记录,请不要创建联接。“@CriteriaCities”表也是如此。这很有效,不过我不得不做一些调整。谢谢!