用于搜索具有无限数量的位字段的表的SQL设计方法
考虑搜索包含公寓租赁信息的表:使用该界面的客户端选择在数据库中表示为位字段的多个条件,例如:
> AllowPets 等等.. 我们面临的情况是,我们软件的每个新客户都有他们希望允许最终用户搜索的其他字段.位字段的数量可以达到数百个. 我有三种方法,我正在考虑并希望输入和/或不同的方法. >当前方法:添加更多位字段,动态构建SQL查询并使用EXEC执行:SET @SQL = @SQL’l.[NumUnits],’exec(@SQL)) 继续添加更多位字段. (300列的表?) >将数据表示为一个字段中的一系列位.我不清楚这种方法是否有效,考虑我上面提供的4个样本位字段.该字段可能如下所示:1011表示“hasparking”为false,但对所有其他字段为true.我不清楚你是如何构建一个你不关心它是否为真或假的查询,例如1?11,搜索者需要1,3和4才是真的但不关心’HasParking’是真还是假. 其他一些方法?这是一个众所周知的SQL设计模式吗? 谢谢你的帮助 KM-编辑评论 attribute table has a few other rows in it and is called listingattributes CREATE TABLE [dbo].[ListingAttributes]( [ListingID] [bigint] NOT NULL,[AttributeID] [int] IDENTITY(1,1) NOT NULL,[AttributeType] [smallint] NOT NULL,[BoardID] [int] NOT NULL,[ListingMLS] [varchar](30) NOT NULL,[PropertyTypeID] [char](3) NOT NULL,[StatusID] [varchar](2) NOT NULL,PRIMARY KEY CLUSTERED ( [AttributeID] ASC )WITH (PAD_INDEX = OFF,STATISTICS_NORECOMPUTE = OFF,IGNORE_DUP_KEY = OFF,ALLOW_ROW_LOCKS = ON,ALLOW_PAGE_LOCKS = ON,FILLFACTOR = 80) ON [PRIMARY] ) ON [PRIMARY] ;WITH GetMatchingAttributes AS ( SELECT ListingID,COUNT(AttributeID) AS CountOfMatches FROM ListingAttributes WHERE BoardID = 1 AND StatusID IN ('A') AND --PropertyTypeID in (select * from @PropertyType) --AND AttributeType IN (2,3,6) GROUP BY ListingID HAVING COUNT(AttributeID)=(3) ) SELECT count(l.listingid) FROM Listing l INNER JOIN GetMatchingAttributes m ON l.ListingID=m.ListingID -- where -- StatusID IN (select * from @Status) --AND --PropertyTypeID in (select * from @PropertyType) 1 1 0 NULL NULL 1 NULL 1 NULL NULL NULL 0.1934759 NULL NULL SELECT 0 NULL |--Compute Scalar(DEFINE:([Expr1006]=CONVERT_IMPLICIT(int,[Expr1012],0))) 1 2 1 Compute Scalar Compute Scalar DEFINE:([Expr1006]=CONVERT_IMPLICIT(int,0)) [Expr1006]=CONVERT_IMPLICIT(int,0) 1 0 0.001483165 11 0.1934759 [Expr1006] NULL PLAN_ROW 0 1 |--Stream Aggregate(DEFINE:([Expr1012]=Count(*))) 1 3 2 Stream Aggregate Aggregate NULL [Expr1012]=Count(*) 1 0 0.001483165 11 0.1934759 [Expr1012] NULL PLAN_ROW 0 1 |--Filter(WHERE:([Expr1005]=(3))) 1 4 3 Filter Filter WHERE:([Expr1005]=(3)) NULL 2471.109 0 0.00440886 9 0.1919928 NULL NULL PLAN_ROW 0 1 |--Compute Scalar(DEFINE:([Expr1005]=CONVERT_IMPLICIT(int,[Expr1011],0))) 1 5 4 Compute Scalar Compute Scalar DEFINE:([Expr1005]=CONVERT_IMPLICIT(int,0)) [Expr1005]=CONVERT_IMPLICIT(int,0) 9185.126 0 0.01422281 11 0.1875839 [Expr1005] NULL PLAN_ROW 0 1 |--Stream Aggregate(GROUP BY:(.[dbo].[ListingAttributes].[ListingID]) DEFINE:([Expr1011]=Count(*))) 1 6 5 Stream Aggregate Aggregate GROUP BY:(.[dbo].[ListingAttributes].[ListingID]) [Expr1011]=Count(*) 9185.126 0 0.01422281 11 0.1875839 [Expr1011] NULL PLAN_ROW 0 1 |--Index Seek(OBJECT:(.[dbo].[ListingAttributes].[_dta_index_ListingAttributes_BoardID_ListingID__AttributeType_PropertyTypeID_StatusID_6_7]),SEEK:(.[dbo].[ListingAttributes].[BoardID]=(1)),WHERE:(.[dbo].[ListingAttributes].[StatusID]='A' AND (.[dbo].[ListingAttributes].[AttributeType]=(2) OR .[dbo].[ListingAttributes].[AttributeType]=(3) OR .[dbo].[ListingAttributes].[AttributeType]=(6))) ORDERED FORWARD) 1 7 6 Index Seek Index Seek OBJECT:(.[dbo].[ListingAttributes].[_dta_index_ListingAttributes_BoardID_ListingID__AttributeType_PropertyTypeID_StatusID_6_7]),WHERE:(.[dbo].[ListingAttributes].[StatusID]='A' AND (.[dbo].[ListingAttributes].[AttributeType]=(2) OR .[dbo].[ListingAttributes].[AttributeType]=(3) OR .[dbo].[ListingAttributes].[AttributeType]=(6))) ORDERED FORWARD .[dbo].[ListingAttributes].[ListingID],.[dbo].[ListingAttributes].[AttributeID],.[dbo].[ListingAttributes].[AttributeType],.[dbo].[ListingAttributes].[StatusID] 16050.41 0.09677318 0.0315279 26 0.1283011 .[dbo].[ListingAttributes].[ListingID],.[dbo].[ListingAttributes].[StatusID] NULL PLAN_ROW 0 1 (7 row(s) affected) 解决方法这样的事情可能适合你:定义表: CREATE TABLE #Apartments ( ApartmentID int not null primary key identity(1,1),ApartmentName varchar(500) not null,Status char(1) not null default ('A') --.... ) CREATE TABLE #AttributeTypes ( AttributeType smallint not null primary key,AttributeDescription varchar(500) not null ) CREATE TABLE #Attributes --boolean attributes,if row exists apartment has this attribute ( ApartmentID int not null --FK to Apartments.ApartmentID,AttributeID int not null primary key identity(1,AttributeType smallint not null --fk to AttributeTypes ) 插入样本数据: SET NO COUNT ON INSERT INTO #Apartments VALUES ('one','A') INSERT INTO #Apartments VALUES ('two','A') INSERT INTO #Apartments VALUES ('three','I') INSERT INTO #Apartments VALUES ('four','I') INSERT INTO #AttributeTypes VALUES (1,'dishwasher') INSERT INTO #AttributeTypes VALUES (2,'deck') INSERT INTO #AttributeTypes VALUES (3,'pool') INSERT INTO #AttributeTypes VALUES (4,'pets allowed') INSERT INTO #AttributeTypes VALUES (5,'washer/dryer') INSERT INTO #AttributeTypes VALUES (6,'Pets Alowed') INSERT INTO #AttributeTypes VALUES (7,'No Pets') INSERT INTO #Attributes (ApartmentID,AttributeType) VALUES (1,1) INSERT INTO #Attributes (ApartmentID,2) INSERT INTO #Attributes (ApartmentID,3) INSERT INTO #Attributes (ApartmentID,4) INSERT INTO #Attributes (ApartmentID,5) INSERT INTO #Attributes (ApartmentID,6) INSERT INTO #Attributes (ApartmentID,AttributeType) VALUES (2,7) INSERT INTO #Attributes (ApartmentID,AttributeType) VALUES (3,4) INSERT INTO #Attributes (ApartmentID,AttributeType) VALUES (4,2) SET NOCOUNT OFF 样本搜索查询: ;WITH GetMatchingAttributes AS ( SELECT ApartmentID,COUNT(AttributeID) AS CountOfMatches FROM #Attributes WHERE AttributeType IN (1,2,3) --<<change dynamically or split a CSV string and join in GROUP BY ApartmentID HAVING COUNT(AttributeID)=3--<<change dynamically or split a CSV string and use COUNT(*) from resulting table ) SELECT a.* FROM #Apartments a INNER JOIN GetMatchingAttributes m ON a.ApartmentID=m.ApartmentID WHERE a.Status='A' ORDER BY m.CountOfMatches DESC OUTPUT: ApartmentID ApartmentName ----------- -------------- 1 one 2 two (2 row(s) affected) 在上面的搜索查询中,我只是包含了要搜索的属性ID的CSV字符串.实际上,您可以创建一个搜索存储过程,在其中传入包含要搜索的ID的CSV参数.您可以查看this answer以了解可以将CSV字符串无循环拆分到可以加入的表中.这将导致不需要使用任何动态SQL. 编辑基于许多评论: 如果向#AttributeTypes表添加几列,则可以动态构建搜索页面.以下是一些建议: >状态:“A”ctive“I”nactive 您可以创建所有字段复选框,或添加另一个名为#AttributesGroups的表,并将其组合在一起并使用单选按钮.例如,由于“Pets Allowed”和“No Pets”是独占的,因此在#AttributesGroups表“Pets”中添加一行.应用程序将在界面中对属性进行分组.组中的属性与常规的未组合属性相同,只需收集选定的ID并将其传递给搜索过程.但是,对于每个组,您需要让应用程序包含“无首选项”单选按钮并将其默认打开.此选项没有属性ID,因为您不想考虑该属性,所以不会传入该选项. 在我的示例中,我确实展示了#Apartments中的“超级属性”的示例 编辑最新评论: 这里是代码,有一个排除属性列表: ;WITH GetMatchingAttributes AS ( SELECT ApartmentID,3) --<<change dynamically or split an include CSV string and join in GROUP BY ApartmentID HAVING COUNT(AttributeID)=3--<<change dynamically or split a CSV string and use COUNT(*) from resulting include table ),SomeRemoved AS ( SELECT m.ApartmentID FROM GetMatchingAttributes m LEFT OUTER JOIN #Attributes a ON m.ApartmentID=a.ApartmentID AND a.AttributeType IN (5,6) --<<change dynamically or split an exclude CSV string and join in WHERE a.ApartmentID IS NULL ) SELECT a.* FROM #Apartments a INNER JOIN SomeRemoved m ON a.ApartmentID=m.ApartmentID WHERE a.Status='A' 我不认为我会这样做.我会按照我之前编辑的方法进行操作.当需要包含/排除属性时,我只为每个属性添加一个属性:“允许携带宠物”和“禁止携带宠物”. 我更新了原始帖子中的示例数据以显示此信息. 运行原始查询: >(..,..,6,..)找到允许携带宠物的公寓 我认为这是更好的方法.当与上一次编辑中描述的分组构思和动态构建的搜索页面结合使用时,我认为这会更好并且运行得更快. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- Sqlserver SQL语句 表字段 增删改.以及约束的删除与添加
- sql – 选择两列之间的日期
- -------------------------------SQLServer2000同步复制技术
- sql-server – 如何使用外部SQL数据库中的数据填充SharePoi
- [SqlServer]如何向数据库插入带有单引号(')的字符串
- sqlserver 存储过程备份
- MySQL命令行导出导入数据库实例详解
- sql-server – 在SQL Server中处理对密钥表的并发访问而不会
- SQLserver中字符串查找功能patindex和charindex的区别
- sql-server – 我应该在SQL Server Express 2008上使用什么