一个简单但复杂的SQL查询

时间:2011-10-18 06:53:47

标签: sql sql-server

我有一个非常简单的MS SQL表,其中包含以下数据(列名和数据类型):

TableId     PersonName              Attribute           AttributeValue
(int)       (nvarchar 50)           (nvarchar 50)       (bit)
----------- ----------------------- ------------------- --------------
1           A                       IsHuman             1
2           A                       CanSpeak            1
3           A                       CanSee              1
4           A                       CanWalk             0
5           B                       IsHuman             1
6           B                       CanSpeak            1
7           B                       CanSee              0
8           B                       CanWalk             0
9           C                       IsHuman             0
10          C                       CanSpeak            1
11          C                       CanSee              1
12          C                       CanWalk             0

现在,我需要的是具有Attribute IsHuman和CanSpeak且AttributeValue = 1的唯一PersonName。

预期结果应该是(必须不包括C,因为这个具有IsHuman = 0)

PersonName
------------
A
B

请任何专家帮我写一个SQL查询。

6 个答案:

答案 0 :(得分:3)

SELECT PersonName 
  FROM MyTable 
 WHERE AttributeName = 'IsHuman' 
       AND AttributeValue = 1
INTERSECT
SELECT PersonName 
  FROM MyTable 
 WHERE AttributeName = 'CanSpeak' 
       AND AttributeValue = 1;

显然,如果标准可以变化,这种方法不会“扩展”。可能您需要的关系运算符是division,通常称为"the supplier who supplies all parts",特别是division with remainder

答案 1 :(得分:2)

SELECT PersonName 
FROM MyTable 
WHERE (AttributeName = 'IsHuman' AND AttributeValue = 1) OR 
      (AttributeName = 'CanSpeak' AND AttributeValue = 1) 
GROUP BY PersonName
HAVING COUNT(*) > 1

SELECT PersonName 
FROM MyTable 
WHERE AttributeValue = 1 AND AttributeName IN ('IsHuman', 'CanSpeak') 
GROUP BY PersonName
HAVING COUNT(*) > 1

答案 2 :(得分:1)

SELECT PersonName FROM MyTable 
WHERE PersonName IN 
(SELECT T1.PersonName FROM MyTable T1 WHERE T1.Attribute = 'IsHuman' and T1.AttributeValue='1')
AND (Attribute = 'CanSpeak' AND AttributeValue='1')

答案 3 :(得分:0)

select personname from yourtablename where personname in ('a','b') group by personname

答案 4 :(得分:0)

我认为根据索引和表格大小,两个内部联接可能会给你带来正常的性能。

SELECT t.PersonName FROM table t 
INNER JOIN table t2 ON t.PersonName=t2.PersonName AND t3.Attribute = 'IsHuman' AND t2.AttributeValue = 1 
INNER JOIN table t3 ON t2.PersonName=t3.PersonName AND t3.Attribute = 'CanSpeak' AND t3.AttributeValue = 1 

SELECT t.PersonName FROM table t 
INNER JOIN table t2 ON t.PersonName=t2.PersonName
INNER JOIN table t3 ON  t2.PersonName=t3.PersonName
WHERE t2.Attribute = 'IsHuman' AND t2.AttributeValue = 1 AND t3.Attribute = 'CanSpeak' AND t3.AttributeValue = 1 

这个解决方案可以大大简化,但是属性IsHuman和CanSpeak是在单独的表中,它们之间有一个链接ID表。听起来像这张表可能会受益于一些规范化。

如果您无法取得进展,则视图可能有助于提高效果。我没有安装SQL,所以我无法验证任何性能方面。

答案 5 :(得分:-1)

我实际上将此作为面试的筛选问题。你们谁都不会得到这份工作。

好吧,也许你愿意,但是虽然你使用的策略可能会或可能不会起作用,但它们并不是一般化的,它们会错过关系代数的基本概念,即机智,别名。

正确的答案(在某种意义上说,它会让我更有可能雇用你,以及RDMS的优化程序理解它的重要性较低,并且可以扩展到其他任意复杂的情况)

SELECT t1.PersonName 
  FROM MyTable t1, MyTable t2
 WHERE t2.AttributeName = 'CanSpeak' 
       AND t2.AttributeValue = 1
       AND t1.AttributeName = 'IsHuman' 
       AND t1.AttributeValue = 1
       AND t1.PersonName = t2.PersonName;