数据模型
从您的评论中,我看到您还有其他一些您在问题中没有提到的与属性相关的表格。我假设我们现在可以忽略这些,只专注于表示属性值,这可以通过下面的简化模型来完成:
![在此处输入图像描述](https://i.stack.imgur.com/GuIjV.png)
DDL SQL(MS SQL 服务器):
CREATE TABLE [USER] (
USER_ID int NOT NULL,
NICKNAME nvarchar(50) NOT NULL,
CONSTRAINT PK_USER PRIMARY KEY CLUSTERED (USER_ID)
);
CREATE TABLE USER_PROPERTY_VALUE(
USER_ID int NOT NULL,
PROPERTY_NAME nvarchar(50) NOT NULL,
PROPERTY_VALUE_NO int NOT NULL,
PROPERTY_VALUE nvarchar(255) NOT NULL,
CONSTRAINT PK_USER_PROPERTY_VALUE PRIMARY KEY CLUSTERED (
USER_ID,
PROPERTY_NAME,
PROPERTY_VALUE_NO
)
);
ALTER TABLE USER_PROPERTY_VALUE ADD CONSTRAINT FK_USER_PROPERTY_VALUE_USER FOREIGN KEY(USER_ID)
REFERENCES [USER] (USER_ID);
多值由 USER_PROPERTY_VALUE 中的几行表示,共享相同的 PROPERTY_NAME,但每行都有不同的 PROPERTY_VALUE_NO。
以下示例数据...
Rob: HairColor={brown}, Hobby={basketball,football}
Bob: HairColor={brown}, Hobby={basketball}
Steve: Hobby={basketball,football}
...在数据库中表示如下:
用户:
USER_ID NICKNAME
1 Rob
2 Bob
3 Steve
USER_PROPERTY_VALUE:
USER_ID PROPERTY_NAME PROPERTY_VALUE_NO PROPERTY_VALUE
1 HairColor 1 brown
1 Hobby 1 basketball
1 Hobby 2 football
2 HairColor 1 brown
2 Hobby 1 basketball
3 Hobby 1 basketball
3 Hobby 2 football
示例查询
选择棕色头发的用户:
SELECT *
FROM [USER]
WHERE
EXISTS (
SELECT *
FROM USER_PROPERTY_VALUE
WHERE
USER_PROPERTY_VALUE.USER_ID = [USER].USER_ID
AND PROPERTY_NAME = 'HairColor'
AND PROPERTY_VALUE = 'brown'
)
结果:
USER_ID NICKNAME
1 Rob
2 Bob
选择爱好篮球和足球的用户:
SELECT *
FROM [USER]
WHERE
EXISTS (
SELECT *
FROM USER_PROPERTY_VALUE
WHERE
USER_PROPERTY_VALUE.USER_ID = [USER].USER_ID
AND PROPERTY_NAME = 'Hobby'
AND PROPERTY_VALUE = 'basketball'
)
AND EXISTS (
SELECT *
FROM USER_PROPERTY_VALUE
WHERE
USER_PROPERTY_VALUE.USER_ID = [USER].USER_ID
AND PROPERTY_NAME = 'Hobby'
AND PROPERTY_VALUE = 'football'
)
结果:
USER_ID NICKNAME
1 Rob
3 Steve
选择头发颜色为棕色且爱好包括篮球和足球的用户。
SELECT *
FROM [USER]
WHERE
EXISTS (
SELECT *
FROM USER_PROPERTY_VALUE
WHERE
USER_PROPERTY_VALUE.USER_ID = [USER].USER_ID
AND PROPERTY_NAME = 'HairColor'
AND PROPERTY_VALUE = 'brown'
)
AND EXISTS (
SELECT *
FROM USER_PROPERTY_VALUE
WHERE
USER_PROPERTY_VALUE.USER_ID = [USER].USER_ID
AND PROPERTY_NAME = 'Hobby'
AND PROPERTY_VALUE = 'basketball'
)
AND EXISTS (
SELECT *
FROM USER_PROPERTY_VALUE
WHERE
USER_PROPERTY_VALUE.USER_ID = [USER].USER_ID
AND PROPERTY_NAME = 'Hobby'
AND PROPERTY_VALUE = 'football'
)
结果:
USER_ID NICKNAME
1 Rob
等等等等……
根据其他表的内容进行查询
假设您有一个包含过滤条件的表:
CREATE TABLE PROPERTY_FILTER (
PROPERTY_NAME nvarchar(50) NOT NULL,
PROPERTY_VALUE nvarchar(255) NOT NULL,
CONSTRAINT PK_PROPERTY_FILTER PRIMARY KEY (PROPERTY_NAME, PROPERTY_VALUE)
)
以下查询将仅返回满足当前包含在该表中的条件的用户:
SELECT *
FROM [USER] U
WHERE
NOT EXISTS (
SELECT F.PROPERTY_NAME, F.PROPERTY_VALUE
FROM PROPERTY_FILTER F
EXCEPT
SELECT P.PROPERTY_NAME, P.PROPERTY_VALUE
FROM USER_PROPERTY_VALUE P
WHERE P.USER_ID = U.USER_ID
)
简而言之:如果有一个过滤器属性不是用户的属性,则忽略该用户。
顺便说一句,这在并发多用户环境中不起作用 - 您需要在 PROPERTY_FILTER 表中引入一个附加字段来标识“会话”,或者使用临时表(如果您不需要持久性)。