我有两个表,一个表是人,另一个表用于存储有关该人的各种动态属性/信息。
Id | Persons PersonId | Field | Value
----+------------- ----------+--------+-----------
1 | Peter 1 | City | New York
2 | Jane 1 | Age | 26
2 | City | New York
2 | Age | 50
age > 25 and city = 'New York'
没有grouping
或pivoting
表的人。答案 0 :(得分:2)
SELECT key1.PersonId
FROM KeyValue key1
INNER JOIN KeyValue key2 ON key1.PersonId = key2.PersonId
WHERE key1.[Field] = 'Age' and key1.[Value] > 25
AND key2.[Field] = 'City' and key2.[Value] = 'New York'
<强>更新强>
我做了一些测试,INNER JOIN看起来足够快。这里是结果和测试脚本
SET NOCOUNT ON
SET STATISTICS IO ON
CREATE TABLE KeyValue (
ID INT NOT NULL IDENTITY CONSTRAINT [PK_KeyValue] PRIMARY KEY CLUSTERED
,PersonId INT NOT NULL
,Field varchar(30) NOT NULL
,Value varchar(255) NOT NULL
,CONSTRAINT UQ__KeyValue__PersonId_Field UNIQUE (PersonId, Field)
)
GO
--INSERT INTO KeyValue 500K "users", 4 "Fields" - 2M rows
CREATE NONCLUSTERED INDEX [IX__KeyValue__Field_Value_ID]
ON [dbo].[KeyValue] ([Field],[Value]) INCLUDE ([PersonId])
GO
select PersonId from (
select PersonId, ROW_NUMBER() OVER (PARTITION BY PersonId ORDER BY PersonId) RowNumber from (
select PersonId from KeyValue where [Field] = 'Age' and [Value] > 25 union all
select PersonId from KeyValue where [Field] = 'City' and [Value] = 'Sydney' union all
select PersonId from KeyValue where [Field] = 'Email' and [Value] = 'xxxxx@gmail.com' union all
select PersonId from KeyValue where [Field] = 'Name' and [Value] = 'UserName'
) x
) y where RowNumber = 4
--Table 'KeyValue'. Scan count 20, logical reads 1510, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
--Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
select PersonId from (
select PersonId from KeyValue where [Field] = 'Age' and [Value] > 25 union all
select PersonId from KeyValue where [Field] = 'City' and [Value] = 'Sydney' union all
select PersonId from KeyValue where [Field] = 'Email' and [Value] = 'xxxxx@gmail.com' union all
select PersonId from KeyValue where [Field] = 'Name' and [Value] = 'UserName'
) x GROUP by PersonId
HAVING COUNT(*) = 4
--Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
--Table 'KeyValue'. Scan count 4, logical reads 1377, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SELECT key1.PersonId
FROM KeyValue key1
INNER JOIN KeyValue key2 ON key1.PersonId = key2.PersonId
INNER JOIN KeyValue key3 ON key1.PersonId = key3.PersonId
INNER JOIN KeyValue key4 ON key1.PersonId = key4.PersonId
WHERE key1.[Field] = 'Age' and key1.[Value] > 25
AND key2.[Field] = 'City' and key2.[Value] = 'Sydney'
AND key3.[Field] = 'Email' and key3.[Value] = 'xxxxx@gmail.com'
AND key4.[Field] = 'Name' and key4.[Value] = 'UserName'
-- Table 'KeyValue'. Scan count 1, logical reads 21, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SET STATISTICS IO OFF
GO
答案 1 :(得分:1)
您可以使用以下结构:
select PersonId from
(
select PersonId from xxx where [Field] = 'Age' and [Value] > 25
union all
select PersonId from xxx where [Field] = 'City' and [Value] = 'New York'
) x
group by PersonId
having count(*) = 2
您可以为每个参数创建另一个联合查询。因此,这种方式会使每个PersonId
返回符合条件的次数。然后,您可以选择符合所有条件的PersonId
,即count(*)
等于参数数量。
您可以轻松地将其扩展到更多参数。
如果您在Field
和Value
上拥有正确的索引,这应该会很好。
这是一个没有group by
的版本(虽然效果相同):
select PersonId from
(
select PersonId, ROW_NUMBER() OVER (PARTITION BY PersonId ORDER BY PersonId) RowNumber from
(
select PersonId from xxx where [Field] = 'Age' and [Value] > 25
union all
select PersonId from xxx where [Field] = 'City' and [Value] = 'Sydney'
) x
) y
where RowNumber = 2
答案 2 :(得分:0)
如果我理解你的问题,那么这样的事情会起作用:
SELECT
one.*
FROM table1 AS one
INNER JOIN table2 AS two1 ON one.Id = two1.PersonId
INNER JOIN table2 AS two2 ON one.Id = two2.PersonId
WHERE (two1.field = 'age' AND two1.value > 25)
AND (two2.field = 'city' AND two2.value = 'New York')
祝你好运!