我正在使用SQL Server创建一个网站。在管理界面中,我有两个字段:
可以为记录分配多个字段值。
现在在前端搜索中,我希望访问者能够选择一个以上的字段值进行搜索。例如,某人可能会搜索主题为数学或历史,并且成绩为1或3。
我应该使用哪种表设计和SQL语句(或MS专有语句)来进行有效搜索?
谢谢和问候。
更新
感谢所有输入!
我觉得有必要解释一下。我技术熟悉并熟悉SQL。我在多年的编程经验中学到的一件事是实用。对于这个问题,我已经有了初步设计,但不确定其他人如何处理高效搜索(总有更聪明的人)。这是我用于存储记录的表格设计:
Subject
type: varchar. record example: ,1,3, (each is the id of corresponding value)
Grade (this means applicable grade)
type: varchar. record example: ,1,2, (each is the id of corresponding values. this means a record is applicable to grade 1, 2)
搜索示例
where (subject LIKE '%,1,%' OR subject like '%,3,%') AND (grade like '%,1,%')
这种设计应该导致有效的搜索,但缺点是它增加了后端的复杂性数据管理。
我的设计的另一个原因是:主题和成绩每个都有一个从不/很少改变的值列表,一旦创建了一个记录,它就永远或很少更新。
我试图在简单性,可理解性,设计,管理等方面取得平衡。
答案 0 :(得分:1)
create table Subject (
SubjectId int identity(1, 1),
SubjectName nvarchar(255),
other fields.... )
create table GradingScale (
GradeId int identity(1, 1),
Grade int,
Description varchar(25),
other fields... )
create table Students (
StudentId int identity(1, 1),
StudentName nvarchar(255))
create table StudentGrades (
StudentId int,
SubjectId int,
GradeId int,
SemesterId int )
create FUNCTION [dbo].[fnArray] ( @Str varchar(max), @Delim varchar(1) = ' ', @RemoveDups bit = 0 )
returns @tmpTable table ( arrValue varchar(max))
as
begin
declare @pos integer
declare @lastpos integer
declare @arrdata varchar(8000)
declare @data varchar(max)
set @arrdata = replace(@Str,@Delim,'|')
set @arrdata = @arrdata + '|'
set @lastpos = 1
set @pos = 0
set @pos = charindex('|', @arrdata)
while @pos <= len(@arrdata) and @pos <> 0
begin
set @data = substring(@arrdata, @lastpos, (@pos - @lastpos))
if rtrim(ltrim(@data)) > ''
begin
if @RemoveDups = 0
begin
insert into @tmpTable ( arrValue ) values ( @data )
end
else
begin
if not exists( select top 1 arrValue from @tmpTable where arrValue = @data )
begin
insert into @tmpTable ( arrValue ) values ( @data )
end
end
end
set @lastpos = @pos + 1
set @pos = charindex('|', @arrdata, @lastpos)
end
return
end
select *
from Students st
inner join StudentGrades sg on sg.StudentId = st.StudentId
inner join Subject s on sg.SubjectId = s.SubjectId
inner join GradingScale gs on sg.GradeId = gs.GradeId
inner join dbo.fnArray(@subjects, ',') sArr on s.SubjectId = convert(int, sArr.arrValue)
inner join dbo.fnArray(@grades, ',') gArr on gs.GradeId = convert(int, gArr.arrValue)
显然@subjectId和@gradeId可以通过一些下拉选择器传入,或者你的UI是由组成的。
编辑使用dbo.fnArray,这是一个可以将分隔的字符串解析为列表的小工具。
现在当然这意味着如果你有2个科目和2个成绩......比如给我看所有学生(数学和科学)和得分(2或3),这将有效。但是,如果您想要学习数学并且得分为2或3的学生或者学习科学并且得分为3的学生则必须重新编写查询。