【问题标题】:SQL query to get count of rows with more than one row in another tableSQL查询以获取另一个表中多于一行的行数
【发布时间】:2011-08-11 16:46:01
【问题描述】:

在我的应用程序中,我有一组过滤器可以在列出资源时应用,这些过滤器通过在执行查询之前添加 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”中可能有多个行,名称 =“ContactName”,用于同一个 ResID。

我想要做的是计算“资源”表中的行数,这些行在“资源字段”中列出了多个“联系人姓名”,“类型”等于某个值。强>

我想出了这个(别笑——我知道的 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;

但我没有返回“资源”中的行数(我的测试集中为 43),而是返回所有 COUNT(rf.Value) 值(即 43 个单独的计数)。

我做错了什么?

【问题讨论】:

    标签: sql sql-server group-by


    【解决方案1】:

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

    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
    

    【讨论】:

    • 他可能实际上想要一个内部countSUM(),否则我喜欢这个。
    • 是的,他肯定会。然而,到目前为止,他表示他希望获得值43,但却得到了 43 行值。
    • 不,我只是想要计数。我会试试这个。
    • 只是出于好奇,后面的 's' 是干什么用的?
    • 它是子选择的(在这种情况下不需要)名称(如在 AS 中) - 例如,如果您想将其与其他内容连接,您可以使用 s 访问子选择列(在这种情况只是 C)...
    【解决方案2】:

    我对 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;
    

    【讨论】:

      【解决方案3】:

      您需要预先汇总“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
      

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

      【讨论】:

        【解决方案4】:

        希望这会有所帮助:

        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
        

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

        【讨论】:

        • 这实际上返回了 79,所以我认为它在子查询中包含了一些行。
        • 是的,我过于依赖现有的查询。现在它应该可以按预期工作了。
        猜你喜欢
        • 1970-01-01
        • 2020-06-17
        • 1970-01-01
        • 2012-04-24
        • 1970-01-01
        • 2014-02-14
        • 1970-01-01
        • 1970-01-01
        • 2017-08-21
        相关资源
        最近更新 更多