对属性表中多个属性的匹配查询

昨天有同事问我一个SQL语句,估计在不少地方会用到,所以在这里分享一下。

有一个对象,每个对象有0到N个属性,根据数据库设计的3NF,我们会设计一个这样的表

CREATE TABLE [dbo].[Objects](

 [ObjectID] [int] NOT NULL PRIMARY KEY,

 [ObjectNane] [varchar](100) NOT NULL

 )

 

CREATE TABLE [dbo].[ObjectAttributes](

 [ObjectID] [int] NOT NULL,

 [AttrName] [varchar](100) NOT NULL,

 [AttrValue] [varchar](500) NULL

)

ALTER TABLE ObjectAttributes ADD CONSTRAINT PK_ObjectAttributes PRIMARY KEY CLUSTERED

 (

 ObjectId,

 AttrName

 )

那么,我们希望找出Attr1 (AttrName) = "1" (AttrValue) 并且Attr2 (AttrName) = "2" (AttrValue)的记录。
比如,ObjectAttributes的内容为
1 Attr1 1
1 Attr2 2
2 Attr2 2
3 Attr1 1
4 Attr3 1

那么我们希望的结果是[dbo].[Objects]表中ObjectID为1的记录。
你会怎样写这个SQL语句呢?

我的同事想了一个办法,对ObjectAttributes 表查两次,然后Union All,Group By之后求Count。
完整的SQL语句如下:

SELECT o.*

FROM  Objects AS o INNER JOIN

      (SELECT     ObjectId

        FROM  (SELECT     ObjectId

                FROM          ObjectAttributes

                WHERE      (AttrName = 'Attr1') AND (AttrValue = '1')

                UNION ALL

                SELECT     ObjectId

                FROM         ObjectAttributes

                WHERE     (AttrName = 'Attr2') AND (AttrValue = '2')) AS M1

        GROUP BY ObjectId

        HAVING      (COUNT(*) = 2)) AS M2

ON o.ObjectID = M2.ObjectId

OK, 虽然看起来怪麻烦的,but it works.能管用就好,效率其实也不算差。就是如果判断条件再复杂一点,而且有交集并集的时候就不好办了。

其实,有一个更自然的写法可以解决这个问题。

SELECT *

FROM Objects AS o

WHERE EXISTS

        (SELECT * FROM ObjectAttributes

        WHERE ObjectId = o.ObjectID AND AttrName = 'Attr1' AND AttrValue = '1')

    AND EXISTS

        (SELECT * FROM ObjectAttributes

        WHERE ObjectId = o.ObjectID AND AttrName = 'Attr2' AND AttrValue = '2')

这样看起来是不是更易读呢?而且增加条件也很简单。

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值