что-то вроде этого может работать для вас:
определить таблицы:
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,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, AttributeType) VALUES (1,2)
INSERT INTO #Attributes (ApartmentID, AttributeType) VALUES (1,3)
INSERT INTO #Attributes (ApartmentID, AttributeType) VALUES (1,4)
INSERT INTO #Attributes (ApartmentID, AttributeType) VALUES (1,5)
INSERT INTO #Attributes (ApartmentID, AttributeType) VALUES (1,6)
INSERT INTO #Attributes (ApartmentID, AttributeType) VALUES (2,1)
INSERT INTO #Attributes (ApartmentID, AttributeType) VALUES (2,2)
INSERT INTO #Attributes (ApartmentID, AttributeType) VALUES (2,3)
INSERT INTO #Attributes (ApartmentID, AttributeType) VALUES (2,4)
INSERT INTO #Attributes (ApartmentID, AttributeType) VALUES (2,7)
INSERT INTO #Attributes (ApartmentID, AttributeType) VALUES (3,1)
INSERT INTO #Attributes (ApartmentID, AttributeType) VALUES (3,2)
INSERT INTO #Attributes (ApartmentID, AttributeType) VALUES (3,3)
INSERT INTO #Attributes (ApartmentID, AttributeType) VALUES (3,4)
INSERT INTO #Attributes (ApartmentID, AttributeType) VALUES (4,1)
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
ВЫВОД:
ApartmentID ApartmentName
----------- --------------
1 one
2 two
(2 row(s) affected)
В приведенном выше поисковом запросе я просто включил CSV-строку идентификаторов атрибутов для поиска. В действительности вы можете создать хранимую процедуру поиска, в которой вы передаете параметр CSV, содержащий идентификаторы для поиска. Вы можете посмотреть этот ответ , чтобы узнать о разбиении этих циклов CSV без таблицы на таблицы, к которым вы можете присоединиться. Это привело бы к тому, что не нужно использовать какой-либо динамический SQL.
РЕДАКТИРОВАТЬ на основе множества комментариев:
если вы добавите несколько столбцов в таблицу #AttributeTypes, вы можете динамически построить страницу поиска. Вот несколько предложений:
- Статус: "A" ctive "I" nactive
- ListOrder: можно использовать это для сортировки, чтобы построить экран
- ColumnNumber: может помочь организовать поля в одной строке экрана
- AttributeGroupID: чтобы сгруппировать поля, см. Ниже
- и т.д..
Вы можете установить флажки для всех полей или добавить другую таблицу с именем #AttributesGroups, сгруппировать их вместе и использовать переключатели. Например, поскольку «Домашние животные разрешены» и «Домашние животные не разрешены» являются исключительными, добавьте строку в таблицу #AttributesGroups «Домашние животные». Приложение будет группировать атрибуты в интерфейсе. Атрибуты в группах будут работать так же, как обычные разгруппированные атрибуты, просто соберите выбранные идентификаторы и передайте их в процедуру поиска. Однако для каждой группы необходимо, чтобы приложение включало переключатель «без предпочтений» и включало его по умолчанию. Эта опция не будет иметь идентификатора атрибута и не будет передана, так как вы не хотите рассматривать атрибут.
В моем примере я показываю пример "супер атрибута", который находится в #Apartments
стол "Статус". Вы должны учитывать только основные атрибуты этой таблицы. Если вы начнете использовать их, вы можете изменить CTE на FROM #Apartments с фильтрацией по этим полям, а затем присоединиться к #Attributes. Однако вы столкнетесь с проблемами Условия динамического поиска, поэтому прочитайте эту статью Эрланда Соммарскога .
РЕДАКТИРОВАТЬ в последних комментариях:
вот код для списка исключаемых атрибутов:
;WITH GetMatchingAttributes AS
(
SELECT
ApartmentID,COUNT(AttributeID) AS CountOfMatches
FROM #Attributes
WHERE AttributeType IN (1,2,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'
Я не думаю, что пошел бы по этому пути, хотя. Я бы пошел с подходом, который я изложил в моем предыдущем EDIT выше. Когда необходимо включить / исключить атрибут, я бы просто добавил атрибут для каждого: «Домашние животные разрешены» и «Домашние животные не разрешены».
Я обновил пример данных из исходного поста, чтобы показать это.
Запустите исходный запрос с помощью:
- (.., .., 6, ..), чтобы найти квартиры, в которых разрешено проживание с домашними животными
- (.., .., 7, ..) для поиска квартир, в которых домашние животные не допускаются
- (.., .., ..), если нет предпочтений.
Я думаю, что это лучший подход. В сочетании с идеей группировки и динамически создаваемой страницей поиска, описанной в последнем редакторе, я думаю, что это будет лучше и будет работать быстрее.