SQL查询以获取另一个表中具有多个行的行数

时间:2011-08-11 16:46:01

标签: sql sql-server group-by

在我的应用程序中,我有一组可以在列出资源时应用的过滤器,这些过滤器在执行查询之前通过添加WHERE子句等来构建查询。这是使用SQL Server 2008。

我有两个相关的表,一个包含有关资源的静态数据,另一个包含与该资源相关的任意/可选字段。

第一个表是这样的(表名和字段已更改):

CREATE TABLE Resources (
    ResID       varbinary(28),

    ... extra stuff omitted

    type        integer );

第二个表只有名称/值对和相应的资源ID

CREATE TABLE ResourceFields (
    ResID       varbinary(28) NOT NULL,

    Name        nvarchar(255) NOT NULL,
    Value       nvarchar(1024) NOT NULL);

因此,对于此示例,“ResourceFields”中可能有多行,其中name ='ContactName'表示相同的ResID。

我想要做的是获取'Resources'表中有多个'ContactName'的行数,这些'ContactName'在'ResourceFields'中列出,'type'等于某个值。

我想出了这个(不要笑 - 我知道足够的SQL导致问题)

SELECT count(r.ResID) 
    FROM Resources as r 
        INNER JOIN ResourceFields AS rf 
            ON rf.ResID = r.ResID 
                AND rf.name = 'ContactName' 
    WHERE r.type = 1 
    GROUP BY rf.ResID 
    HAVING COUNT(rf.Value) > 1;

但是不是在'Resources'中返回行数(我的测试集中的43)的计数,而是返回所有返回的COUNT(rf.Value)值(即43个单独的计数)。

我做错了什么?

4 个答案:

答案 0 :(得分:8)

只需将原始查询用作派生表(将其放在子选择中):

SELECT COUNT(*)
FROM (
    SELECT count(*) AS C
    FROM Resources as r 
        INNER JOIN ResourceFields AS rf 
            ON rf.ResID = r.ResID 
                AND rf.name = 'ContactName' 
    WHERE r.type = 1 
    GROUP BY rf.ResID 
    HAVING COUNT(rf.Value) > 1;
) s

答案 1 :(得分:1)

我对SQL Server并不熟悉,但请尝试:

SELECT count( r.ResID ) FROM Resources as r where 1 < (select count(rf.value) from ResourceFields AS rf where rf.ResID = r.ResID AND rf.name = 'ContactName') and r.type = 1;

答案 2 :(得分:1)

您需要预先聚合“ContactName”属性的计数。这可能是CTE最容易实现的:

WITH Multiple_Contacts (ResID) as (SELECT a.ResID
                                   FROM Resources as a
                                   JOIN ResourceFields as B
                                   ON b.ResID = A.ResID
                                   AND b.name = 'ContactName'
                                   WHERE a.type = 1
                                   GROUP BY a.ResID
                                   HAVING COUNT(a.ResId) > 1)
SELECT COUNT(ResId)
FROM Multiple_Contacts

需要考虑的其他事项 -
可能使name中的ResourceFields实际上是另一个表的外键(因此将所有属性更改为不同的文本名称是微不足道的)。这也允许您在value中将有关预期数据格式的信息放在引用的表中,希望限制无效数据(使用正则表达式掩码等) - 您必须非常小心多域表,如这(通常不应该使用它们,但可能有一些用例) 另外,您真的希望存储28个字节值不同的资源吗?这是一个相当大的数字......(请记住,Int通常是4个字节,并存储大约40亿个不同的值)。

答案 3 :(得分:0)

希望这会有所帮助:

SELECT COUNT(*)
FROM Resources as r
WHERE EXISTS (
    SELECT 1
    FROM ResourceFields rf
    WHERE rf.ResId = r.ResId
    AND rf.name = 'ContactName'
    HAVING COUNT(*) > 1
)
AND r.type = 1

更新:从子查询中删除分组,子查询将不相关的行添加到计数中。